Three.js store camera rotation and apply to camera dolly - three.js

I'm developing a VR app and I'm attempting to store the current camera viewing angle with
THREE.Utils = {
cameraLookDir: function(camera) {
var vector = new THREE.Vector3(0, 0, -1);
vector.applyEuler(camera.rotation, camera.eulerOrder);
return vector;
}
};
var dir = THREE.Utils.cameraLookDir(camera);
var defaults = {
x:dir.x,
y:dir.y,
z:dir.z,
fov: camera.fov
};
I'm then attempting to apply this to a dolly which I use to pre-set the camera viewing angle for using with VRControls
The dolly is constructed as
dolly = new THREE.PerspectiveCamera();
dolly.position.set( 0, 0, 0 );
scene.add( dolly );
dolly.add( camera );
and I try and apply the angle so the camera is facing the same way
dolly.rotation.x = defaults.x;
dolly.rotation.y = defaults.y;
dolly.rotation.z = defaults.z;
This isn't' really working, and I'm not really sure how to go about getting the camera to face the same way as it's saved values.
Any clues on how to go about this?

Related

Three.js: Calling lookAt() method causes mesh to disappear

I'm trying to use the three.js lookAt() method on a meshes (from CylinderBufferGeometry) so that it is oriented toward a point, but when I use the .lookAt() method, it causes the mesh to disappear from view.
The cylinder shows up fine if I comment out the .lookAt() method. I'm using a THREE.PerspectiveCamera and the THREE.WebGLRenderer incase that could have anything to do with the issue.
// Build cylinder
var cylinderRadius = 0.15
var cylinderHeight = 20
var geometry = new THREE.CylinderBufferGeometry(cylinderRadius, cylinderRadius, cylinderHeight);
var material = new THREE.MeshBasicMaterial({color: 0xffffff});
var cylinder = new THREE.Mesh(geometry, material);
// Point the cylinder up
cylinder.geometry.rotateX( Math.PI / 2);
cylinder.geometry.translate(0,0, cylinderHeight/2 );
// Move cylinder to position
cylinder.position.x = 10;
cylinder.position.y = 10;
// Look at point
cylinder.lookAt(0,0,15); // <-- ISSUE OCCURS HERE
scene.add(cylinder);
render();
Use cylinder.lookAt(new THREE.Vector3(0,0,15)); instead of cylinder.lookAt(0,0,15);

Camera transition with rotation

I got a question about camera object. I'm trying to make a transition between cameras and I got it partially working. Camera is moving well but it does not rotate correct. I suppose my code does not calculate lookAtVector right but I cannot find information how to do it correct.
Here is the code I'm using:
var new_position = new_camera.position.clone();
var new_rotation = new_camera.rotation.clone();
var new_quaternion = new_camera.quaternion.clone();
camera.rotation.clone(new_rotation);
camera.quaternion.clone(new_quaternion);
newlookAtVector = new THREE.Vector3(0, 0, -1);
newlookAtVector.applyEuler(new_rotation, new_camera.eulerOrder);
new TWEEN.Tween( camera.position ).to( {
x: new_position.x,
y: new_position.y,
z: new_position.z}, 600 ).onUpdate(function () {
camera.lookAt(newlookAtVector);
}).onComplete(function () {
camera.lookAt(newlookAtVector);
}).easing( TWEEN.Easing.Sinusoidal.Out).start();
Thank you!

THREE.JS UV Mapping on ExtrudeGeometry

I need to apply a texture on a ExtrudeGeometry object.
The shape is a circle and the extrude path is composed of 2 vectors :
One for the top.
One for the bottom.
I didn't choose cylinderGeometry because I need to place top/bottom sections of my geometry at precise positions and because the geometry created will not be always purely vertical (like a oblique cylinder for example).
Here is a picture of a section (one top vector, one bottom vector and a shape extruded between these 2 vectors).
and a picture of the texture I'm trying to apply.
All I want to do is to wrap this picture on the vertical sides of my object just one time.
Here is my code :
var biVectors = [ new THREE.Vector3( this.startVector.x, this.startVector.y, this.startVector.z ) , new THREE.Vector3( this.endVector.x, this.endVector.y, this.endVector.z ) ];
var wellSpline = new THREE.SplineCurve3(biVectors);
var extrudeSettings = {
steps : 1,
material: 0,
extrudeMaterial: 1,
extrudePath : wellSpline
};
var pts = [];
for (var i = 0; i <= this.segments; i++) {
var theta = (i / this.segments) * Math.PI * 2;
pts.push( new THREE.Vector3(Math.cos(theta) * this.diameter , Math.sin(theta) * this.diameter, 0) );
}
var shape = new THREE.Shape( pts );
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var texture = THREE.ImageUtils.loadTexture( 'textures/sampleTexture2.jpg' );
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.flipY = false;
var material = new THREE.MeshBasicMaterial( { map: texture } );
var slice = new THREE.Mesh( geometry, material );
var faceNormals = new THREE.FaceNormalsHelper( slice );
console.log("face normals: ", faceNormals);
myCanvas.scene.add( faceNormals );
slice.parentObject = this;
myCanvas.scene.add( slice );
this.object3D = slice;
}
Now, as you can see, the mapping is not correct at all.
I've read a lot of information about this problem the last 3 days. But I'm running out of options as I'm new to THREE.JS.
I think I have to redefine the UV coordinates but I have no clue how to do this.
It seems that wrapping a texture on a cylinder like object is anything but easy in THREE.JS.
Can someone please help me on this issue ?

Isometric cube, size does not match up with tilesize 128x128

I've been trying for bigger parts of the night to make a export code that quickly will let me texture cubes and export them to a game i'm making, but for some reason I can't make my cube to cover the entire 128x128 width and height that I want it to have.
I have the following code:
function init(){
if( Detector.webgl ){
renderer = new THREE.WebGLRenderer({
antialias : false, // to get smoother output
preserveDrawingBuffer : true // to allow screenshot
});
renderer.setClearColorHex( 0xBBBBBB, 1 );
// uncomment if webgl is required
//}else{
// Detector.addGetWebGLMessage();
// return true;
}else{
renderer = new THREE.CanvasRenderer();
}
renderer.setSize(128,128);
document.getElementById('container').appendChild(renderer.domElement);
// add Stats.js - https://github.com/mrdoob/stats.js
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.bottom = '0px';
document.body.appendChild( stats.domElement );
var zoom = 1.0;
// create a scene
scene = new THREE.Scene();
// put a camera in the scene
camera = new THREE.OrthographicCamera(WIDTH / -zoom, HEIGHT / zoom, WIDTH / zoom, HEIGHT / -zoom, -2000, 1000);
//camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set(0.45,0.45,0.45);
camera.lookAt(scene.position);
//camera.position.set(0, 0, 5);
scene.add(camera);
// create a camera contol
//cameraControls = new THREEx.DragPanControls(camera)
// transparently support window resize
THREEx.WindowResize.bind(renderer, camera);
// allow 'p' to make screenshot
THREEx.Screenshot.bindKey(renderer);
// allow 'f' to go fullscreen where this feature is supported
//if( THREEx.FullScreen.available() ){
// THREEx.FullScreen.bindKey();
// document.getElementById('inlineDoc').innerHTML += "- <i>f</i> for fullscreen";
//}
// here you add your objects
// - you will most likely replace this part by your own
//var geometry = new THREE.TorusGeometry( 1, 0.42 );
var cubeSize = 128;
var geometry = new THREE.CubeGeometry( cubeSize, cubeSize, cubeSize );
var material = new THREE.MeshNormalMaterial();
mesh= new THREE.Mesh( geometry, material );
mesh.rotation.x = 0;
mesh.rotation.y = 0;
mesh.rotation.z = 0;
scene.add( mesh );
}
I've been trying out different "zooms" but it still ends up either too big or too small.
The point with all this is to end up with a code that can generate something like this:
https://dl.dropboxusercontent.com/u/5256694/cube_ex.png
What am I doing wrong?
Kind Regards
Hiam
Instead of thinking about the parameters of THREE.OrthographicCamera as "zoom" levels, you should think of them as coordinates of boundary planes for what the camera is able to see.
Also see the answer to Three.js - Orthographic camera for more details about using orthographic cameras in Three.js

Specifying the range for Depth of Field (MeshDepthMaterial range?)

I have adapted this post processing example http://mrdoob.github.com/three.js/examples/webgl_postprocessing_dof.html to apply a Depth of Field / Bokeh effect. How can I specify the focus range (or whatever it could be called)?
If the camera far plane is at 10000, and the model size is 10 it was impossible to focus into invidual parts of the model - because it tries to focus from 1-10000 (camera-near to camera-far) instead of 1-10 (between camera and the back of my model), the actual area of interest.
It did work fine after I realised to set the camera far plane as low as possible (to about same as scene size), so the focus can adjusted where the actual model is.
Now I can't do the camera far plane trick anymore, because I added a skybox, so the camera needs to have it's far plane quite far related to the model size. That messes up the Depth of Field; I can focus very close or very far, but the whole model is either completely blurred or not blurred at all as the adjustable distance is way too big (all the way to the skybox).
If I know the area I want to be able to focus at, how can I specify it in my code?
Here is my setup code:
dof_material_depth = new THREE.MeshDepthMaterial();
dof_scene = new THREE.Scene();
dof_camera = new THREE.OrthographicCamera(SCREEN_WIDTH / - 2, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_HEIGHT / - 2, -10000, 10000 );
dof_camera.position.z = 100;
dof_scene.add( dof_camera );
var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat };
dof_rtTextureDepth = new THREE.WebGLRenderTarget(SCREEN_WIDTH, SCREEN_HEIGHT, pars );
dof_rtTextureColor = new THREE.WebGLRenderTarget(SCREEN_WIDTH, SCREEN_HEIGHT, pars );
dof_bokeh_shader = THREE.BokehShader;
dof_bokeh_uniforms = THREE.UniformsUtils.clone(dof_bokeh_shader.uniforms );
dof_bokeh_uniforms[ "tColor" ].value = dof_rtTextureColor;
dof_bokeh_uniforms[ "tDepth" ].value = dof_rtTextureDepth;
dof_bokeh_uniforms[ "focus" ].value = 1.1;
dof_bokeh_uniforms[ "aspect" ].value = SCREEN_WIDTH / SCREEN_HEIGHT;
dof_materialBokeh = new THREE.ShaderMaterial( {
uniforms: dof_bokeh_uniforms,
vertexShader: dof_bokeh_shader.vertexShader,
fragmentShader: dof_bokeh_shader.fragmentShader
});
dof_quad = new THREE.Mesh( new THREE.PlaneGeometry(SCREEN_WIDTH, SCREEN_HEIGHT), dof_materialBokeh );
dof_quad.position.z = -500;
dof_scene.add(dof_quad );
And here the rendering part:
renderer.render(scene, camera, dof_rtTextureColor, true );
scene.overrideMaterial = dof_material_depth;
renderer.render(scene, camera, dof_rtTextureDepth, true );
dof_scene.overrideMaterial = null;
render(dof_scene, dof_camera );
var delta = 0.01;
composerScene.render( delta);
EDIT:
I did manage to get desired results by setting a low far plane for the camera just before rendering the depth material, then reverting back to normal before rendering the composite:
renderer.render(scene, camera, dof_rtTextureColor, true );
var oldfar = camera.far; // this goes to skybox
camera.far = scenesize; // this goes to just behind the model
scene.overrideMaterial = dof_material_depth;
renderer.render(scene, camera, dof_rtTextureDepth, true );
camera.far = oldfar;
dof_scene.overrideMaterial = null;
render(dof_scene, dof_camera );
var delta = 0.01;
composerScene.render( delta);
This works perfect. I will leave the question open though, as I'm quite new to WebGLL / 3D programming in general, want to learn, and would like to know if it's possible to do this in the shaders/materials setup phase.

Resources