How to set camera position dynamically using three.js - three.js

I am working on a three.js parser which can parse obj and JSON file.
The problem is different objects different alignments. I need to hard code value of camera.position.z. but this not dynamic.
How can I calculate this value dynamically? I already tried solutions from #WestLangley but it's not working. Maybe I am doing it wrong.
here is my code :
camera = new THREE.PerspectiveCamera( 45, width/ height, 1, 10000 );
camera.position.z = 200;
// scene
scene = new THREE.Scene();
scene.add( camera );
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( object_path.dir );
mtlLoader.load( object_path.mtl, function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( object_path.dir);
objLoader.load( object_path.object, function ( object ) {
// object.position.y = - 95;
camera.lookAt(object.position);
scene.add( object );
}, onProgress, onError );
});
renderer = new THREE.WebGLRenderer({preserveDrawingBuffer: true });
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( width, height);
container.appendChild( renderer.domElement );
controls = new THREE.OrbitControls( camera, renderer.domElement );

You need to call a render()-Function.
And in this function you can calculate the camera.z dynamically depending on your current state. Like:
var render = function () {
requestAnimationFrame( render );
camera.position.z = ...
renderer.render(scene, camera);
};
render();

Related

Not able to see the roughness on the non-metallic parts of the model, it looks correct in don mccurdy gltf viewer. What am I missing?

I have a model with some parts of it being metallic and others non-metallic. I have applied the environment map to get the correct reflections from the metallic parts of the model but the non metallic parts look equally reflective.
What should I do to make the non-metallic parts to appear less reflective and more rough as they are created. The model looks perfect in the Don Muccurdy’s gltf-viewer.
Please tell me what parameters do I need to change to get it right?
First is my rendered model and Second is the gltf viewer rendered model.
var rgbeLoader=new THREE.RGBELoader().setType( THREE.UnsignedByteType )
.setPath( 'textures/equirectangular/' )
.load( 'pedestrian_overpass_2k.hdr', function ( texture ) {
cubeGenerator = new THREE.EquirectangularToCubeGenerator( texture, { resolution: 1024 } );
cubeGenerator.update( renderer );
pmremGenerator = new THREE.PMREMGenerator( cubeGenerator.renderTarget.texture );
pmremGenerator.update( renderer );
pmremCubeUVPacker = new THREE.PMREMCubeUVPacker( pmremGenerator.cubeLods );
pmremCubeUVPacker.update( renderer );
envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture;
var loader = new THREE.GLTFLoader();
loader.load( 'tfsProject4.glb', function ( gltf ) {
scene.add(gltf.scene);
gltf.scene.traverse((e)=>{
e.material.envMap=envMap;
});
});
The following code is called from a function after loading all the assets including the model shown.
const scene = new THREE.Scene();
modalCamera = new THREE.PerspectiveCamera( 75, modalCanHolder.width() /
modalCanHolder.height(), 0.001, 100 );
var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 );
scene.add( light );
var light = new THREE.AmbientLight( 0x808080 );
scene.add( light );
var directionalLight = new THREE.DirectionalLight( 0xffffff, .3 );
directionalLight.position.set(0,10,10)
scene.add( directionalLight );
modalRenderer = new THREE.WebGLRenderer({antialias: true, alpha:true});
modalRenderer.gammaOutput = true;
modalRenderer.gammaFactor = 2.2;
modalRenderer.physicallyCorrectLights=true;
modalRenderer.outputEncoding = THREE.sRGBEncoding;
modalRenderer.physicallyCorrectLights = true;
modalRenderer.setSize( modalCanHolder.width(), modalCanHolder.height() );
modalRenderer.setPixelRatio( window.devicePixelRatio );
modalCanHolder.append( modalRenderer.domElement );
modalRenderer.domElement.id = 'modalCanvas';
cubeGenerator.update( modalRenderer );
pmremGenerator.update( modalRenderer );
pmremCubeUVPacker.update( modalRenderer );
var controls = new THREE.OrbitControls( modalCamera, modalRenderer.domElement );
var prod=products[id];
scene.add(prod);
controls.update();
const animate = function () {
subAnimation=requestAnimationFrame( animate );
controls.update();
modalRenderer.render( scene, modalCamera );
};
animate();
Please help me get the rendering right.

Centering pivot point in three.js with OrbitControls autorotate

I'm loading a .glb model into three.js, and while I have it rotating automatically using OrbitControls, I'm not able to see how to change the pivot point so the rotating model is centered.
I've seen a lot of questions on setting boxes or pivot points with rotation, but not with OrbitControls and autorotate. Is there a way for me to center the imported model using autorotate as per my code below?
var scene = new THREE.Scene();
// Load Camera Perspective
var camera = new THREE.PerspectiveCamera( 25, window.innerWidth / window.innerHeight, 1, 8000 );
camera.position.set( 200, 100, 0 );
// Load a Renderer
var renderer = new THREE.WebGLRenderer({ alpha: false });
renderer.setClearColor( 0xC5C5C3 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Load the Orbitcontroller
var controls = new THREE.OrbitControls( camera, renderer.domElement );
camera.position.set( 60, 20, 100 );
controls.update();
controls.autoRotate = true;
controls.minDistance = 700;
controls.maxDistance = 2000;
//controls.update();
// Load Light
var ambientLight = new THREE.AmbientLight( 0xcccccc );
scene.add( ambientLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.set( 0, 1, 1 ).normalize();
scene.add( directionalLight );
// glTf 2.0 Loader
var loader = new THREE.GLTFLoader();
loader.load( 'BTR.glb', function ( gltf ) {
var object = gltf.scene;
gltf.scene.scale.set( 1, 1, 1 );
gltf.scene.position.x = 0; //Position (x = right+ left-)
gltf.scene.position.y = 0; //Position (y = up+, down-)
gltf.scene.position.z = 0; //Position (z = front +, back-)
scene.add( gltf.scene );
});
function animate() {
// required if controls.enableDamping or controls.autoRotate are set to true
controls.update();
render();
requestAnimationFrame( animate );
}
function render() {
renderer.render( scene, camera );
}
render();
animate();
I think this issue can be solved by setting Controls.target (the focus point) to the center point of your glTF asset. You should be able to do this like so:
var aabb = new THREE.Box3().setFromObject( gltf.scene );
aabb.getCenter( controls.target );
controls.update();
three.js R107
Correct way to set target.
var aabb = new THREE.Box3().setFromObject( gltf.scene );
controls.target.set(aabb.getCenter());
controls.update();
it should take (aab.getCenter()), as it returns a vector3 with 3 axis values. But I found this didn't work for me, so I used the following
let aabb = new THREE.Box3().setFromObject( gltf.scene );
let aabbc = aabb.getCenter()
controls.target.set(aabbc.x, aabbc.y, aabbc.z);
controls.update();
just separating into 3 values, if you ever get stuck just console.log(whateveryourstuckwith) and read through the methods and variables and stuff, really helped me understand Three.js more

Applying postprocessing steps for specific objects

Based on this example i try to create a scene where several objects get the bloom, and other objects dont.
The white cube in the middle is supposed to be just white (without the bloom)
I'm confused on how to get the result that i want. I tried for example adding a 2nd scene with the white cube but it seems i cant get the order right. Maybe my approch with different scenes is wrong?
Whats the "best" way to achieve this behaviour? I always end up just seeing one scene, just the white cube or the 4 colored ones. (example below shows everything atm)
myFiddle: https://jsfiddle.net/qwertasyx/8qw3ys4z/16/
var scene,scene2,camera, controls, pointLight, stats;
var composer, renderer, mixer;
var params = {
exposure: 1,
bloomStrength: 1.5,
bloomThreshold: 0,
bloomRadius: 0
};
var objects = [];
var clock = new THREE.Clock();
var container = document.getElementById( 'container' );
stats = new Stats();
//container.appendChild( stats.dom );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.toneMapping = THREE.ReinhardToneMapping;
container.appendChild( renderer.domElement );
scene = new THREE.Scene();
//scene2 = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 100 );
camera.position.set( 2.5,2.5, 10 );
scene.add( camera );
// scene2.add( camera );
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.maxPolarAngle = Math.PI * 0.5;
controls.minDistance = 1;
controls.maxDistance = 10;
controls.target.set(2.5,2.5,0)
controls.update()
// scene.add( new THREE.AmbientLight( 0x404040 ) );
pointLight = new THREE.PointLight( 0xffffff, 1 );
// camera.add( pointLight );
var renderScene = new THREE.RenderPass( scene, camera );
//var renderScene2 = new THREE.RenderPass( scene2, camera );
var bloomPass = new THREE.UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
bloomPass.renderToScreen = true;
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;
composer = new THREE.EffectComposer( renderer );
composer.setSize( window.innerWidth, window.innerHeight );
composer.addPass( renderScene );
composer.addPass( bloomPass );
//composer.addPass( renderScene2 );
//objects
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var cube = new THREE.Mesh( geometry, material );
cube.vrz = 0.01;
cube.position.x += 5
scene.add( cube );
objects.push(cube)
var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var cube = new THREE.Mesh( geometry, material );
cube.vrz = 0.01;
cube.position.x += 5
cube.position.y += 5
scene.add( cube );
objects.push(cube)
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
cube.vrz = 0.01;
cube.position.y += 5
scene.add( cube );
objects.push(cube)
var material = new THREE.MeshBasicMaterial( { color: 0x0000ff } );
var cube = new THREE.Mesh( geometry, material );
cube.vrz = 0.01;
scene.add( cube );
objects.push(cube)
// cube thats supposed to be not bloomy
var material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
var cube = new THREE.Mesh( geometry, material );
cube.vrz = 0.01;
cube.position.y += 2.5
cube.position.x += 2.5
scene.add( cube );
objects.push(cube)
var gui = new dat.GUI();
gui.add( params, 'exposure', 0.1, 2 ).onChange( function ( value ) {
renderer.toneMappingExposure = Math.pow( value, 4.0 );
} );
gui.add( params, 'bloomThreshold', 0.0, 1.0 ).onChange( function ( value ) {
bloomPass.threshold = Number( value );
} );
gui.add( params, 'bloomStrength', 0.0, 3.0 ).onChange( function ( value ) {
bloomPass.strength = Number( value );
} );
gui.add( params, 'bloomRadius', 0.0, 1.0 ).step( 0.01 ).onChange( function ( value ) {
bloomPass.radius = Number( value );
} );
window.onresize = function () {
var width = window.innerWidth;
var height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
composer.setSize( width, height );
};
function animate() {
requestAnimationFrame( animate );
objects.forEach(function(obj){
obj.rotation.z += obj.vrz;
});
stats.update();
composer.render();
}
animate();
I had a similar problem once. An example from this comment helped me.
Note that in that example there are 2 scenes and 2 composers (the final composer gets output of the previous composer as its input)
ppoFinal.blendPass.uniforms.tAdd.value = ppoRGB.composer.renderTarget2.texture;
and render() is called on both composers.
ppoRGB.composer.render();
ppoFinal.composer.render();
This pattern allows you to apply postprocessing effects selectively and it works well. The problem is the scalability of the method and probably performance. Because when you want to apply another object with yet different effect, you need to introduce 3rd scene and 3rd composer. For my little project in the past I ended up with 4 scenes and 4 composers...

GUI and Raycaster dont work together (three.js)

I have the following code to add a gui and the ability to click on objects.
When I set the controls as controls = new THREE.TrackballControls( camera, renderer.domElement); the GUI works but the Raycaster doesnt seem to work.
If I define the constrols as controls = new THREE.TrackballControls( camera); the raycaster works, however once I click the gui on the corner, then wherever I move the mouse the values of the gui change, while if I close it, the GUI resize with response to mouse movements
Can Anyone give me any hint how to fix this?
At the moment works but I'm able to unclick from the control by simultaneously left and right clicking
This link shows how far I have gone and give you an idea of the problem
http://subsurface.gr/joomla/threejs/StreamFnc_ws.html
Here is the full code:
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
// global variables
var camera, controls, scene, renderer;
var container, stats;
var raycaster, intersects;
var threshold = 0.05;
var mouse = new THREE.Vector2();
var cube;
// Parameters for GUI
var params = {
AAmin: 0.0,
AAmax: 1000.0
};
// main functions
init();
animate();
function init(){
container = document.createElement( 'div' );
document.body.appendChild( container );
//Setup Camera
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
camera.name = 'camera';
camera.position.z = 20;
// Setup world
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 );
// Setup lights
var directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.set( 1, 1, 1 );
scene.add( directionalLight );
directionalLight.name = 'directionalLight';
var directionalLight1 = new THREE.DirectionalLight( 0x002288 );
directionalLight1.position.set( -1, -1, -1 );
directionalLight1.name = 'directionalLight1';
scene.add( directionalLight1 );
var ambientLight = new THREE.AmbientLight( 0x222222 );
ambientLight.name = 'ambientLight';
scene.add( ambientLight );
raycaster = new THREE.Raycaster();
raycaster.params.Points.threshold = threshold;
// Main Scene
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
cube = new THREE.Mesh( geometry, material );
cube.name = 'mycube';
scene.add( cube );
// GUI parameter
var gui = new dat.GUI();
gui.add( params, 'AAmin', -1000, 500 );
gui.add( params, 'AAmax', 500, 2000 );
gui.open();
//renderer
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setClearColor( scene.fog.color );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//controls
controls = new THREE.TrackballControls( camera);
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
controls.keys = [ 65, 83, 68 ];
controls.addEventListener( 'change', render);
stats = new Stats();
container.appendChild( stats.dom );
// events
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
render();
}
function animate() {
requestAnimationFrame( animate );
render();
controls.update();
}
function render() {
renderer.render( scene, camera );
stats.update();
}
function onDocumentMouseDown( event ){
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
intersects = raycaster.intersectObject( cube );
if ( intersects.length > 0 ){
console.log("You click a cube!");
}
}
If I understand correctly, the TrackballControls is stopping propagation of the mouseDown event (bound to the renderer.domElement) -- meaning your onDocumentMouseDown handler isn't being invoked. Try moving your document.addEventListener(...) to come before new THREE.TrackballControls(...).
Responding to your comment below:
I see the problem now. There appears to be an incompatibility between TrackballControls and Dat.GUI in that the TrackballControls mouseup events stops propagation of the event, which causes Dat.GUI to bug out and get stuck resizing the UI for some reason.
I believe you can solve this by disabling TrackballControls when clicking the GUI, and re-enabling TrackballControls on mouseup:
gui.domElement.addEventListener( 'mousedown', function(){ controls.enabled = false; }, false );
document.addEventListener( 'mouseup', function(){ controls.enabled = true; }, false );

Three.js CanvasRenderer Artifacts

I am trying to load a collada file using Threejs. All works well, but if I make the object spin I can see that the rendering is not right. Check the image:
Here is the code (which was partially stolen from another example):
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to spin the cube';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 20, window.innerWidth / window.innerHeight, .1, 10000 );
camera.position.x=50;
camera.position.y=50;
camera.position.z=50;
camera.lookAt(new THREE.Vector3(0,0,0));
scene = new THREE.Scene();
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
var ambientLight = new THREE.AmbientLight(0x000000);
scene.add(ambientLight);
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(100,50,80).normalize();
scene.add(directionalLight);
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true; // this rotates so it looks right
loader.load('models/VM.dae', function (result) {
cube = result.scene;
// cube.doubleSided = true;
// cube.flipSided = true;
console.log(cube);
cube.updateMatrix();
scene.add(result.scene);
animate();
});
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
cube.rotation.y += 0.01;
// plane.rotation.y = cube.rotation.y += ( targetRotation - cube.rotation.y ) * 0.05;
renderer.render( scene, camera );
}
New update:
I changed the loader to a MTL+OBJ one. The result is exactly the same:
var loader = new THREE.OBJMTLLoader();
loader.addEventListener("load", function (event) {
cube = event.content;
cube.doubleSided = true;
console.log(event);
scene.add(cube);
animate();
});
loader.load ("models/VM.obj", "models/VM.mtl");
Fiddle: http://jsfiddle.net/qMqH7/
Your model is throwing errors in the Console, I would suggest you track them down.
What you are seeing is a known limitation of CanvasRenderer related to depth-sorting. It is made worse by your geometry which has several elongated faces. The model renders correctly with WebGLRenderer.
Also, object.doubleSided has been deprecated. It has been replaced by material.side = THREE.DoubleSide. It does not appear that flag is required in this case.
three.js r.58

Resources