I'm trying to make a simple tree billboard of two crossed planes with a partially transparent texture. The self-transparency only works for one plane, I'm assuming because of depth-sorting problems when geometry intersects.
See here: https://jsfiddle.net/2q5a7fzy/21/
The geometry is fairly simple:
geometry.vertices.push(
new THREE.Vector3( -1, -1, 0 ),
new THREE.Vector3( -1, 1, 0 ),
new THREE.Vector3( 1, 1, 0 ),
new THREE.Vector3( 1, -1, 0 ),
new THREE.Vector3( 0, -1, -1 ),
new THREE.Vector3( 0, 1, -1 ),
new THREE.Vector3( 0, 1, 1 ),
new THREE.Vector3( 0, -1, 1 ) );
geometry.faces.push(
new THREE.Face3( 0, 1, 2 ),
new THREE.Face3( 0, 2, 3 ),
new THREE.Face3( 4, 5, 6 ),
new THREE.Face3( 4, 6, 7 ) );
I don't want to use the PointCloud billboards because I'd like the trees to be upright even when the camera is above them, rather than always camera-facing.
Anyone have a possible workaround? Can I sort the individual polygons before rendering, somehow? Are there other ways to do billboards that rotate on a fixed axis?
If you have overlapping, textured objects with transparent regions, then one solution to artifacts caused by depth sorting is to set the alphaTest property of the object's material:
material.alphaTest = 0.5; // between 0 and 1
updated fiddle: https://jsfiddle.net/c5qbd8rm/
three.js r.71
Related
Just found a uv picture
As follows I created a triangle, three vertices and corresponding uv coordinates
let geometry = new THREE.BufferGeometry();
geometry.setAttribute(
"position",
new THREE.BufferAttribute(
new Float32Array([-1.0, 1.0, 0, -1.0, -1.0, 0, 1.0, 1.0, 0]),
3
)
);
geometry.setAttribute(
"uv",
new THREE.BufferAttribute(new Float32Array([0.0, 1.0, 0, 0, 1.0, 1.0]), 2)
);
let mesh = new THREE.Mesh(
geometry,
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load("/1.png"),
})
);
As shown in the figure below, the vertex order is counterclockwise, so the side shooting from the screen to us is the front.
When I clone a copy and do x-axis scaling -1
let clonedMesh = mesh.clone(true);
scene.add(mesh);
clonedMesh.scale.set(-1, 1, 1);
clonedMesh.position.x = 2;
scene.add(clonedMesh);
The order becomes clockwise as follows, the front should be shot into the screen, and MeshBasicMaterial only renders the front by default, so it stands to reason that the clonedMesh should not be able to see it.
I have the following question.
There is a model, through the setFromObject method I get Box3 (screenshot - http://prntscr.com/12787py). Next, I rotate the model and get a new Box3 (screenshot - http://prntscr.com/12789fy).
Is it possible after rotating the model to get Box3 with the same rotation, as if Box3 was rotating with the model?
Box3 is a mathematical representation of a box. As such, it is represented with only two Vector3 properties (max and min) that represent two opposing corners of the box. The values of these do not represent a box in full 3D space, but rather an axis-aligned box.
It looks like you're using BoundingBoxHelper. This creates a wireframe box that is world-aligned. This means it will compute its shape based on the transformed positions of the geometry vertices, and so it may change shape as your mesh is rotated.
To create a shape-tight wireframe box that rotates with your object, you will need to create one directly from your geometry, and ensure the same transformation is applied to both shapes.
// your shape
const shapeGeo = new BoxGeometry( 10, 10, 10 )
shapeGeo.computeBoundingBox() // <----------- DO THIS BEFORE ADDING IT TO THE SCENE!
const shapeMat = new MeshPhongMaterial( { color: 'red' } )
const shapeMsh = new Mesh( shapeGeo, shapeMat )
// your wireframe
const bboxMin = shapeGeo.boundingBox.min
const bboxMax = shapeGeo.boundingBox.max
const wireGeo = new BufferGeometry()
wireGeo.setAttribute( 'position' , new BufferAttribute( new Float32Array( [
bboxMin.x, bboxMin.y, bboxMin.z,
bboxMin.x, bboxMin.y, bboxMax.z,
bboxMin.x, bboxMax.y, bboxMax.z,
bboxMin.x, bboxMax.y, bboxMin.z,
bboxMax.x, bboxMin.y, bboxMin.z,
bboxMax.x, bboxMin.y, bboxMax.z,
bboxMax.x, bboxMax.y, bboxMax.z,
bboxMax.x, bboxMax.y, bboxMin.z,
] ), 3, false ) )
wireGeo.setIndex( new BufferAttribute( new Uint8Array( [
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7
] ), 1, false ) )
const wireMat = new LineBasicMaterial( { color: 'yellow' } )
const wireBox = new LineSegments( wireGeo, wireMat )
Now, here's where things take what might seem like an odd twist. Once you have your wire box, you can simply add it to your shape, and future changes to your shape will be passed on to your wire box:
scene.add( shapeMsh )
shapeMsh.add( wireBox )
This works because transformations are passed on to children*, and a Mesh is really just an extension of Object3D, so a Mesh can have children just like any other Object3D derivative.
* as long as you don't disable automatic matrix updates
I seem to find only examples to use the raycaster with the camera, but none that just have a raycaster from Point A to Point B.
I have a working raycaster, it retrieves my Helpers, Lines etc. but it seems it does not recognize my sphere.
My first thought was my points are off, so i decided to create a line from my pointA to my pointB with a direction like so:
var pointA = new Vector3( 50, 0, 0 );
var direction = new Vector3( 0, 1, 0 );
direction.normalize();
var distance = 100;
var pointB = new Vector3();
pointB.addVectors ( pointA, direction.multiplyScalar( distance ) );
var geometry = new Geometry();
geometry.vertices.push( pointA );
geometry.vertices.push( pointB );
var material = new LineBasicMaterial( { color : 0xff0000 } );
var line = new Line( geometry, material );
This will show a line from my point (50 0 0) to (50 100 0) right trough my sphere which is at point (50, 50, 0) so my pointA and direction values are correct.
Next i add a raycaster:
To avoid conflicts with any side effects i recreated my points here:
var raycaster = new Raycaster(new Vector3( 50, 0, 0 ), new Vector3( 0, 1, 0 ).normalize());
var intersects = raycaster.intersectObject(target);
console.log(intersects);
Seems pretty straight forward to me, i also tried to use raycaster.intersectObjects(scene.children) but it gives Lines, helpers etc. but not my sphere.
What am i doing wrong? I am surely missing something here.
IMG of the line and the sphere:
What you see is explained in the following github issue:
https://github.com/mrdoob/three.js/issues/11449
The problem is that the ray emitted from THREE.Raycaster does not directly hit a face but its vertex which results in no intersection.
There are several workarounds to solve this issue e.g. slightly shift the geometry or the ray. For your case:
var raycaster = new THREE.Raycaster( new THREE.Vector3( 50, 0, 0 ), new THREE.Vector3( 0, 1, 0.01 ).normalize() );
However, a better solution is to fix the engine and make the test more robust.
Demo: https://jsfiddle.net/kzwmoug2/3/
three.js R106
I have an issue with the position of cubes in my application. When I set them all with the same size they are rendered properly on the same Y position as I defined:
Example:
geometry = new THREE.BoxGeometry(50, 50, 50);
material = new THREE.MeshBasicMaterial({ color: 0xff0000 })
mesh = new THREE.Mesh(geometry, material);
mesh.position.set(100, 0, 400); // I always set y as 0 because I want the cubes to be on the same level like buildings in a city
And I do the same for the next cubes, only changing the X and Z positions.
However, when I create cubes with different sizes, which is my objective, as follows,
geometry = new THREE.BoxGeometry(50, 100, 50);
they appear on a different level in the final visualization on the browser, as shows the image:
https://cloud.githubusercontent.com/assets/3678443/8651664/35574c18-2972-11e5-8c75-2612733ea595.png
Any ideas on how to solve this problem? What am I doing wrong?
BoxGeometry is centered on the origin. There are two solutions to translating the box so it sits on the XZ-plane.
Option 1. Translate the geometry so the bottom face of the box passes through the origin. You do that by translating the geometry up by half its height.
geometry = new THREE.BoxGeometry( 50, 50, 50 );
geometry.translate( 0, 50 / 2, 0 );
mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 100, 0, 400 );
Option 2. Translate the mesh by setting its position.
geometry = new THREE.BoxGeometry( 50, 50, 50 );
mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 100, 50 / 2, 400 );
The first option is likely preferable for your use case.
three.js r.92
The Position of the Objects is correct, they are placed where their centerĀ“s are. So your cube with 100 height in geometry extends 50 to the top and 50 to the bottom, its centroid is right in its "middle" at 0.
You could set the y positions of your Cubes to y + cube.geometry.parameters.height / 2 so every cube is aligned at one level (variable y).
From a model file object definition the placement a new object is given by a location (a point in space) and the normalized directions of the X-Axis, the Y-Axis and the Z-Axis.
How can i translate this to a THREE.Euler so i can rotate my object correctly in space.
So the axes are off type THREE.Vector3.
If the new object is aligned with the world the values would be:
xAxis = new THREE.Vector3( 1, 0, 0 );
yAxis = new THREE.Vector3( 0, 1, 0 );
zAxis = new THREE.Vector3( 0, 0, 1 );
But if for example the whole local UCS of the object is rotated 180 degrees ( or Math.PI ) around the zAxis they would look like this:
xAxis = new THREE.Vector3( -1, 0, 0 );
yAxis = new THREE.Vector3( 0, -1, 0 );
zAxis = new THREE.Vector3( 0, 0, 1 );
So I need to do something like this:
var object3D = new THREE.Object3D();
object3D.position = location;
var euler = new THREE.Euler();
euler.setFromNormalizedAxes( xAxis, yAxis, zAxis );
object3D.rotation = euler;
Or create a rotation matrix from those axes:
var rotationMatrix = new THREE.Matrix4();
rotationMatrix.setFromNormalizedAxes( xAxis, yAxis, zAxis );
object3D.rotation.setFromRotationMatrix( rotationMatrix, "XYZ" );
I am not so good yet with these rotation matrices and euler rotations...
In the example you gave, the answer would be
object.quaternion.setFromRotationMatrix(
new THREE.Matrix4( -1, 0, 0, 0,
0, -1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 )
);
The columns of the upper 3x3 of the Matrix4 are the new x-, y-, and z-axes.
You could set object.rotation instead. It does not matter.
three.js r.66