I'd like to render a mesh on top of everything else, this solution works fine:
Three.js - Geometry on top of another
I was wondering if the same could be achievable with mesh.renderDepth, but I couldn't make it work so far. Seems like renderDepth only has an effect if material.depthTest or depthWrite is set to false, but then depth ordering is of course wrong within the same object:
http://jsfiddle.net/SF9tX/22/
var cube = new THREE.Mesh(geometry, material);
cube.renderDepth = 1;
scene.add(cube);
var cube2 = new THREE.Mesh(geometry, material);
cube2.position.x = 1;
cube2.renderDepth = 2;
scene.add(cube2);
// with any one of these lines the renderDepth has an effect
// but then of course the depth test/write is wrong within the same object
// material.depthWrite = false;
// material.depthTest = false;
For r70 is renderDept function removed.
https://github.com/mrdoob/three.js/issues/5496
Related
var lineGeometry = new THREE.Geometry();
var lineMaterial = new THREE.LineBasicMaterial({
color: 0x000000
});
lineGeometry.vertices.push(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 10, 0),
);
var line = new THREE.Line(lineGeometry, lineMaterial);
scene.add(line);
I want to update this line's endpoint in a circular fashion. In other languages it is straightforward, I would increase some variable and update the endpoint like radius * cos(dt) and radius * sin(dt). In three.js I tried the following, but it doesn't work:
var dt = 0;
function render(){
dt += 0.01;
line.geometry.vertices[1].x = 10*Math.cos(dt);
line.geometry.vertices[1].z = 10*Math.sin(dt);
renderer.render(scene, camera);
requestAnimationFrame(render);
}
edit: I don't want to use line.rotation.z += 0.01 method.
line.geometry.verticesNeedUpdate = true;
Add the above line before calling render. This will signal three.js that the vertex buffer has changed, so it will update it appropriately.
Since you mentioned using line.rotation, I must mention that updating the vertices is inefficient compared to rotating the line shape. When you rotate a line shape, you are simply updating the shape's transformation matrix. But when you update vertices, three.js needs to re-upload the entire set of vertices to the GPU. This may seem trivial for a single line segment, but it's a bad habit to get into if you ever intend to use larger shapes later.
I am trying to make a series of cubes that can be clicked to highlight them. This will enable me to change their color or add a texture or manipulate them in some way. I have looked through the source code of all the interactive examples at https://threejs.org/examples/ and it appears that each example uses a slightly different way of creating and selecting objects in the scene. I am not used to using javascript though, so maybe I'm missing something simple.
I create an Object3D class named blocks to store all of the cubes
blocks = new THREE.Object3D()
I am using a for loop to create a 9 x 9 array of cubes starting at (0,0,0) coordinates with a slight gap between them, and add() them to blocks and add() blocks to the scene. example: (cube size 2,2,2)
function stack(mx,my,mz){
for (var i = 0; i < 9; i++){
line(mx,my,mz);
mz += 3;
}
}
function line(mx,my,mz){
for (var i = 0;i<9;i++){
var block = new THREE.Mesh( Geometry, Material);
block.position.x = mx;
block.position.y = my;
block.position.z = mz;
blocks.add(block);
mx+=3;
}
}
stack(mx,my,mz)
scene.add(blocks)
When I run this code, I can see them rendered. I use raycaster to .intersectObjects() which requires an array of objects. This is where I run into the problem of selecting just one object.
function onDocumentMouseDown(event) {
var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
**var intersects = raycaster.intersectObjects(blocks.children, true);**
if (intersects.length > 0) {
intersects[0].object.material.transparent = true;
other code stuff blah blah blah
{
This will make all children clickable but they have the same .id as the first object created. so if I try to .getObjectById() in order to change something, it doesn't work.
I have tried to generate each element and add them to the scene iteratively instead of creating an object array to hold them and it still has a similar effect. I've tried storing them in a regular array and then using true parameter to recursively search the .intersectObject() array but it selects all of the objects when I click on it.
var intersects = raycaster.intersectObjects(blocks, true);
I have considered creating 81 unique variables to hold each element and statically typing an array of 81 variables (desperate option) but I can't find a secure way to dynamically create variable names in the for loop to hold the objects. This way was posted on stackoverflow as a solution to creating different named variables but it doesn't seem to create variables at all.
for (var i=0, i<9, i++){
var window["cube" + i] = new THREE.Mesh( Geometry, Material)
{
Main Question: How can I iteratively create multiple Mesh's (enough that statically typing each variable would be ill-advised) in a controllable way that I can select them and manipulate them individually and not as a group?
I think the reason why you met this problem is you reference same Material to build your Mesh, you did intersect a single object in blocks.children, but when you change some properties of the material others mesh who use the material would change too.
function line(mx,my,mz){
for (var i = 0;i<9;i++){
material = new THREE.MeshLambertMaterial({color: 0xffffff});
var block = new THREE.Mesh( Geometry, material);
block.position.x = mx;
block.position.y = my;
block.position.z = mz;
blocks.add(block);
mx+=3;
}
}
it works for me.
I'm trying to draw a line between two moving vertices. The vertex's drawing is stored in a variable called object, which has a position, which is a THREE.Vector3.
The line is created thusly:
var Line = function(scene, source, target){
var geometry = new THREE.Geometry();
geometry.dynamic = true;
geometry.vertices.push(source.object.position);
geometry.vertices.push(target.object.position);
geometry.verticesNeedUpdate = true;
var material = new THREE.LineBasicMaterial({ color: 0x000000 });
var line = new THREE.Line( geometry, material );
scene.add(line);
return line;
};
..., where source and target are vertices and the vertices get updated via:
vertex.object.position.add(vertex.velocity);
Now, I assigned the source.object.position and target.object.position to the line.geometry.vertices[0] and line.geometry.vertices[1] because I wanted one to update with the other. But instead, the vertex positions vary wildly from the line positions. The vertices are where they are, but the lines don't connect to the vertices.
How can I make the lines move with the vertices?
In your animation loop you have to set line.geometry.verticesNeedUpdate = true. Because every time after rendering it becomes false. jsfiddle example
I'm working on a project where i would like to have objects floating around a webpage,
you can see the progress here.
I'm now using a 2d plane to float the objects around, it's the same size as the div behind it and i've set the plane's opacity to 0.
This creates the desired effect but there is one problem occurring. The objects float around the div and become invisible when behind the plane, that's good. The renderer is transparent renderer = new THREE.WebGLRenderer({alpha: true}); so i can see the DOM underneath, that's good to. But the transparent plane that hides the floating objects adds a white color to the DOM. This only happens to DOM elements behind the plane. When dom behind the canvas is not behind the plane the proper colors are shown.
This is the code to create the plane:
var plane = new THREE.Mesh(new THREE.PlaneGeometry(160, 400), new THREE.MeshNormalMaterial());
plane.overdraw = true;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = -100;
plane.material.opacity = 0;
edit:
The problem was caused by the material type. By using a THREE.MeshBasicMaterial() instead of a THREE.MeshNormalMaterial() and adding a color to the material plane.material.color = '0xffffff' the problem got solved! The final code to create the plane looks like this:
var plane = new THREE.Mesh(new THREE.PlaneGeometry(160, 400), new THREE.MeshBasicMaterial());
plane.overdraw = true;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = -100;
plane.material.color = '0xffffff';
plane.material.opacity = 0;
Hope this helps people facing the same problem.
I am currently using a matrix to mirror my Collada models.
I have posted this question before: Flip Normals Three.JS after flipping geometry
and referenced this one: ThreeJS geometry flipping
The problem is that I can't flip the geometry before adding it to a mesh to avoid the inverted material, since it is a Collada model, which already contains the mesh.
What would be the best way to go about mirroring a Collada model while maintaining its material?
I thought I could do the following, but I didn't know how to target the materials properly to change them (my new geometry does not have a new material applied to it). Also my models are fairly complex and contain a lot of hierarchies. The result is the flipped Collada model, with an inside out material.
var mS = (new THREE.Matrix4()).identity();
var newGroup = new THREE.Object3D();
var newMesh;
mS.elements[5] = -1;
mesh.traverse(function(child){
if (child.geometry!==undefined) {
if (child instanceof THREE.Mesh) {
child.geometry.applyMatrix(mS);
child.geometry.verticesNeedUpdate = true;
child.geometry.normalsNeedUpdate = true;
child.geometry.computeVertexNormals();
child.geometry.computeBoundingSphere();
child.geometry.computeFaceNormals();
child.geometry.computeVertexNormals();
if (child.material.materials!=undefined) {
for (var i; i<child.material.materials.length; i++) {
child.material.materials[i]=newMaterial;
child.material.materials[i].wrapAround = true;
child.material.materials[i].side = THREE.DoubleSide;
}
}
var geom = child.geometry.clone();
newMesh = new THREE.Mesh(geom, child.material);
newMaterial.needsUpdate = true;
newGroup.add( newMesh );
};
};
});
return newGroup;
Thanks!
UPDATE
I had a typo in my code. Everything works.
var i;
should be
var i=0;