I have a strange problem, which can be a three.js bug, but it also can be my curve hands.
I have a scene with some meshes (in example below I used several transparent cubes and small spheres) and one line object (can be Line or LineSegments - doesn't matter) based on buffer geometry. While I rotating the camera line object sometimes disappears form view like it's covered by another object. It seems it also disappears if I cannot see the start point (if rotate camera to a degree where start point is offscreen, even without additional meshes) of the line while 90% of the line object should be in view.
The question is: Why does the line disappear and how should I prevent such its behavior?
This is how it looks on screencast:
http://screencast.com/t/HLC99OMmDdK
And this is an example of the problem:
http://jsfiddle.net/exiara/sa4bxhc3/
You should be able to see how line disappears when camera rotates.
The code of jsfiddle example:
var camera, controls, scene, renderer, dummy, projector,
stats, fps = 30, fpsTimeout = 1000 / fps,
linesGeometry,globalLine;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor(0xFFFFeF, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xFFFFeF, 100, 2500 );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 50000 );
camera.position.set(-450, 300, 650);
camera.target = new THREE.Vector3(0,0,0);
controls = new THREE.OrbitControls( camera );
controls.addEventListener('change', render );
// ------------ MAIN PART START ------------ //
var lines = 1000;
linesGeometry = new THREE.BufferGeometry();
var positions = new Float32Array( lines * 6 );
for ( var i = 0, j, ll = lines; i < ll; i++ ) {
j=i*6;
positions[j] = Math.random()*100;
positions[j+1] = Math.random()*100;
positions[j+2] = Math.random()*100;
positions[j+3] = Math.random()*100;
positions[j+4] = Math.random()*100;
positions[j+5] = Math.random()*100;
}
linesGeometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
globalLine = new THREE.Line( linesGeometry, new THREE.LineBasicMaterial({
color: 0x000000,
transparent: true,
opacity: 0.8
} ));
scene.add( globalLine );
// ------------ MAIN PART END ------------ //
// add cubes
var step = 400;
var gridSize = 4;
var offset = step*gridSize/2;
var cubeGeometry = new THREE.BoxGeometry(step, step, step);
var cubeMaterial = new THREE.MeshBasicMaterial({ color:0xFF0000, ambient: 0xCCCCCC, transparent: true, opacity: 0 });
var testCube, edge;
for (var x = -offset; x <= offset; x+=step) {
for (var y = -offset; y <= offset; y+=step) {
for (var z = -offset; z <= offset; z+=step) {
testCube = new THREE.Mesh(cubeGeometry,cubeMaterial);
testCube.position.set(x, y, z);
edge = new THREE.EdgesHelper( testCube, 0x000000 );
scene.add(testCube);
scene.add(edge);
}
}
}
// spheres
var sphereGeometry = new THREE.SphereGeometry( 10,32,16),
sphere;
var spheres = [
[0xff0000, 0, 0, 0 ], // red
[0x0000ff, 200, 0, 0 ], // blue
[0x00FF00, -200, 0, 0 ], // green
[0xFF00ff, 0, 200, 0 ], // magenta
[0x00ffff, 0, -200, 0 ], // aqua
[0xFFff00, 0, 0, 200 ], // lime
[0x000000, 0, 0, -200] // black
];
for (var i = 0, sl = spheres.length; i <sl; i++) {
sphere = new THREE.Mesh(sphereGeometry, new THREE.MeshBasicMaterial({color: spheres[i][0]}));
sphere.position.set(spheres[i][1], spheres[i][2], spheres[i][3]);
scene.add(sphere);
}
/* Stats */
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
document.body.appendChild( stats.domElement );
/* window observers */
window.addEventListener( 'resize', onWindowResize, false );
window.addEventListener( 'load', render, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function degInRad(deg) {
return deg * Math.PI / 180;
}
function animate()
{
setTimeout(function() {
requestAnimationFrame(animate);
}, fpsTimeout );
render();
}
function render() {
camera.lookAt(camera.target);
renderer.render( scene, camera );
stats.update();
}
The problem is that you are drawing multiple levels of opacity on top of each other and webgl needs to sort them. So the short answer is to add depthTest: false to your cube material.
var cubeMaterial = new THREE.MeshBasicMaterial({ color:0xFF0000, ambient: 0xCCCCCC, transparent: true, opacity: 0, depthTest: false });
But I would like to mention that what you are doing is inefficient. You should not be drawing a grid that way. Use lines instead.
Related
<!DOCTYPE html>
<html>
<head>
<title>____________glTF2_Loader_________</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="three.js"></script>
<script src="GLTFLoader.js"></script>
<script src="OrbitControls.js"></script>
<script>
// Load 3D Scene
var scene = new THREE.Scene();
// Load Camera Perspektive
var camera = new THREE.PerspectiveCamera( 25, window.innerWidth / window.innerHeight, 1, 20000 );
camera.position.set( 1, 1, 20 );
// 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);
var controls = new THREE.OrbitControls( camera, renderer.domElement );
//load in camera controls
controls.update();
// Load the Orbitcontroller
// Load Light
var ambientLight = new THREE.AmbientLight( 0xcccccc, 2);
// NOTE: More ambience gives an etherial look. :O
scene.add( ambientLight );
var PointLight = new THREE.PointLight( 0xffffff, 3, 100, 2 );
//color (white), intensity (3 times)
PointLight.position.set( 4, -4, 1 ).normalize();
scene.add( PointLight );
// _____ TODO!!!: FADE INTO SCENE. ___________
// glTf 2.0 Loader
var mixer;
var clock = new THREE.Clock();
var loader = new THREE.GLTFLoader();
let obj;
loader.load( './models/ZOMBIIIL12.glb', function ( gltf ) {
// <<--------- Model Path
mixer = new THREE.AnimationMixer(gltf.scene);
obj = gltf.scene;
var action = mixer.clipAction( gltf.animations[ 0 ] );
console.log( action );
gltf.scene.scale.set( .5, .5, .5 );
gltf.scene.position.x = 0; //Position (x = right+ left-)
gltf.scene.position.y = -5; //Position (y = up+, down-)
gltf.scene.position.Z = 5; //Position (z = front +, back-)
gltf.scene.rotation.y = 90; //rotating on the y axis, + is towards the right, - is towards the left.
obj.rotation.y = camera.rotation.y;
var URll = './texture maps/Material Base Color.png';
var textT = THREE.ImageUtils.loadTexture( URll );
var materiall = new THREE.MeshPhongMaterial({
map : textT,
})
gltf.texture = materiall;
scene.add( gltf.scene );
action.play();
});
function animate() {
renderer.render(scene, camera);
requestAnimationFrame( animate );
}
function render() {
renderer.render( scene, camera );
}
var geometry2 = new THREE.PlaneGeometry( 30, 20, 32 );
var url = './texture maps/GREEN LEAVES.png';
var texture = THREE.ImageUtils.loadTexture( url );
var material2 = new THREE.MeshPhongMaterial({
map : texture,
})
var plane = new THREE.Mesh( geometry2, material2 );
plane.position.z = -1;
scene.add( plane );
/*
var xSpeed = .1;
var zSpeed = .1;
document.addEventListener("keydown", onDocumentKeyDown, false);
//while the document is active, listen for this event called keydown, and run function onDocumentKeyPress
x1 = 0;
function onDocumentKeyDown(event) {
var keyCode = event.which;
if (keyCode == 87) {
//obj.rotation.y += .05;
//rotates the model so that you change where it is facing.
obj.translateZ( .5 );
// camera.rotation.y = obj.rotation.y;
camera.translateZ( .5 );
camera.position.y = obj.position.y - 1.9;
// camera.position.y = obj.position.y - 1.9;
//++++++++++++++++++ WWWWWW KEYYYYYYYY (forward)
} else if (keyCode == 83) {
obj.translateZ( -0.5 );
camera.translateZ( -0.5 );
camera.position.y = obj.position.y - 1.9;
console.log(obj.position.y)
//camera.position.set(obj.position.x, camera.position.y, camera.position.z);
//updates z position by the amount of speed.
// obj.rotation.y = 90;
// camera.rotation = 90;
//camera.translateZ( .1 );
//++++++++++++++++++ SSSSSSS KEYYYYYYYY (back)
} else if (keyCode == 65) {
//obj.rotation.y += 90;
obj.translateX( -.5 );
camera.translateX( -.5 );
camera.position.z = obj.position.z + 20;
//++++++++++++++++++ AAAAAAA KEYYYYYYYY (left)
/// If camera rotation on the y is less than or greater than a certain value, then rotate it on the mouse movement, otherwise, nothing.
} else if (keyCode == 68) {
obj.translateX(.5);
camera.translateX(.5);
camera.position.z = obj.position.z + 20;
//++++++++++++++++++ DDDDDD KEYYYYYYYY (rigtht)
} else if (keyCode == 32) {
obj.position.set(0, 0, 0);
// console.log(obj.position.x);
//space bar
}
//camera.rotation.x += 0.05
};
*/
render();
animate();
</script>
</body>
</html>
above code works to load in the model, however, it does not play the animation when called. I get no errors but it still does not work. The console even logs the action animation that is loaded from the glb model showing that it is there. i tried acting as though it is a json, and using json loader animator functions. I tried using clipaction functions, but they only gave me errors saying that they were either undefined, or just would say that there was an error.
You have to update your animation mixer in your animation loop like so:
var delta = clock.getDelta();
if ( mixer ) mixer.update( delta );
Notice that clock is an instance of THREE.Clock. Create it similar to your camera and scene at the top of your file.
three.js R112
I want to rotate this cube around the light blue axis. I works If I change the rotation around THREE.Vector3(0,0,0) instead of THREE.Vector3(0.4,0,0.9)
I don't know why the cubes shape changes and why it gets smaller with more iterations
An fiddle showing this problem (please ignore the crappy implementation. I just changed a old one)
So this is how I do the rotation:
function rotate(deg) {
_initTranslation = new THREE.Vector3();
_initRotation = new THREE.Quaternion();
_initScale = new THREE.Vector3();
rotateMatrix = new THREE.Matrix4();
cube.matrix.decompose(_initTranslation, _initRotation, _initScale);
cube.matrix = rotateMatrix.compose(_initTranslation, new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0.4,1,0.9), THREE.Math.degToRad(deg)), _initScale);
cube.matrixAutoUpdate = false;
cube.matrixWorldNeedsUpdate = true;
}
Maybe someone knows what I did wrong.
var renderer, scene, camera, controls;
var geometry, material, line, vertices, last, _initTranslation, _initRotation, initScale, rotateMatrix;
var deg = 0;
init();
animate();
function init() {
document.body.style.cssText = 'margin: 0; overflow: hidden;' ;
renderer = new THREE.WebGLRenderer( { alpha: 1, antialias: true, clearColor: 0xffffff } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 5, 5, 5 );
controls = new THREE.OrbitControls( camera, renderer.domElement );
geometry2 = new THREE.BoxGeometry( .5, .5, .5 );
material2 = new THREE.MeshNormalMaterial();
cube = new THREE.Mesh( geometry2, material2 );
scene.add( cube );
material = new THREE.LineBasicMaterial({ color: 0x0077ff });
geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3( 0, 0, 0) );
line = new THREE.Line( geometry, material )
scene.add( line );
var sphereAxis = new THREE.AxesHelper(20);
scene.add(sphereAxis);
addStep();
cube.lookAt(new THREE.Vector3(0.4,0,0.9));
}
function addStep() {
vertices = geometry.vertices;
last = vertices[ vertices.length - 1 ];
vertices.push(
new THREE.Vector3(0.4,0,0.9)
);
geometry = new THREE.Geometry();
geometry.vertices = vertices;
scene.remove( line );
line = new THREE.Line( geometry, material )
scene.add( line );
}
function animate() {
rotate(deg)
deg += 5
requestAnimationFrame( animate );
renderer.render(scene, camera);
controls.update();
}
function rotate(deg) {
_initTranslation = new THREE.Vector3();
_initRotation = new THREE.Quaternion();
_initScale = new THREE.Vector3();
rotateMatrix = new THREE.Matrix4();
cube.matrix.decompose(_initTranslation, _initRotation, _initScale);
cube.matrix = rotateMatrix.compose(_initTranslation, new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0.4,0,0.9), THREE.Math.degToRad(deg)), _initScale);
cube.matrixAutoUpdate = false;
cube.matrixWorldNeedsUpdate = true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
The vector component of the Quaternion has to be (normalize.). The length of a normalized vector (Unit vector) is 1.0.
In your case the length of the vector component (THREE.Vector3(0.4, 0, 0.9)) is less than 1.0:
sqrt(0.9*0.9 + 0.0*0.0 + 0.4*0.4) = sqrt(0.81 + 0.16) = sqrt(0.97) = 0.9409
This causes that the cube scales sown by time. This can be verified by logging the scaling component (console.log(_initScale)).
If you would use a vector component with a length greater than 1.0 (e.g. THREE.Vector3(0.5, 0, 0.9), then the cube will scale up.
Normalize the axis of the Quaternion, to solve the issue:
let axis = new THREE.Vector3(0.4, 0, 0.9);
let q = new THREE.Quaternion().setFromAxisAngle(axis.normalize(), THREE.Math.degToRad(deg));
cube.matrix = rotateMatrix.compose(_initTranslation, q, _initScale);
If you want that one side of the cube is aligned to the axis, in that way, that the axis is normal to the side, then this is something completely different.
You've to do 2 rotations. First rotate the cube (e.g.) continuously around the x-axis, then turn the x-axis to the target axis (0.4, 0, 0.9). Use .setFromAxisAngle` to initialize a quaternion which rotates the x-axis to the target axis:
let x_axis = new THREE.Vector3(1, 0, 0);
let axis = new THREE.Vector3(0.4, 0, 0.9);
let q_align = new THREE.Quaternion().setFromUnitVectors(x_axis, axis.normalize());
let q_rotate = new THREE.Quaternion().setFromAxisAngle(x_axis, THREE.Math.degToRad(deg));
let q_final = q_align.clone().multiply(q_rotate);
cube.matrix = rotateMatrix.compose(_initTranslation, q, _initScale);
See the example, which compares the 2 different behavior:
var renderer, scene, camera, controls;
var geometry, material, line, vertices, last, _initTranslation, _initRotation, initScale, rotateMatrix;
var deg = 0;
init();
animate();
function init() {
document.body.style.cssText = 'margin: 0; overflow: hidden;' ;
renderer = new THREE.WebGLRenderer( { alpha: 1, antialias: true, clearColor: 0xffffff } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 1, 3, 3 );
controls = new THREE.OrbitControls( camera, renderer.domElement );
geometry2 = new THREE.BoxGeometry( .5, .5, .5 );
material2 = new THREE.MeshNormalMaterial();
let shift = 0.5
cube = new THREE.Mesh( geometry2, material2 );
cube.matrix.makeTranslation(shift, 0, 0);
scene.add( cube );
cube2 = new THREE.Mesh( geometry2, material2 );
cube2.matrix.makeTranslation(-shift, 0, 0);
scene.add( cube2 );
material = new THREE.LineBasicMaterial({ color: 0x0077ff });
geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3(-0.4, 0, -0.9), new THREE.Vector3(0.4, 0, 0.9) );
line = new THREE.Line( geometry, material )
line.position.set(shift, 0, 0);
scene.add( line );
line2 = new THREE.Line( geometry, material )
line2.position.set(-shift, 0, 0);
scene.add( line2 );
var sphereAxis = new THREE.AxesHelper(20);
scene.add(sphereAxis);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
}
function animate() {
rotate(deg)
deg += 5
requestAnimationFrame( animate );
renderer.render(scene, camera);
controls.update();
}
function rotate(deg) {
_initTranslation = new THREE.Vector3();
_initRotation = new THREE.Quaternion();
_initScale = new THREE.Vector3();
let x_axis = new THREE.Vector3(1, 0, 0);
let axis = new THREE.Vector3(0.4, 0, 0.9);
// cube
cube.matrix.decompose(_initTranslation, _initRotation, _initScale);
let q_align = new THREE.Quaternion().setFromUnitVectors(x_axis, axis.normalize());
let q_rotate = new THREE.Quaternion().setFromAxisAngle(x_axis, THREE.Math.degToRad(deg));
let q_final = q_align.clone().multiply(q_rotate);
cube.matrix.compose(_initTranslation, q_final, _initScale);
cube.matrixAutoUpdate = false;
cube.matrixWorldNeedsUpdate = true;
// cube2
cube2.matrix.decompose(_initTranslation, _initRotation, _initScale);
q = new THREE.Quaternion().setFromAxisAngle(axis.normalize(), THREE.Math.degToRad(deg));
cube2.matrix.compose(_initTranslation, q, _initScale);
cube2.matrixAutoUpdate = false;
cube2.matrixWorldNeedsUpdate = true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
I made a TubeGeometry by passing in a SplineCurve3 / CatmullRomCurve3 path as a parameter.
I am trying to update the position of each of the path's points with geometry.parameters.path.points[1].y += 0.01; under requestAnimationFrame.
The values itself updates on console.log but the points dont move. How can i do this?
By the way, i'm not looking to move 'vertices' but rather the points of the path that shape how the tube is rendered.
var camera, scene, light, renderer, geometry, material, mesh;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// default bg canvas color //
renderer.setClearColor(0x00ff00);
// use device aspect ratio //
// renderer.setPixelRatio(window.devicePixelRatio);
// set size of canvas within window //
renderer.setSize(window.innerWidth, window.innerHeight);
// create camera //
// params = field of view, aspect ratio, clipping of near objects, clipping of far objs
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 3000);
camera.position.z = 100;
// create scene
scene = new THREE.Scene();
// create ambient lighting, params -> color, intensity
light = new THREE.AmbientLight(0xffffff, 0.5)
// add light to scene
scene.add(light)
// create line, with params as x,y,z
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3( -60, 0, 0 ),
new THREE.Vector3( -50, 10, 0 ),
new THREE.Vector3( -40, 0, 0 ),
new THREE.Vector3( -30, -10, 0 ),
new THREE.Vector3( -20, 0, 0 ),
new THREE.Vector3( -10, 10, 0 ),
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( 10, -10, 0 ),
new THREE.Vector3( 20, 0, 0 ),
new THREE.Vector3( 30, 10, 0 ),
new THREE.Vector3( 40, 0, 0 ),
new THREE.Vector3( 50, -10, 0 ),
new THREE.Vector3( 60, 0, 0 )
]);
curve.verticesNeedUpdate = true;
for (i = 0; i < curve.points.length; i++) {
// this will get a number between 1 and 10;
var num = Math.floor(Math.random()*10) + 1;
num *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
curve.points[i].y = num;
// console.log(curve.points[i].y);
}
geometry = new THREE.TubeGeometry(curve, 1000, 0.2, 8, false);
geometry.dynamic = true;
/* standard material */
material = new THREE.MeshBasicMaterial({
color: 0xff0000
});
// create mesh
mesh = new THREE.Mesh(geometry, material);
// set positon of line
mesh.position.set(0,0,-10);
// add to scene
scene.add(mesh);
document.body.appendChild(renderer.domElement);
} /* end init */
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//console.log(geometry.parameters.path.points);
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
// mesh.rotation.x += 0.01;
// mesh.rotation.y += 0.01;
geometry.parameters.path.points[1].y += 0.01;
geometry.verticesNeedUpdate = true;
//console.log(geometry.parameters.path.points[1].y)
/* render scene and camera */
renderer.render(scene,camera);
}
body {
margin:0;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
I wasn't able to get it working using TubeGeometry, but I did with TubeBufferGeometry. Luckily, there isn't much to change, because both use the curve path to define the mesh vertices. You're free to try to replicate this with TubeGeometry instead.
The main problem you're seeing though is that Tube(Buffer)Geometry BUILDS geometry, rather than IS geometry, and that's where the convenience ends. Updating the path does not trigger the geometry to rebuild. Instead, if you update your path, you must recreate the Tube(Buffer)Geometry.
In the code below, all I did was swap TubeBufferGeometry in place of TubeGeometry, changed geometry.verticesNeedUpdated to geometry.needsUpdate (this is how BufferGeometry handles updates), and added the line which re-builds the tube:
geometry.copy(new THREE.TubeBufferGeometry(geometry.parameters.path, 1000, 0.2, 8, false));
var camera, scene, light, renderer, geometry, material, mesh;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// default bg canvas color //
renderer.setClearColor(0x00ff00);
// use device aspect ratio //
// renderer.setPixelRatio(window.devicePixelRatio);
// set size of canvas within window //
renderer.setSize(window.innerWidth, window.innerHeight);
// create camera //
// params = field of view, aspect ratio, clipping of near objects, clipping of far objs
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 0.1, 3000);
camera.position.z = 100;
// create scene
scene = new THREE.Scene();
// create ambient lighting, params -> color, intensity
light = new THREE.AmbientLight(0xffffff, 0.5)
// add light to scene
scene.add(light)
// create line, with params as x,y,z
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3( -60, 0, 0 ),
new THREE.Vector3( -50, 10, 0 ),
new THREE.Vector3( -40, 0, 0 ),
new THREE.Vector3( -30, -10, 0 ),
new THREE.Vector3( -20, 0, 0 ),
new THREE.Vector3( -10, 10, 0 ),
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( 10, -10, 0 ),
new THREE.Vector3( 20, 0, 0 ),
new THREE.Vector3( 30, 10, 0 ),
new THREE.Vector3( 40, 0, 0 ),
new THREE.Vector3( 50, -10, 0 ),
new THREE.Vector3( 60, 0, 0 )
]);
curve.verticesNeedUpdate = true;
for (i = 0; i < curve.points.length; i++) {
// this will get a number between 1 and 10;
var num = Math.floor(Math.random()*10) + 1;
num *= Math.floor(Math.random()*2) == 1 ? 1 : -1;
curve.points[i].y = num;
// console.log(curve.points[i].y);
}
geometry = new THREE.TubeBufferGeometry(curve, 1000, 0.2, 8, false);
geometry.dynamic = true;
/* standard material */
material = new THREE.MeshBasicMaterial({
color: 0xff0000
});
// create mesh
mesh = new THREE.Mesh(geometry, material);
// set positon of line
mesh.position.set(0,0,-10);
// add to scene
scene.add(mesh);
document.body.appendChild(renderer.domElement);
} /* end init */
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//console.log(geometry.parameters.path.points);
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
// mesh.rotation.x += 0.01;
// mesh.rotation.y += 0.01;
geometry.parameters.path.points[3].y += 0.01;
geometry.copy(new THREE.TubeBufferGeometry(geometry.parameters.path, 1000, 0.2, 8, false));
geometry.needsUpdate = true;
//console.log(geometry.parameters.path.points[1].y)
/* render scene and camera */
renderer.render(scene,camera);
}
body {
margin:0;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
Hi I have been playing with render targets but I ran into some problems. I created a simplified example here:
init = function() {
// RENDERER
canvas = document.getElementById("mycanvas");
renderer = new THREE.WebGLRenderer({
antialias: true
});
document.body.appendChild( renderer.domElement );
renderer.setClearColor(0x000000, 1.0);
renderer.setSize(window.innerWidth, window.innerHeight);
// SCENE
texscene = new THREE.Scene();
texcamera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
texcamera.position.z = 2;
// FRAMEBUFFER
var renderTargetParams = {
minFilter:THREE.LinearFilter,
stencilBuffer:false,
depthBuffer:false,
wrapS: THREE.RepeatWrapping,
wrapT: THREE.RepeatWrapping
};
rendertarget = new THREE.WebGLRenderTarget( 512, 512, renderTargetParams );
// CUBE
var cubeGeo = new THREE.BoxGeometry( 1, 1, 1, 1, 1, 1 );
var cubeMat = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
texcube = new THREE.Mesh( cubeGeo, cubeMat )
texscene.add(texcube);
var blueMaterial = new THREE.MeshBasicMaterial({color:0x7074FF})
var plane = new THREE.PlaneBufferGeometry( 100, 100 );
var planeObject = new THREE.Mesh(plane,blueMaterial);
planeObject.position.z = -15;
texscene.add(planeObject);
/////////////////////////////////
//SCENE
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
var boxMaterial = new THREE.MeshBasicMaterial({map:rendertarget.texture});
var boxGeometry2 = new THREE.BoxGeometry( 5, 5, 5 );
mainBoxObject = new THREE.Mesh(boxGeometry2,boxMaterial);
// Move it back so we can see it
mainBoxObject.position.z = -10;
// Add it to the main scene
scene.add(mainBoxObject);
animate();
}
animate = function() {
requestAnimationFrame(animate);
renderer.render(texscene, texcamera, rendertarget);
renderer.render(scene, camera);
texcube.rotation.y += 0.01;
texcube.rotation.z += 0.01;
mainBoxObject.rotation.x +=0.01;
mainBoxObject.rotation.y += 0.005;
mainBoxObject.rotation.z += 0.008;
}
init();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.js"></script>
I render a red cube and a blue plane to a render target then use it as a texture. Problem is the red cube is not visible in the final result.
Try for yourself to see the render target scene by changing
renderer.render(texscene, texcamera, rendertarget);
renderer.render(scene, camera);
to
renderer.render(texscene, texcamera);
Apparantly the problem is caused by turning off the depth buffer as I had done in the settings of my rendertarget
depthBuffer:false,
Removing this line makes my rendertarget render as it should with a red box on a blue background
Here is a sample code of my page. I want to get name of object, when user clicks it. And it works well with cube or sphere, but fails with polygon.
You may watch console logs to see clicks responds.
What should I do to get polygon name on click?
<html>
<head>
<title>Моё 3</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<div id="ThreeJS" style="position: absolute; left:0px; top:0px"></div>
<script src="http://stemkoski.github.io/Three.js/js/Three.js"></script>
<script src="http://stemkoski.github.io/Three.js/js/Detector.js"></script>
<script src="http://stemkoski.github.io/Three.js/js/Stats.js"></script>
<script src="http://stemkoski.github.io/Three.js/js/OrbitControls.js"></script>
<script src="http://stemkoski.github.io/Three.js/js/THREEx.KeyboardState.js"></script>
<script src="http://stemkoski.github.io/Three.js/js/THREEx.FullScreen.js"></script>
<script src="http://stemkoski.github.io/Three.js/js/THREEx.WindowResize.js"></script>
<script>
/*
Three.js "tutorials by example"
Author: Lee Stemkoski
Date: July 2013 (three.js v59dev)
*/
// MAIN
var polyhedronShape, polyhedronPts = [], cube, mesh;
// standard global variables
var container, scene, camera, renderer, controls, stats;
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();
// custom global variables
var targetList = [];
var projector, mouse = { x: 0, y: 0 };
init();
animate();
// FUNCTIONS
function init()
{
// SCENE
scene = new THREE.Scene();
// CAMERA
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(0,150,400);
camera.lookAt(scene.position);
// RENDERER
if ( Detector.webgl )
renderer = new THREE.WebGLRenderer( {antialias:true} );
else
renderer = new THREE.CanvasRenderer();
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
container = document.getElementById( 'ThreeJS' );
container.appendChild( renderer.domElement );
// EVENTS
THREEx.WindowResize(renderer, camera);
THREEx.FullScreen.bindKey({ charCode : 'm'.charCodeAt(0) });
// CONTROLS
controls = new THREE.OrbitControls( camera, renderer.domElement );
// STATS
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.bottom = '0px';
stats.domElement.style.zIndex = 100;
container.appendChild( stats.domElement );
// LIGHT
var light = new THREE.PointLight(0xffffff);
light.position.set(0,250,0);
scene.add(light);
// FLOOR
var floorTexture = new THREE.ImageUtils.loadTexture( 'images/checkerboard.jpg' );
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set( 10, 10 );
var floorMaterial = new THREE.MeshBasicMaterial( { map: floorTexture, side: THREE.DoubleSide } );
var floorGeometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.position.y = -0.5;
floor.rotation.x = Math.PI / 2;
scene.add(floor);
// SKYBOX/FOG
var skyBoxGeometry = new THREE.CubeGeometry( 10000, 10000, 10000 );
var skyBoxMaterial = new THREE.MeshBasicMaterial( { color: 0x9999ff, side: THREE.BackSide } );
var skyBox = new THREE.Mesh( skyBoxGeometry, skyBoxMaterial );
scene.add(skyBox);
////////////
// CUSTOM //
////////////
//////////////////////////////////////////////////////////////////////
// this material causes a mesh to use colors assigned to faces
var faceColorMaterial = new THREE.MeshBasicMaterial(
{ color: 0xffffff, vertexColors: THREE.FaceColors } );
var sphereGeometry = new THREE.SphereGeometry( 80, 32, 16 );
for ( var i = 0; i < sphereGeometry.faces.length; i++ )
{
face = sphereGeometry.faces[ i ];
face.color.setRGB( 0, 0, 0.8 * Math.random() + 0.2 );
}
var sphere = new THREE.Mesh( sphereGeometry, faceColorMaterial );
sphere.name = "Sphere";
sphere.title = "Magic sphere";
sphere.position.set(0, 50, 0);
scene.add(sphere);
targetList.push(sphere);
// Create an array of materials to be used in a cube, one for each side
var cubeMaterialArray = [];
// order to add materials: x+,x-,y+,y-,z+,z-
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0xff3333 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0xff8800 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0xffff33 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0x33ff33 } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0x3333ff } ) );
cubeMaterialArray.push( new THREE.MeshBasicMaterial( { color: 0x8833ff } ) );
var cubeMaterials = new THREE.MeshFaceMaterial( cubeMaterialArray );
// Cube parameters: width (x), height (y), depth (z),
// (optional) segments along x, segments along y, segments along z
var cubeGeometry = new THREE.CubeGeometry( 100, 100, 100, 1, 1, 1 );
// using THREE.MeshFaceMaterial() in the constructor below
// causes the mesh to use the materials stored in the geometry
cube = new THREE.Mesh( cubeGeometry, cubeMaterials );
cube.name = "Cube";
cube.title = "Cube to do";
cube.position.set(-100, 50, -50);
scene.add( cube );
targetList.push(cube);
// polyhedron
polyhedronPts.push( new THREE.Vector2 ( -100, 600 ) );
polyhedronPts.push( new THREE.Vector2 ( 300, 600 ) );
polyhedronPts.push( new THREE.Vector2 ( 600, -100 ) );
polyhedronShape = new THREE.Shape( polyhedronPts );
var extrudeSettings = {amount: 20}; // bevelSegments: 2, steps: 2 , bevelSegments: 5, bevelSize: 8, bevelThickness:5
var geometry = new THREE.ExtrudeGeometry( polyhedronShape, extrudeSettings );
polyhedron = THREE.SceneUtils.createMultiMaterialObject( geometry, [ new THREE.MeshBasicMaterial( { color: 0x00cc00 } ), new THREE.MeshBasicMaterial( { color: 0xff3333, wireframe: true, transparent: true } ) ] );
//geometry.computeVertexNormals();
polyhedron.name = "Polyhedron";
polyhedron.title = "Polyhedron is nice";
polyhedron.position.set( 0, -333, 0 );
//polyhedron.rotation.set( 0, 0, 100 );
//polyhedron.scale.set( 1, 1, 1 );
scene.add(polyhedron);
targetList.push(polyhedron);
//////////////////////////////////////////////////////////////////////
// initialize object to perform world/screen calculations
projector = new THREE.Projector();
// when the mouse moves, call the given function
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
}
function onDocumentMouseDown( event )
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
// event.preventDefault();
//console.log("Click.");
// update the mouse variable
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
// find intersections
// create a Ray with origin at the mouse position
// and direction into the scene (camera direction)
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
// create an array containing all objects in the scene with which the ray intersects
var intersects = ray.intersectObjects( targetList, true );
// if there is one (or more) intersections
if ( intersects.length > 0 )
{
console.log(intersects[0]);
//console.log("Hit # " + toString( intersects[0].point ) );
console.log("Hit # " + intersects[0].object.name);
// change the color of the closest face.
intersects[ 0 ].face.color.setRGB( 0.8 * Math.random() + 0.2, 0, 0 );
intersects[ 0 ].object.geometry.colorsNeedUpdate = true;
}
}
function toString(v) { return "[ " + v.x + ", " + v.y + ", " + v.z + " ]"; }
function animate()
{
requestAnimationFrame( animate );
render();
update();
}
function update()
{
if ( keyboard.pressed("z") )
{
// do something
}
controls.update();
stats.update();
}
function render()
{
renderer.render( scene, camera );
}
</script>
</body>
</html>
The call to THREE.SceneUtils.createMultiMaterialObject() (to create your polyhedron) returns a THREE.Object3D where the call to THREE.Mesh() (to create your sphere and cube) returns a THREE.Mesh. So they are different entities but you treat them the same. If instead you call:
polyhedron = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0x00cc00 } ) );
then you can get the name of your polyhedron, since now polyhedron is of type THREE.Mesh()
Otherwise you would have to parse the children of the polyhedron (since it is a THREE.Object3D())