I am using ThreeJS to "open" and view 3D files.
At this moment I can only observe a 3D figure in 3D format.
How can I replace this geometrical figure (cube) with a 3D file (obj or fbx)?
In the project I placed two 3D files (one fbx and the other obj) with the name image.
Do I need to use any specific loader to read this type of files?
Can someone help me?
Thanks !
DEMO
html
<canvas #canvas></canvas>
.ts
#ViewChild('canvas') canvasRef: ElementRef;
renderer = new THREE.WebGLRenderer;
scene = null;
camera = null;
controls = null;
mesh = null;
light = null;
private calculateAspectRatio(): number {
const height = this.canvas.clientHeight;
if (height === 0) {
return 0;
}
return this.canvas.clientWidth / this.canvas.clientHeight;
}
private get canvas(): HTMLCanvasElement {
return this.canvasRef.nativeElement;
}
constructor() {
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(35, 800/640, 0.1, 1000)
}
ngAfterViewInit() {
this.configScene();
this.configCamera();
this.configRenderer();
this.configControls();
this.createLight();
this.createMesh();
this.animate();
}
configScene() {
this.scene.background = new THREE.Color( 0xdddddd );
}
configCamera() {
this.camera.aspect = this.calculateAspectRatio();
this.camera.updateProjectionMatrix();
this.camera.position.set( -15, 10, 15 );
this.camera.lookAt( this.scene.position );
}
configRenderer() {
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true,
alpha: true
});
this.renderer.setPixelRatio(devicePixelRatio);
this.renderer.setClearColor( 0x000000, 0 );
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
}
configControls() {
this.controls = new OrbitControls(this.camera, this.canvas);
this.controls.autoRotate = false;
this.controls.enableZoom = true;
this.controls.enablePan = true;
this.controls.update();
}
createLight() {
this.light = new THREE.PointLight( 0xffffff );
this.light.position.set( -10, 10, 10 );
this.scene.add( this.light );
}
createMesh() {
const geometry = new THREE.BoxGeometry(5, 5, 5);
const material = new THREE.MeshLambertMaterial({ color: 0xff0000 });
this.mesh = new THREE.Mesh(geometry, material);
this.scene.add(this.mesh);
}
animate() {
window.requestAnimationFrame(() => this.animate());
// this.mesh.rotation.x += 0.01;
// this.mesh.rotation.y += 0.01;
this.controls.update();
this.renderer.render(this.scene, this.camera);
}
Do I need to use any specific loader to read this type of files?
Yes. You have to use THREE.OBJLoader and THREE.FBXLoader if you want to load OBJ or FBX files. For loading OBJ files, the workflow looks like so:
Import the loader:
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
Load the asset and add it to your scene:
const loader = new OBJLoader();
loader.load('https://threejs.org/examples/models/obj/tree.obj', object => {
this.scene.add(object);
});
BTW: There is no need to use the npm package #avatsaev/three-orbitcontrols-ts. You can import OrbitControls from the three package.
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
Related
Hello I'm trying to import an fbx model into my scene, but there is not much info on it online I had found one way that looks to use official three.js package but for some reason the model dose not appear in my scene, even through I don't get any errors. If any one can help me please because I have no clue at why it is not loading.
The guide that I used: https://sbcode.net/threejs/loaders-fbx/
The short version of the code.
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
const fbxLoader = new FBXLoader()
fbxLoader.load('models/3dModdleOfTheBox.fbx', (object) => {
scene.add(object)
})
Full code
import React, { useEffect } from 'react'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
export default function Threed_model() {
//three js
useEffect(() => {
//basic setup
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
camera.position.z = 5
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#canvas'),
})
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
//controls
const controls = new OrbitControls(camera, renderer.domElement)
controls.enableZoom = false
controls.enablePan = false
controls.target.set(0, 0, 0)
//fbx loader
const material = new THREE.MeshNormalMaterial()
const fbxLoader = new FBXLoader()
fbxLoader.load('models/3dModdleOfTheBox.fbx', (object) => {
scene.add(object)
})
//light
const light = new THREE.PointLight()
light.position.set(0.8, 1.4, 1.0)
scene.add(light)
const ambientLight = new THREE.AmbientLight()
scene.add(ambientLight)
//adding stuff
const geometry = new THREE.TorusGeometry(1, 0.5, 16, 100)
const torus = new THREE.Mesh(geometry, material)
scene.add(torus)
function animate() {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}
animate()
renderer.render(scene, camera)
}, [])
return <canvas id="canvas">test</canvas>
}
Turns out you have to set a scale for your model for it to display
object.scale.set(0.01, 0.01, 0.01)
My final code looked like this for who ever might need it.
fbxLoader.load('models/3dModdleOfTheBox.fbx', (object) => {
object.traverse(function (child) {
if (child.isMesh) {
console.log(child.geometry.attributes.uv)
const texture = new THREE.TextureLoader().load(
'models/pakage(12).png'
)
child.material.map = texture
child.material.needsUpdate = true
}
})
object.scale.set(0.01, 0.01, 0.01)
scene.add(object)
console.log(object)
})
Please i need help on three.js animation. trying to animate the ball randomly on the plane before stoping at specific or selected location on the plane. my code below please any help will be appreciates.
1: https://i.stack.imgur.com/3kXhW.png
Please i need help on three.js animation. trying to animate the ball randomly on the plane before stoping at specific or selected location on the plane. my code below please any help will be appreciates.
.
. .
import { OrbitControls } from "./libs/three128/OrbitControls.js";
import { GUI } from "./dat.gui.module.js";
class Game {
constructor() {
const container = document.createElement("div");
document.body.appendChild(container);
this.step = 0;
this.speed = 0.01;
this.camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
this.camera.position.set(-10, 150, 150);
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xaaaaaa);
const ambient = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 0.3);
this.scene.add(ambient);
const light = new THREE.DirectionalLight();
light.position.set(0.2, 1, 1);
this.scene.add(light);
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(this.renderer.domElement);
//Replace Box with Circle, Cone, Cylinder, Dodecahedron, Icosahedron, Octahedron, Plane, Sphere, Tetrahedron, Torus or TorusKnot
const planeGeometry = new THREE.BoxBufferGeometry(200, 200, 3);
const planeMaterial = new THREE.MeshStandardMaterial({
color: 0xff0000,
side: THREE.DoubleSide,
});
this.plane = new THREE.Mesh(planeGeometry, planeMaterial);
this.scene.add(this.plane);
const ballGeometry = new THREE.SphereGeometry(8, 100, 100);
const ballMaterial = new THREE.MeshStandardMaterial({
color: 0x0000ff,
wireframe: false,
});
this.ball = new THREE.Mesh(ballGeometry, ballMaterial);
this.scene.add(this.ball);
const controls = new OrbitControls(this.camera, this.renderer.domElement);
this.gridHelper = new THREE.GridHelper(200);
this.scene.add(this.gridHelper);
this.input();
this.renderer.setAnimationLoop(this.render.bind(this));
window.addEventListener("resize", this.resize.bind(this));
}
input() {
const gui = new GUI();
let ball = this.ball;
let plane = this.plane;
ball.position.set(0, 9.5, 0);
const options = {
ballColor: ball.material.color.getHex(),
planeColor: plane.material.color.getHex(),
positionX: ball.position.x,
positionZ: ball.position.z,
wireframe: false,
};
gui
.add(options, "positionX", -100, 100)
.name("X-coodinate")
.onChange(function (value) {
ball.position.x = value;
console.log(value);
});
gui
.add(options, "positionZ", -100, 100)
.name("Y-coodinate")
.onChange(function (value) {
ball.position.z = value;
console.log(value);
});
gui
.addColor(options, "ballColor")
.name("Ball-Color")
.onChange(function (value) {
ball.material.color.set(value);
});
gui
.addColor(options, "planeColor")
.name("Plane-Color")
.onChange(function (value) {
plane.material.color.set(value);
});
// gui.add(ball.material, "wireframe").name("Wireframe");
}
resize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
render() {
this.plane.rotation.x = -0.5 * Math.PI;
this.renderer.render(this.scene, this.camera);
}
}
export { Game };
project picture.
I tried to follow the source code at https://threejs.org/examples/misc_controls_pointerlock.html without the divs, but it didn't work. I then tried following the code here https://sbcode.net/threejs/pointerlock-controls/ but it also did not work.
I simply want to be able to look around with the pointerlock controls, for first person view. I will be able to sort out the movement of the controls afterwards.
Currently I have a model (mainChar), where the camera is attached to him. I would like the pointerlock controls to be attached to his position somehow.
This is my code that doesn't work:
//IMPORT STATEMENTS
import { EntityManager } from './EntityManager.js';
import { LightingManager } from './LightingManager.js';
import { Time } from '../Time.js';
import { PauseMenu } from '../SceneSubjects/Menu/PauseMenu.js';
import { keyboardManager } from './KeyboardManager.js';
//lights
import { GeneralLights } from '../SceneSubjects/lighting/GeneralLights.js';
import { CeilingLight } from '../SceneSubjects/lighting/CeilingLight.js';
import { CeilingLightObj } from '../SceneSubjects/objects/CeilingLightObj.js';
//objects
import { House } from '../SceneSubjects/House.js';
import { SceneSubject } from '../SceneSubjects/objects/SceneSubject.js';
import { TestBlock } from '../SceneSubjects/characters/TestBlock.js';
import { Door } from '../SceneSubjects/objects/Door.js';
import { MainChar } from '../SceneSubjects/characters/MainChar.js';
//other
import { PointerLockControls } from '../../jsm/PointerLockControls.js';
import { OrbitControls } from '../../jsm/OrbitControls.js';
import * as THREE from '../../../jsm/three.module.js';
//==================================================================================================
//Global Variables
//lights
var generalLights = new GeneralLights();
//ceiling lights
var bedroomLightObj = new CeilingLightObj();
var kitchenLightObj = new CeilingLightObj();
var studyLightObj = new CeilingLightObj();
var hallwayLightObj1 = new CeilingLightObj();
var hallwayLightObj2 = new CeilingLightObj();
var bathroomLightObj = new CeilingLightObj();
var loungeLightObj = new CeilingLightObj();
var bedroomLight = new CeilingLight();
var kitchenLight = new CeilingLight();
var studyLight = new CeilingLight();
var hallwayLight1 = new CeilingLight();
var bathroomLight = new CeilingLight();
var hallwayLight2 = new CeilingLight();
var loungeLight = new CeilingLight();
//objects
var house = new House();
var sceneSubject = new SceneSubject();
var testBlock = new TestBlock();
var testdoor = new Door();
export var mainChar = new MainChar(testBlock);
export class SceneManager {
constructor(canvas) {
//this entire function renders a scene where you can add as many items as you want to it (e.g. we can create the house and add as
//many items as we want to the house). It renders objects from other javascript files
//------------------------------------------------------------------------------------------------------------------------------------------
//These are supposed to act like constants. DO NOT CHANGE
this.GAME_PAUSE = "pause";
this.GAME_RUN = "run";
this.GAME_START = "start";
//------------------------------------------------------------------------------------------------------------------------------------------
//we use (this) to make variables accessible in other classes
this.time = new Time();
this.objPauseMenu;
this.game_state = this.GAME_RUN;
this.width_screen = canvas.width;
this.height_screen = canvas.height;
this.screenDimensions = {
width: canvas.width,
height: canvas.height
};
//the essentials for rendering a scene
this.scene = this.buildScene();
this.renderer = this.buildRender(this.screenDimensions);
this.camera = this.buildCamera(this.screenDimensions);
//comment this out
// this.controls = new OrbitControls(this.camera, this.renderer.domElement);
//initialise pointerlock controls
this.pointerLockControls = new PointerLockControls(this.camera, this.renderer.domElement);
this.pointerLockControls.unlock();
//this.scene.add(this.pointerLockControls.getObject());
//====================
//adjust the ceiling light properties in the house
this.setCeilingLightProperties();
this.managers = this.createManagers();
//load things to scene
this.loadToScene(this.managers[0].lights);
this.loadToScene(this.managers[1].entities);
//---------------------------------------------------------------------------------------------------------------------------------
// Ok, now we have the cube. Next we'll create the hud. For that we'll
// need a separate scene which we'll render on top of our 3D scene. We'll
// use a dynamic texture to render the HUD.
// We will use 2D canvas element to render our HUD.
//---------------------------------------------------------------------------------------------------------------------------------
}
loadToScene(entities) {
for (let i = 0; i < entities.length; i++) {
this.scene.add(entities[i].object);
}
}
//this function creates our scene
buildScene() {
//create a new scene
const scene = new THREE.Scene();
//set the scene's background-> in this case it is our skybox
const loader = new THREE.CubeTextureLoader();
//it uses different textures per face of cube
const texture = loader.load([
'../skybox/House/posx.jpg',
'../skybox/House/negx.jpg',
'../skybox/House/posy.jpg',
'../skybox/House/negy.jpg',
'../skybox/House/posz.jpg',
'../skybox/House/negz.jpg'
]);
scene.background = texture;
//if we wanted it to be a colour, it would have been this commented code:
//scene.background = new THREE.Color("#000");
return scene;
}
//this creates a renderer for us
buildRender({ width, height }) {
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true, alpha: true
});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
return renderer;
}
//create a camera for the screen
buildCamera({ width, height }) {
//SETTING FIELD OF VIEW, ASPECT RATIO (which should generally be width/ height), NEAR AND FAR (anything outside near/ far is clipped)
const aspectRatio = width / height;
const fieldOfView = 60;
const nearPlane = 1;
const farPlane = 1000;
//there are 2 types of cameras: orthographic and perspective- we will use perspective (more realistic)
const camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, nearPlane, farPlane);
//Set camera initial position to main character
let pos = mainChar.returnWorldPosition();
camera.position.set(pos.x, pos.y + 10, pos.z - 10);
return camera;
}
setCeilingLightProperties() {
//set their light positions
bedroomLightObj.setLightPosition(0, 21, 50);
bedroomLight.setLightPosition(0, 16, 50);
loungeLightObj.setLightPosition(-45, 21, -60);
loungeLight.setLightPosition(-45, 16, -60);
studyLightObj.setLightPosition(35, 21, -50);
studyLight.setLightPosition(35, 16, -50);
kitchenLight.setLightPosition(-45, 16, 5);
kitchenLightObj.setLightPosition(-45, 21, 5);
bathroomLight.setLightPosition(45, 16, 15);
bathroomLightObj.setLightPosition(45, 21, 15);
hallwayLightObj1.setLightPosition(0, 21, -60);
hallwayLight1.setLightPosition(0, 16, -60);
hallwayLightObj2.setLightPosition(0, 21, 0);
hallwayLight2.setLightPosition(0, 16, 0);
}
//add subjects to the scene
createManagers() {
const managers = [new LightingManager(), new EntityManager()];
//can be altered so we can add multiple entities, and depending on which position
//it is, certain ones won't be paused, and some will be
//Note that these variables are declared globally before the class definition
/*This is so that we can use any of these object's methods or values later somewhere else*/
//lights
// managers[0].register(generalLights);
managers[0].register(bedroomLight);
managers[0].register(loungeLight);
managers[0].register(studyLight);
managers[0].register(hallwayLight1);
managers[0].register(hallwayLight2);
managers[0].register(kitchenLight);
managers[0].register(bathroomLight);
//entities
managers[1].register(loungeLightObj);
managers[1].register(studyLightObj);
managers[1].register(kitchenLightObj);
managers[1].register(bathroomLightObj);
managers[1].register(bedroomLightObj);
managers[1].register(hallwayLightObj1);
managers[1].register(hallwayLightObj2);
managers[1].register(house);
testdoor.setPosition(0, -0.5, 33);
//testdoor.setRotation(-Math.PI/2);
managers[1].register(testdoor);
managers[1].register(mainChar);
managers[1].register(sceneSubject);
managers[1].register(testBlock);
return managers;
}
updateCameraPosition() {
//Match camera position and direction to the character's position and direction
let pos = mainChar.returnWorldPosition();
let dir = mainChar.returnObjectDirection();
//Set y to 10 to move camera closer to head-height
//UNCOMMENT FOR 3RD PERSON
// this.camera.position.set(pos.x, 10 +10, pos.z + 20);
// this.camera.rotation.set(dir.x - 0.5, dir.y, dir.z);
//UNCOMMENT FOR FIRST PERSON
this.camera.position.set(pos.x, 15, pos.z - 5);
this.camera.rotation.set(dir.x, dir.y, dir.z);
}
//this updates the subject/model every frame
update() {
//won't call this loop if it's paused-> only for objects that need to be paused (managers that need to be paused)
if (this.game_state == this.GAME_RUN) {
//TO EXPERIMENT WITH FOR LOOKING AROUND!
// this.camera.position.x += ( keyboardManager.getMouseX() - this.camera.position.x ) ;
// this.camera.position.y += ( - keyboardManager.getMouseY() - this.camera.position.y );
// this.camera.lookAt( this.scene.position );
const runTime = this.time.getRunTime();
this.managers[0].update(runTime);
this.managers[1].update(runTime);
//update orbit controls
//comment out this.controls.update()
//this.controls.update();
this.renderer.render(this.scene, this.camera);
}
else {
//comment out
// this.controls.update();
this.renderer.autoClear = true;
//render scene1
this.renderer.render(this.scene, this.camera);
//prevent canvas from being erased with next .render call
this.renderer.autoClear = false;
//just render scene2 on top of scene1
this.renderer.render(this.objPauseMenu.scene, this.objPauseMenu.camera);
// renderer.autoClear = true;
}
//update orbit controls
//comment out
// this.controls.update();
//uncomment this
this.updateCameraPosition();
}
//this resizes our game when screen size changed
onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
pause() { //when pause mode is entered. The pause menu needs to be rendered.
this.game_state = this.GAME_PAUSE;
this.time.pause();
//comment out
// this.controls.enabled = false; // stop orbit controls from responding to use input
this.objPauseMenu = new PauseMenu(this.width_screen, this.height_screen);
}
unpause() {
this.game_state = this.GAME_RUN;
this.time.unpause();
//comment out
// this.controls.enabled = true; // start orbit controls tp respond to input
}
}
pointerLockControls.unlock() deactivates the controls
this should work
this.pointerLockControls.lock()
I have uploaded a glb file with an animation, and the animation is moving extremely fast, and I do not know why.
This is my character's animation code:
class MainChar extends THREE.Object3D {
constructor() {
super();
this.object = new THREE.Object3D();
this.object.position.set(0, 1, 50);
this.object.scale.x=20;
this.object.scale.y=20;
this.object.scale.z=20;
//load house model form blender file
/*
loader.setPath('../../models/characters/');
const gltf = loader.load('Douglas.glb', (gltf) => {
gltf.scene.traverse(c => {
c.castShadow = true;
});
this.object.add( gltf.scene);
});
*/
const loader = new THREE.GLTFLoader();
loader.setPath('../../models/characters/');
const gltf = loader.load('walk.glb', (gltf) => {
gltf.scene.traverse(c => {
c.castShadow = true;
});
this.mixer = new THREE.AnimationMixer( gltf.scene );
this.mixer.timeScale=1/5;
var action = this.mixer.clipAction( gltf.animations[ 0 ] );
action.play();
this.object.add( gltf.scene );
});
//save keyboard bindings
this.keyboard = new THREEx.KeyboardState();
/*
//creating a box (need to change it to a character with animations)
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
this.object = new THREE.Mesh( geometry, material );
this.object.scale.x=5;
this.object.scale.y=10;
this.object.scale.z=5;
//starting position for character
this.object.position.set(0, 10, 50);
*/
this.update = function (time) {
if ( this.mixer ){
this.mixer.update( time );
console.log(time);
}
//MOVEMENT OF BOX
//speed
var moveDistance = 0.5 ;
// var rotateAngle = Math.PI / 2 * 0.05;
// move forwards/backwards/left/right
if ( this.keyboard.pressed("W") ){
this.object.translateZ( -moveDistance );
}
if ( this.keyboard.pressed("S") ){
this.object.translateZ( moveDistance );
}
if ( this.keyboard.pressed("A") ){
this.object.translateX( -moveDistance );
}
if ( this.keyboard.pressed("D") ){
this.object.translateX( moveDistance );
}
// move forwards/backwards/left/right
if ( this.keyboard.pressed("up") ){
this.object.translateZ( -moveDistance );
}
if ( this.keyboard.pressed("down") ){
this.object.translateZ( moveDistance );
}
if ( this.keyboard.pressed("left") ){
this.object.translateX( -moveDistance );
}
if ( this.keyboard.pressed("right") ){
this.object.translateX( moveDistance );
}
// FOR CAMERA ROTATIONS
//this.object.rotateOnAxis( new THREE.Vector3(0,1,0), -rotateAngle);
//this.object.rotateOnAxis( new THREE.Vector3(0,1,0), rotateAngle);
//var rotation_matrix = new THREE.Matrix4().identity();
if ( this.keyboard.pressed("Z") )
{
this.object.position.set(0, 1, 50);
this.object.rotation.set(0,0,0);
}
/*
// global coordinates
if ( this.keyboard.pressed("left") )
this.object.position.x -= moveDistance;
if ( this.keyboard.pressed("right") )
this.object.position.x += moveDistance;
if ( this.keyboard.pressed("up") )
this.object.position.z -= moveDistance;
if ( this.keyboard.pressed("down") )
this.object.position.z += moveDistance;
*/
};
}
}
This is the time class that allows the game to be paused, as well as returns the delta time:
class Time {
constructor(){
this.is_pause = false;
this.accumalated_run_time = 0;
this.clock = new THREE.Clock();
this.pause_clock = new THREE.Clock();
}
getRunTime()
{
this.accumalated_run_time += this.clock.getDelta();
return this.accumalated_run_time
}
pause()
{
this.is_pause = true;
}
unpause()
{
this.is_pause = false;
this.clock.getDelta();
}
}
This is the sceneManager that calls up my character for updating animations:
class SceneManager {
constructor(canvas) {
//this entire function renders a scene where you can add as many items as you want to it (e.g. we can create the house and add as
//many items as we want to the house). It renders objects from other javascript files
//------------------------------------------------------------------------------------------------------------------------------------------
//These are supposed to act like constants. DO NOT CHANGE
this.GAME_PAUSE = "pause";
this.GAME_RUN = "run";
//------------------------------------------------------------------------------------------------------------------------------------------
//we use (this) to make variables accessible in other classes
this.time = new Time();
this.game_state = this.GAME_RUN;
this.screenDimensions = {
width: canvas.width,
height: canvas.height
};
//the essentials for rendering a scene
this.scene = this.buildScene();
this.renderer = this.buildRender(this.screenDimensions);
this.camera = this.buildCamera(this.screenDimensions);
this.managers = this.createManagers();
this.loadToScene(this.managers[0].entities);
//allow camera to orbit target (player)
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.target.set(0, 20, 0);
this.controls.update();
}
loadToScene(entities)
{
for (let i = 0 ; i < entities.length ; i++)
{
console.log("before" +i.toString());
this.scene.add(entities[i].object);
console.log("after");
}
}
//this function creates our scene
buildScene() {
//create a new scene
const scene = new THREE.Scene();
//set the scene's background-> in this case it is our skybox
const loader = new THREE.CubeTextureLoader();
//it uses different textures per face of cube
const texture = loader.load([
'../skybox/House/posx.jpg',
'../skybox/House/negx.jpg',
'../skybox/House/posy.jpg',
'../skybox/House/negy.jpg',
'../skybox/House/posz.jpg',
'../skybox/House/negz.jpg'
]);
scene.background = texture;
//if we wanted it to be a colour, it would have been this commented code:
//scene.background = new THREE.Color("#000");
return scene;
}
//this creates a renderer for us
buildRender({ width, height }) {
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true, alpha: true
});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
return renderer;
}
//create a camera for the screen
buildCamera({ width, height }) {
//SETTING FIELD OF VIEW, ASPECT RATIO (which should generally be width/ height), NEAR AND FAR (anything outside near/ far is clipped)
const aspectRatio = width / height;
const fieldOfView = 60;
const nearPlane = 1;
const farPlane = 1000;
//there are 2 types of cameras: orthographic and perspective- we will use perspective (more realistic)
const camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, nearPlane, farPlane);
//set where the camera is
camera.position.set(-50, 50, 70);
return camera;
}
//add subjects to the scene
createManagers() {
const managers=[new EntityManager()];
//can be altered so we can add multiple entities, and depending on which position
//it is, certain ones won't be paused, and some will be
managers[0].register(new GeneralLights());
managers[0].register(new House());
managers[0].register(new MainChar());
managers[0].register(new SceneSubject())
return managers;
}
//this updates the subject/model every frame
update() {
//won't call this loop if it's paused-> only for objects that need to be paused (managers that need to be paused)
if (this.game_state == this.GAME_RUN)
{
const runTime = this.time.getRunTime();
this.managers[0].update(runTime);
}
//update orbit controls
this.controls.update();
this.renderer.render(this.scene, this.camera);
}
//this resizes our game when screen size changed
onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
}
pause(){ //when pause mode is entered. The pause menu needs to be rendered.
this.game_state = this.GAME_PAUSE;
this.time.pause();
}
unpause(){
this.game_state = this.GAME_RUN;
this.time.unpause();
}
}
I think the issue is with your AnimationMixer.update() call. If you look at the docs, update is expecting a time-delta in seconds, but it looks like you're passing the total running time. This means it should receive the time passed since the last frame. You can fix this by using clock.getDelta(); as the argument:
this.update = function (time) {
if ( this.mixer ){
const delta = this.clock.getDelta();
this.mixer.update(delta);
}
// ...
}
I am a beginner of Threejs.
I created a Box Mesh and a Sphere Mesh and applied physics using physiJs.
What I want to do is to hit the ball when the Box Mesh rotates and passing through the ball.
However, when the box mesh rotates, it passes without hitting the ball.
I think the box mesh loses physicality when it starts spinning.
function createBall () {
var ball = null;
var ballGeo = new THREE.SphereGeometry(1.5, 30, 30);
var ballMat = Physijs.createMaterial(
new THREE.MeshBasicMaterial({specular: 0x111111})
, 0.3, 0.1
);
ball = new Physijs.SphereMesh(
ballGeo,
ballMat,
5
);
ball.position.set(30, 10, 0);
scene.add(ball);
}
function createBox () {
var material = Physijs.createMaterial(
new THREE.MeshLambertMaterial(
{
color: 0x8041D9,
}), 5, 0.3);
var boxMesh = new THREE.BoxGeometry(5, 5, 25);
box = new Physijs.BoxMesh(
boxMesh,
material,
5
);
box.position.z = 20;
scene.add(box);
}
function createHeightMap() {
var initColor = new THREE.Color( 0x00ff00 );
initColor.setHSL( 0.25, 0.85, 0.5 );
var ground_material = Physijs.createMaterial(
new THREE.MeshPhongMaterial(
{ color: 0x47C83E}
),
.5,
.5
);
var ground_geometry = new THREE.PlaneGeometry(800, 800, 100, 100);
ground = new Physijs.HeightfieldMesh(
ground_geometry,
ground_material,
0, // 질량
100, // PlaneGeometry 의 분할 세그먼트랑 똑같은 값으로 줘야 한다.
100 // PlaneGeometry 의 분할 세그먼트랑 똑같은 값으로 줘야 한다.
);
ground.position.y = -10;
ground.rotation.x = Math.PI / -2;
ground.receiveShadow = true;
var meshes = [];
var controls = new function () {
this.startRotate = false;
this.addBall = function () {
createBall();
};
this.addBox = function () {
createBox();
};
this.clearMeshes = function () {
meshes.forEach(function (e) {
scene.remove(e);
});
meshes = [];
}
};
var gui = new dat.GUI();
gui.add(controls, 'addBall');
gui.add(controls, 'addBox');
gui.add(controls, 'clearMeshes');
gui.add(controls, 'startRotate').onChange(function (e) {
isStartRoate = e;
});
return ground;
}
render = function () {
stats.update();
if (isStartRoate === true) {
var rotateMatrix = new THREE.Matrix4();
rotateMatrix.identity();
rotateMatrix.makeRotationY(0.05);
box.applyMatrix(rotateMatrix);
}
requestAnimationFrame(render);
renderer.render(scene, camera);
var axes = new THREE.AxesHelper(30);
scene.add(axes);
scene.simulate(undefined, 2);
};
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
window.onload = initScene;
below is codepen link
codepen
It seems like physicality not updated.
please give me any idea
When using Physijs, you should use setLinearVelocity() or setAngularVelocity() in order to update the position and rotation of your objects in a physical correct way. The updated codepen shows this approach:
https://codepen.io/anon/pen/YJmajN
Besides, the way you create AxesHelper in the render loop is no good approach. Create the helper once during the setup up of your scene.