three.js set and read camera look vector - vector

Instead of rotating the camera with camera.rotation or with the lookAt() function
I'd like to pass a look vector directly to the camera... Is it possible to set a camera look vector directly and is it possible to read the look vector from the camera?

The camera does not have a "look vector", so you cannot set it.
You can, however, construct a point to look at by adding your look vector to the camera's position, and then calling
camera.lookAt( point );
Here is how to determine the direction in which the camera is looking, assuming the camera either has no parent (other than the scene).
The camera is looking down its internal negative z-axis, so create a vector pointing down the negative z-axis:
var vector = new THREE.Vector3( 0, 0, - 1 );
Now, apply the same rotation to the vector that is applied to the camera:
vector.applyQuaternion( camera.quaternion );
The resulting vector will be pointing in the direction that the camera is looking.
Alternatively, you can use the following method, which works even if the camera is a child of another object:
camera.getWorldDirection( dirVector );
three.js r.73

These other answers are very insightful, but not completely correct. The code returns a vector that points in the same direction that the camera is pointing at. That's a great start!
But unless the camera is at the origin (0, 0, 0) (or lies exactly on the line segment that connects the origin to the rotated vector point without passing beyond that point so that the point is behind the camera) the camera won't be looking at that point. Clearly -- just common sense -- the position of the camera also influences what points are being looked at. Just think about it!!
The camera method lookAt() looks at a point in 3D space regardless of where the camera is. So to get a point that the camera is looking at you need to adjust for the camera position by calling:
vec.add( camera.position );
It is also worth mentioning that the camera is looking not at a single point but is looking down a line of an infinite number of points, each at a different distance from the camera. The code from the other answers returns a vector that is exactly one unit in length because the application of a quaternion to the normalized z-axis vector (0, 0, -1) returns another normalized vector (in a different direction). To calculate the look at point at an arbitrary distance x from the camera use:
THREE.Vector3( 0, 0, -x ).applyQuaternion( camera.quaternion ).add( camera.position );
This takes a point along the z-axis at a distance x from the origin, rotates it to the direction of the camera and then creates a "world point" by adding the camera's position. We want a "world point" (and not just a "relative to the camera point") since camera.lookAt() also takes a "world point" as a parameter.

The above answer wrapped as a util, this is what I do with my Three Utils:
THREE.Utils = {
cameraLookDir: function(camera) {
var vector = new THREE.Vector3(0, 0, -1);
vector.applyEuler(camera.rotation, camera.eulerOrder);
return vector;
}
};
Call it with THREE.Utils.cameraLookDir(camera);

What I did was to use method lookAt(Vector) just before render the scene like in below code , just try it using it on a new html file :)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style >
*{
margin: 0 ;
}
#WebGlElement {
height: 500px;
width: 500px;
background-color: red
}
</style>
</head>
<body>
<script src="js/three.min.js"></script>
<div id="WebGlElement"></div>
<script>
var contianer = document.getElementById("WebGlElement");
var origin = new THREE.Vector3(0,0,0);
// CREATE THREE BASIC ELEMENTS
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 40, 300/300, 1, 1000 );
var renderer = new THREE.WebGLRenderer();
// SET RENDERER AND ATTACH IT TO BODY
renderer.setSize( 500, 500 );
//document.body.appendChild( renderer.domElement );
contianer.appendChild( renderer.domElement);
// CREATE A GEOMETRY AND ADD IT TO SCENE
/*var geometry = new THREE.BoxGeometry( 1, 1, 5 );
var material = new THREE.MeshBasicMaterial( { color: 0x1abc9c } );
material.wireframe = true ;
material.wireframeLinewidth = 0.1 ;
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );*/
var geometry = new THREE.Geometry();
geometry.elementsNeedUpdate=true;
geometry.vertices.push(
new THREE.Vector3( -0, 1, 0 ),
new THREE.Vector3( -1, -1, 0 ),
new THREE.Vector3( 1, -1, 0 )
);
geometry.faces.push(
new THREE.Face3( 0, 1, 2 ),
new THREE.Face3( 2, 1, 0 )
);
var material = new THREE.MeshBasicMaterial( { color: 0x1abc9c } );
//material.wireframe = true ;
//material.wireframeLinewidth = 0.1 ;
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
var axisHelper = new THREE.AxisHelper( 1 );
scene.add( axisHelper );
// POSITION OF CAMER ON Z
camera.position.z = 5;
camera.position.y = 5;
camera.up = new THREE.Vector3(0,0,1);
var dir = 1;
var number = 0.115
// CREATE FUNCTION FOR RENDER
var render = function () {
requestAnimationFrame( render );
//circle.rotation.x += 0.01;
if ( camera.position.x> 5) {
dir = -1;
}
if ( camera.position.x< -5) {
dir = 1;
}
camera.lookAt(cube.position);
//camera.rotation.y += 0.015 * dir;
camera.position.x += number * dir;
renderer.render(scene, camera);
};
// EXECUTE FIRST RENDER
render();
</script>
</body>
</html>

Related

tick function is not working in aframe 0.8.2

I was trying to use tick function as described in the below link https://github.com/aframevr/aframe/blob/master/docs/introduction/best-practices.md but it didnt worked out
AFRAME.registerComponent('foo', {
tick: function () {
var el = this.el;
var rotationTmp = this.rotationTmp = this.rotationTmp || {x: 0, y: 0, z: 0};
var rotation = el.getAttribute('rotation');
rotationTmp.x = rotation.x + 0.1;
rotationTmp.y = rotation.y;
rotationTmp.z = rotation.z;
el.setAttribute('rotation', rotationTmp);
}
});
Expected output the object should rotate around x actual result nothing happens..
I hope it's okay if i clarify a bit Kevin's answer.
But first of all, the code is working. Both in aframe 0.9.2 and 0.8.2.
The issue may be related to
the script being placed after the scene is loaded
the component not being attached to the entity:
js:
AFRAME.registerComponent('foo', {
// component body
})
html:
<a-entity foo></a-entity>
As for Kevins answer - it may be a good idea to make changes in the tick function with referring to the underlying THREE.js object.
If you want to rotate a box, there's no need to throw in all that logic you have:
1) create a tmp variable
2) get the object rotation
3) set the tmp variable
4) set the object rotation
When you have a function which executes on each render loop (tick) then you want to minimize what's happening there. So Kevin directly accesses the THREE.js object, and changes the rotation:
tick: function() {
el.object3D.rotation.x += 0.1 * Math.PI / 180 // three uses radians
}
Check it out in this fiddle.
You can just do el.object3D.rotation.x += 0.1

Three.js - how to make objects with different positions look at Orthographic camera using vectors?

Three.js 76
I start to use Orthographic camera instead Perspective - has some troubles.
I use stemkoski's shader-glow for point animation in scene: he created some sphere and then use shader for it transparancy, i just add animation to it.
function animatePoints() {
var alphas;
var count;
var time;
let j = 0;
while ( animatedPoints[j] ) {
let threeGlow = animatedPoints[j];
let finishAnimation = threeGlow.meta.state.finishAnimation;
let itFinished = 0;
let pointGlowMat = threeGlow.material;
let pointGlowGeom = threeGlow.geometry;
// ########## make glow look at camera
pointGlowMat.uniforms.viewVector.value = new THREE.Vector3().subVectors( threeGlow.position, camera.position);
alphas = pointGlowGeom.attributes.alpha;
count = alphas.count;
time = 0.001* Date.now();
if ( finishAnimation ) {
....
} else {
....
}
alphas.needsUpdate = true;
j++;
}
}
Main goal - to make glow look at camera. When camera was perspective i use solution with subtracts two vectors - camera position and glow position, so it look like glow looking at camera.
pointGlowMat.uniforms.viewVector.value = new THREE.Vector3().subVectors( camera.position, threeGlow.position );
But now, when i use Orthographic camera this solution doesn't work correctly.
The problem is that now the glow should look not at camera position point, it should look at plane of the camera.
I make some pic scheme for that situation:look it, it very useful
So for each new glow (it's positions of course different) i must get new red vector, to make each glow look at orto cam.
Any ideas?
What you need to do to get the red vector in your image, is project vector sub on the vector representing the direction in which the camera is looking.
I think this is what you need:
pointGlowMat.uniforms.viewVector.value = new THREE.Vector3()
.subVectors( camera.position, threeGlow.position )
.projectOnVector( camera.getWorldDirection() );
One way to make an object "look at" an orthographic camera by using this pattern:
object.quaternion.copy( camera.quaternion );
The object's view direction will be perpendicular to the camera's projection plane.
This approach is appropriate if neither the object nor the camera have a rotated parent.
three.js r.84

Can you reflect geometry (not textures) in three.js?

I have found many examples of three.js reflecting images, but is at all possible to reflect lines, triangles and shapes? I want to create a mirror pyramid that reflects lines.
For example: http://www.gus.graphics/buffer.html >This page has lots of lines.
I want to reflect them onto a 3d shape that sits in the middle.
For example: http://www.gus.graphics/ball1.html > This page has a mirror ball.
These are the sort of lines of code I am looking at. Not sure if it's even possible.
var textureCube = THREE.ImageUtils.loadTextureCube( urls );
var material = new THREE.MeshBasicMaterial( { color: 0xffffff, envMap: textureCube } )
shader.uniforms[ "tCube" ].value = textureCube;
At the moment that code above is taking in a bunch of images "urls", but as you probably know by now I want to reflect the geometry in the first link I provided.
You can take a look at THREE.CubeCamera. It creates 6 cameras that render to a WebGLRenderTargetCube and then use it as envMap. An example would be:
//Create cube camera
var cubeCamera = new THREE.CubeCamera( 1, 100000, 128 );
scene.add( cubeCamera );
//Create material and mesh
var chromeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: cubeCamera.renderTarget } );
var car = new Mesh( carGeometry, chromeMaterial );
scene.add( car );
//Update the render target cube
car.setVisible( false );
cubeCamera.position.copy( car.position );
cubeCamera.updateCubeMap( renderer, scene );
//Render the scene
car.setVisible( true );
renderer.render( scene, camera );
See this: http://threejs.org/docs/#Reference/Cameras/CubeCamera
There are also examples usage here:
http://threejs.org/examples/#webgl_materials_cubemap_dynamic
http://threejs.org/examples/#webgl_materials_cubemap_dynamic2

Three.js rotate camera to specific position

I have an sphere with divs using CSS3DRenderer. When I click to one of the divs I'd like to position/rotate the camera so the element displays in the center of the screen.
I've tried several examples and I've read other answers but still I cant get it to work.
At the moment it moves the camera but the sphere gets repositioned in different places
What I'm trying to do is the following:
Gets the HTML element's class. Then loop through an array of THREE.CSS3DObject to get its position, then use that to position the camera.
function moveCamera(element) {
for ( var i = 0; i < objects.length; i ++ ) {
var object = objects[ i ];
if(object.element.className == element.className) {
position = object.position;
rotation = object.rotation;
found = true;
break;
}
}
if (found) {
camera.rotation = rotation;
render();
found = false;
} }
What I'm I doing wrong?
Here's the example http://jsfiddle.net/37R22/1/
Thanks
You were close. You just have to move the camera to the right place.
camera.rotation.copy( rotation );
camera.position.copy( position ).multiplyScalar( 4 );
Updated fiddles: http://jsfiddle.net/37R22/2/ or http://jsfiddle.net/37R22/3/
Be careful about going behind-the-back of TrackballControls and modifying the camera properties yourself. This appears to work, however.
three.js r.65

Wrong getBounds() on LineScaleMode.NONE

I have write a simple example that adds a canvas and draw a rectangle with stroke size 20 scale mode none.
The problem is that if I call getBounds() first time I will get a correct result but after I call scale(); the getBounds() function will give me a wrong result.
It will take in cosideration the stroke but stroke has scalemode to none and on the screen nothing happens but in the result I will have a x value smaller. Can sombody tell me how can I fix this?
protected var display :Canvas;
protected function addCanvas():void
{
display = new Canvas();
display.x = display.y = 50;
display.width = 100;
display.height = 100;
display.graphics.clear();
display.graphics.lineStyle( 20, 0x000000, 0.5, true, LineScaleMode.NONE );
display.graphics.beginFill( 0xff0000, 1 );
display.graphics.drawRect(0, 0, 100, 100);
display.graphics.endFill();
area.addChild( display );
traceBounce();
}
protected function scale():void
{
var m :Matrix = display.transform.matrix;
var apply :Matrix = new Matrix();
apply.scale( 2, 1 );
apply.concat( m );
display.transform.matrix = apply;
traceBounce();
}
protected function traceBounce():void
{
trace( display.getBounds( this ) );
}
Setting the width/height and scaling the same display object can give confusing results. Does your Canvas class do anything unusual (e.g. set the scrollRect or add a mask)?
Also you could try getting bounds of the Canvas' parent instead, or setting cacheAsBitmap on the Canvas and seeing if that helps?

Resources