Change camera position distance in ThreeJS - three.js

In ThreeJS, I am trying to bring my camera closer to the rendered mesh so it's taking up more of the viewport. I have messed around with the camera.position.set values but these only seem to change the rotation, not actually bring it closer/further away from the object.
I'm using the OrbitControls module and think this may be overriding the default settings, but am a bit stumped as to how the distance can be changed?
Any help is much appreciated.
Full source
function init() {
// renderer
renderer = new THREE.WebGLRenderer( { canvas: artifactCanvas, antialias: true } );
renderer.setSize(800, 600);
// scene
scene = new THREE.Scene();
scene.add( new THREE.GridHelper( build_plate_size_mm, build_plate_grid_segments ) );
scene.background = new THREE.Color( 0xc5e5fc );
// camera
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 3000 );
camera.position.set( 1000, 500, 1000 );
camera.lookAt( 0, 200, 0 );
//controls
orbit = new THREE.OrbitControls( camera, renderer.domElement );
orbit.update();
orbit.addEventListener( 'change', render );
control = new THREE.TransformControls( camera, renderer.domElement );
control.showY = false;
control.addEventListener( 'change', render );
control.addEventListener( 'dragging-changed', function ( event ) {
orbit.enabled = ! event.value;
} );

Try setting the position of the camera via the THREE.Vector3 method.
camera.lookAt(new THREE.Vector3(0,0,0));
Refrence

Related

Three.js: is using a RenderTarget as a mesh the most direct way put a scene back into a WebGLRenderer after an EffectComposer?

I'm attempting to use the Magnify-3d package after using an EffectComposer to apply a bokeh effect to a scene. Magnify-3D takes in a renderer, so I cannot simply pass in the EffectComposer after applying passes.
The intended result would work like a microscope, with the ability to independently adjust the plane of focus by adjusting the BokehPass effect, and the magnification using Magnify-3d.
The only way I've gotten this to work so far has been like so:
Create a temporary scene containing actual scene I want to render.
Create an EffectComposer that applies BokehPass and renders the temporary scene to renderTarget.
Create a PlaneBufferGeometry and a mesh that maps renderTarget.texture (the output of the temporary scene) to the plane, and add this to a new scene.
Render the new scene that effectively is just a camera staring at a mesh of the original scene.
Pass the renderer into magnify3d, which creates a lens effect around the scene I want to render.
This seems to work OK (though there appears to be some fuzziness and distortion of the original scene I'm still working out), but I began to wonder -- is this really the best way to use something rendered to a RenderTarget? Is there a more direct way than effectively taking a picture of a picture that I can use to take the output of an EffectComposer, feed it back into a renderer so my final scene is rendered in a WebGLRenderer, and pass it into a library? Any other way I can think to do this, the EffectComposer would not be able to run (since Magnify3d takes in a renderer, not an EffectComposer and I need to run the EffectComposer before passing it into a renderer).
Here's a screenshot of the final result
Here's some code below:
// create initial scene
const renderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight );
const rtScene = new THREE.Scene();
const rtCamera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000000000 );
// add a sample cube to the new scene and move the camera back
const geometry = new THREE.BoxGeometry( 10, 10, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
rtScene.add(cube);
rtCamera.position.z = 500;
// initialize renderer
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xffffff, 1 );
document.body.appendChild( renderer.domElement );
// initialize EffectComposer and apply BokehEffect.
// Note that composer renders its output to RenderTarget.
const composer = new EffectComposer( renderer, renderTarget );
composer.renderToScreen = false;
const renderPass = new RenderPass( rtScene, rtCamera );
composer.addPass( renderPass );
const bokehValues = {
focus: 500,
aperture: .00025,
maxblur: 1,
width: window.innerWidth,
height: window.innerHeight
}
export const bokehPass = new BokehPass( rtScene, rtCamera, bokehValues);
composer.addPass( bokehPass );
// create final scene to render before passing to Magnify3D
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000000000 );
const scene = new THREE.Scene();
camera.position.z = 100;
// make a plane geometry, a mesh that maps renderTarget.texture, and add it to the scene
const planeGeometry = new THREE.PlaneBufferGeometry( window.innerWidth, window.innerHeight );
const planeMaterial = new THREE.MeshBasicMaterial( { map: renderTarget.texture } );
const plane = new THREE.Mesh( planeGeometry, planeMaterial );
scene.add( plane );
function animate() {
// first render temporary scene
renderer.setClearColor( 0xffffff, 1 );
composer.render(); // now composer has rendered to renderTarget
renderer.setClearColor( 0x141414, 1 ); // create a black background for outside of microscope
renderer.render( scene, camera ); // render final scene with meshed plane
// Finally use Magnify3D to render final scene with microscope
magnify3d.render({
renderer: renderer,
pos: {
x: window.innerWidth/2,
y: window.innerHeight/2
},
renderSceneCB: (target) => {
if (target) {
renderer.setRenderTarget(target);
} else {
renderer.setRenderTarget(null);
}
renderer.render(scene, camera);
},
radius: window.innerWidth/5,
exp: 150,
zoom: state.magnification,
});
requestAnimationFrame( animate );
}

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

Three.js: group of geometry

1.I want to combine the geometry,what should i do ?
By using position? And i even want to let the group of geometry move in the scene together what should i do? By using add()?For example: the group of demond
Why my triangle failed to draw?
my code:
var mesh, renderer, scene, camera, controls;
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 20, 20, 20 );
// controls
controls = new THREE.OrbitControls( camera );
// ambient
scene.add( new THREE.AmbientLight( 0x00ffff ) );
// light
var light = new THREE.DirectionalLight( 0x00ffff, 1 );
light.position.set(10, 10, 0 );
//scene.add( light );
// axes
scene.add( new THREE.AxisHelper( 20 ) );
var verticesOfTriangle1 = new THREE.Vector3(1,0,0);
var verticesOfTriangle2 = new THREE.Vector3(0,0,0.3);
var verticesOfTriangle3 = new THREE.Vector3(0,0,-0.3);
var geometry = new THREE.Triangle(verticesOfTriangle1, verticesOfTriangle2, verticesOfTriangle3);
// material
var material = new THREE.MeshPhongMaterial( {
color: 0x00ffff,
shading: THREE.FlatShading,
transparent: true,
opacity: 0.7,
} );
// mesh
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
the message from chrome:The error message
Use THREE.Group() to combine objects and move them together.
You can use THREE.ShapeGeometry() to create a triangle. To create a mesh your geometry should inherit properties of THREE.Geometry(). Look into geometries of threejs documentation for default geometries supported.

Three.js - Camera collision with scene

This is my first question in StackOverflow, but I've been browsing it for some years now, so I kindly ask you to bear with me. :)
I've been experimenting with Three.js to create a 3D world, and everything looked fine until I needed to control the camera. Since I'm using this lib to avoid having to do matricial calculations myself I found and added TrackballControls to my code aswell. It worked fine but then my camera could pass through the 3D shapes, and also below terrain. Unfortunately, although the movement is exactly what I needed, it didn't serve the purpose of allowing camera to respect collision.
My scene is simply the ground (thin BoxGeometry) and a cube (normal-sized BoxGeometry), and a rotating sphere that shares directionalLight position for a "sun light" effect. Some people here suggested adding Physijs to the code and simulate() physics within the scene, and adding a BoxMesh to the camera to make the physics apply to it aswell, but it simply didn't work (scene turned blank).
My working code so far (without Physijs) is:
window.onload = function() {
var renderer, scene, camera, ground, box, sphere, ambient_light, sun_light, controls;
var angle = 0;
var clock = new THREE.Clock();
init();
render();
function init(){
// Create renderer and add it to the page
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xffffff );
renderer.shadowMapEnabled = true;
document.body.appendChild( renderer.domElement );
// Create a scene to hold our awesome 3D world
scene = new THREE.Scene();
/*** 3D WORLD ***/
// Objects
ground = new THREE.Mesh(
new THREE.BoxGeometry(50, 1, 50),
new THREE.MeshLambertMaterial({ color: 0x33CC33 }),
0 // mass
);
ground.receiveShadow = true;
scene.add( ground );
box = new THREE.Mesh(
new THREE.BoxGeometry( 10, 10, 10 ),
new THREE.MeshLambertMaterial({ color: 0xDD3344 })
);
box.position.y = 5;
box.castShadow = true;
scene.add( box );
sphere = new THREE.Mesh(
new THREE.SphereGeometry( 3, 32, 32 ),
new THREE.MeshBasicMaterial({ color: 0xFFBB00 })
);
sphere.position.set( 1, 15.5, 5 );
scene.add( sphere );
// Light
ambient_light = new THREE.AmbientLight( 0x333333 );
ambient_light.mass = 0;
scene.add( ambient_light );
sun_light = new THREE.DirectionalLight( 0xBBBBBB );
sun_light.position.set( 1, 15.5, 5 );
sun_light.castShadow = true;
sun_light.shadowCameraNear = 1;
sun_light.shadowCameraFar = 100;
sun_light.shadowCameraLeft = -50;
sun_light.shadowCameraRight = 50;
sun_light.shadowCameraTop = -50;
sun_light.shadowCameraBottom = 50;
sun_light.shadowBias = -.01;
scene.add( sun_light );
// Create a camera
camera = new THREE.PerspectiveCamera(
45, // FOV
window.innerWidth / window.innerHeight, // Aspect Ratio
1, // Near plane
1000 // Far plane
);
camera.position.set( 30, 30, 30 ); // Position camera
camera.lookAt( box.position ); // Look at the scene origin
scene.add(camera);
// After swapping THREE.Mesh to Physijs.BoxMesh, this is where I'd attach a BoxMesh to the camera
window.addEventListener( 'resize', onWindowResize, false );
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 4.0;
controls.panSpeed = 0.3;
controls.staticMoving = true; // No sliding after-effects
}
function render() {
// use requestAnimationFrame to create a render loop
angle += .007;
var oscillateZ = Math.sin(angle * (Math.PI*4));
var oscillateX = -Math.cos(angle * (Math.PI*4));
//console.log(oscillateZ);
sphere.position.setZ( sphere.position.z + oscillateZ );
sphere.position.setX( sphere.position.x + oscillateX );
sun_light.position.setZ( sun_light.position.z + oscillateZ );
sun_light.position.setX( sun_light.position.x + oscillateX );
requestAnimationFrame( render );
controls.update();
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
};
Can you guys enlighten me? Thank you for your time!
#Edit
Physijs attempt

Why lighting isn't working in Three.js?

I don't understand why the lighting does not work in my code. I downloaded a simple OBJ. file to test the OBJLoader but the model isn't affected. Before I edited the lighting more, at least the Ambient Lighting would work. Maybe the OBJ. model needs a texture?
var container, stats;
var camera, scene, renderer, controls;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.z = 2.5;
scene.add( camera );
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 2.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.0;
controls.noZoom = false;
controls.noPan = true;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
controls.keys = [ 65, 83, 68 ];
controls.addEventListener( 'change', render );
var ambient = new THREE.AmbientLight( 0x020202 );
scene.add( ambient );
directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.set( 1, 1, 0.5 ).normalize();
scene.add( directionalLight );
pointLight = new THREE.PointLight( 0xffaa00 );
pointLight.position.set( 0, 0, 0 );
scene.add( pointLight );
sphere = new THREE.SphereGeometry( 100, 16, 8 );
lightMesh = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial( { color: 0xffaa00 } ) );
lightMesh.scale.set( 0.05, 0.05, 0.05 );
lightMesh.position = pointLight.position;
scene.add( lightMesh );
var loader = new THREE.OBJLoader();
loader.load( "originalMeanModel.obj", function ( object ) {
scene.add( object );
} );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
}
function render() {
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
MeshBasicMaterial in THREE.js is like a toon shader (good for silouhette, shadow drawing or wireframe) and and is not affected by lights.
Try MeshLambertMaterial or MeshPhongMaterial
I had similar problems when using the Three.js exporter for Blender, everything appeared dark even with diffuse colors set in the original blender model and an ambient light added to the scene in the Three.js code. It turns out the fix was to edit part of the converted model file, there was a line to the effect of:
"colorAmbient" : [0, 0, 0]
which I manually changed to
"colorAmbient" : [0.75, 0.75, 0.75]
everywhere it appeared, and that fixed the problem. I bring this up because my best guess is that you are experiencing a problem similar to this. Without seeing the *.obj file it is difficult to diagnose the problem exactly, but perhaps in your model settings you could try changing the ambient color value rather than, say, the diffuse color value, which is what we normally think of when assigning color to a model.
Maybe this will help you if you are experiencing the same problem like me a few days ago, if you have no normals in your obj that's definitely somewhere to look at.
You can try to start with a MeshBasicMaterial as well just to check the vertices/ faces are ok: new THREE.MeshBasicMaterial({ color: 0x999999, wireframe: true, transparent: true, opacity: 0.85 } )
Also, as mr doob said, please consider sharing the obj you're loading.

Resources