Three js: How to get normal of rotated plane - three.js

I am trying to get normal of rotated plane. My solution is to copy the updated plane then get normals.
It is working when I rotate by only 1 angle, but not works in rotating by 2 or 3 angles. jsFiddle
Green one is copied plane, purple one rotated plane.
enter image description here
How to solve this? Please help me
My copy function:
function copyPlane() {
let copyPlaneGeom = new THREE.PlaneGeometry(3, 3, 3);
copyPlaneGeom.rotateX(plane.rotation.x);
copyPlaneGeom.rotateY(plane.rotation.y);
copyPlaneGeom.rotateZ(plane.rotation.z);
let copyPlane = new THREE.Mesh(copyPlaneGeom, new THREE.MeshBasicMaterial({color: 0x00ff00}));
scene.add(copyPlane)
let normals = copyPlane.geometry.faces[0].normal

I think with that approach, you'll always get a vector of 0, 0, 1 because a plane's face normal is always (0, 0, 1) * objectRotation.
Instead, try starting with a Vector3 of 0, 0, 1, and then apply the object's rotation to it:
var originalNormal = new Vector3(0, 0, 1);
// Get the mesh rotation
var objRotation = plane.rotation;
// Apply mesh rotation to vector
originalNormal.applyEuler(objRotation);
now you have a Vector3 with the updated wold normal, instead of the local normal! Read about .applyEuler() here.

Related

Three.js InsatncedMesh rotation on each instance does not change

I am using instancedmesh to show tons of objects on scene.
How can I translate the rotation of each instance likes correct rectangle shape.Current condition is all of the instances are bending to the left side, I want to get red rectangle like below image.
Please check the image link: https://i.stack.imgur.com/jpAhb.png
I tried to set the Eucler and Quaternion on following code but not reflected.
var dummy = new THREE.Object3D();
let finalMatrix = new THREE.Matrix4();
child.geometry.computeBoundingBox();
let matrix = new THREE.Vector3();
let offset = child.geometry.boundingBox.getCenter(matrix);
finalMatrix.makeTranslation(-offset.x, -offset.y, -offset.z);
child.geometry.applyMatrix4(finalMatrix);
dummy.position.copy(offset);
dummy.updateMatrix();
INSTANCEMESH.setMatrixAt(i, dummy.matrix);
INSTANCEMESH.setColorAt(i, child.material.color);
Quaternion
{
"_x": 0,
"_y": 0,
"_z": 0,
"_w": 1
}
Eucler
{
"_x": 0,
"_y": 0,
"_z": 0,
"_order": "XYZ"
}
Do you know how to solve this problem?
Thanks.

Three js: How to normalize a mesh generated by vertices

I'm somewhat new to Three js, and my linear algebra days were back in the 90s so I don't recall much about quarternions. My issue is I have 8 vertices for a cube that I can use to create a custom geometry mesh from, but it doesn't set the position / rotation / scale info for its world matrix. Therefor it can not be used cleanly by other three js modules like controls. I can look up the math and calculate what position / scale / rotation (rotation gets a bit hairy with some fun acos stuff) should be and create a standard boxgeometry from that. But it seems like there should be some way to do it via three js objects if I can generate the proper matrix to apply to it. The quarternion setFromUnitVectors looked interesting, but I'd still have to do some work to generate the vectors. Any ideas would be appreciated thanks
Edit: :) So let me try and simplify. I have 8 vertices, I want to create a box geometry. But box geometry doesn't take vertices. It takes width, height, depth (relatively easy to calculate) and then you set the position/scale/rotation. So here's my code thus far:
5____4
1/___0/|
| 6__|_7
2/___3/
const box = new Box3();
box.setFromPoints(points);
const width = points[1].distanceTo(points[0]);
const height = points[3].distanceTo(points[0]);
const depth = points[4].distanceTo(points[0]);
const geometry = new BoxGeometry(width, height, depth);
mesh = new Mesh(geometry, material);
const center = box.getCenter(new Vector3());
const normalizedCorner = points[0].clone().sub(center);
const quarterian = new Quaternion();
quarterian.setFromUnitVectors(geometry.vertices[0], normalizedCorner);
mesh.setRotationFromQuaternion(quarterian);
mesh.position.copy(center);
The problem being my rotation element is wrong (besides my vectors not being unit vectors). I'm apparently not getting the correct quarternion to rotate my mesh correctly.
Edit: From WestLangley's suggestion, I'm creating a rotation matrix. However, while it rotates in the correct plane, the angle is off. Here's what I have added:
const matrix = new Matrix4();
const widthVector = new Vector3().subVectors(points[6], points[7]).normalize();
const heightVector = new Vector3().subVectors(points[6], points[5]).normalize();
const depthVector = new Vector3().subVectors(points[6], points[2]).normalize();
matrix.set(
widthVector.x, heightVector.x, depthVector.x, 0,
widthVector.y, heightVector.y, depthVector.y, 0,
widthVector.z, heightVector.z, depthVector.z, 0,
0, 0, 0, 1,
);
mesh.quaternion.setFromRotationMatrix(matrix);
Per WestLangley's comments I wasn't creating my matrix correctly. The correct matrix looks like:
const matrix = new Matrix4();
const widthVector = new Vector3().subVectors(points[7], points[6]).normalize();
const heightVector = new Vector3().subVectors(points[5], points[6]).normalize();
const depthVector = new Vector3().subVectors(points[2], points[6]).normalize();
matrix.set(
widthVector.x, heightVector.x, depthVector.x, 0,
widthVector.y, heightVector.y, depthVector.y, 0,
widthVector.z, heightVector.z, depthVector.z, 0,
0, 0, 0, 1,
);
mesh.quaternion.setFromRotationMatrix(matrix);

Three.js: Draw a vector on plane

I'm a newbie in three.js (and in stackoverflow).
I try to find answer but I'm not able to do this simple things.
I'm playing with Helpers and Plane.
I want to create a Plane (and it's PlaneHelper), and draw an arbitrary vector on this Plane.
All is right if the plane's distance from origin is set to 0.
If I give a distance to the plane, the vector is not on the plane.
Here is the commented code I use for this little experiment.
Projecting both the origin and the vector on the plane I was convinced that arrowHelper_Point remained on the plane, but it's not.
Where is my mistake? I can not understand it.
// Define ARROW_LENGTH to display ArrowHelper
const ARROW_LENGTH = 5;
// Point (0,0,0)
var origin = new THREE.Vector3(0, 0, 0);
// Axes helper in (0,0,0)
var axesHelperOrigin = new THREE.AxesHelper(100);
scene.add(axesHelperOrigin);
// Define a plane by the normal, color and distance from (0,0,0)
var vectorNormal = {
normal: new THREE.Vector3(1, 1, 0).normalize(),
color: "rgb(255, 255, 0)",
colorNormal: "rgb(255,100,0)",
colorVector: "rgb(194, 27, 255)",
distance: -3,
};
// Create Plane from the normal and distance
var plane = new THREE.Plane(vectorNormal.normal, vectorNormal.distance);
// Add PlaneHelper to scene
var planeHelper = new THREE.PlaneHelper(plane, 100, vectorNormal.color);
scene.add(planeHelper);
// Add ArrowHelper to display normal
// Find the projection of origin on plane
var originOnPlane = plane.projectPoint(origin);
var arrowHelper_Normal = new THREE.ArrowHelper(vectorNormal.normal, originOnPlane, ARROW_LENGTH, vectorNormal.colorNormal);
scene.add(arrowHelper_Normal);
// Define a point "random"
var point = new THREE.Vector3(5, -2, 6);
// Project the point on plane
var pointOnPlane = plane.projectPoint(point);
// Draw ArrowHelper to display the pointOnPlane, from originOnPlane
var arrowHelper_Point = new THREE.ArrowHelper(pointOnPlane.normalize(), originOnPlane, ARROW_LENGTH, vectorNormal.colorVector);
scene.add(arrowHelper_Point);
EDIT: OK, I think I find the error.
Looking at this Get direction between two 3d vectors using Three.js?
I need the vector between the two points:
var dir=new THREE.Vector3();
dir.subVectors(pointOnPlane,originOnPlane).normalize();
And use dir as the arrow direction.
Sorry for asking an obviously thing.
Looking at this Get direction between two 3d vectors using Three.js?
I need the vector between the two points:
var dir=new THREE.Vector3();
dir.subVectors(pointOnPlane,originOnPlane).normalize();
And use dir as the arrow direction.

Orbiting a cube in WebGL with glMatrix

https://jsfiddle.net/sepoto/Ln7qvv7w/2/
I have a base set up to display a cube with different colored faces. What I am trying to do is set up a camera and apply a combined X axis and Y axis rotation so that the cube spins around both axis concurrently. There seems to be some problems with the matrices I set up as I can see the blue face doesn't look quite right. There are some examples of how this is done using older versions of glMatrix however the code in the examples no longer works because of some changes in vec4 of the glMatrix library. Does anyone know how this can be done using the latest version of glMatrix as I have attached a CDN to the fiddle?
Thank you!
function drawScene() {
gl.viewport(0,0,gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.ortho( mOrtho, -5, 5, 5, -5, 2, -200);
mat4.identity(mMove);
var rotMatrix = mat4.create();
mat4.identity(rotMatrix);
rotMatrix = mat4.fromYRotation(rotMatrix, yRot,rotMatrix);
rotMatrix = mat4.fromXRotation(rotMatrix, xRot,rotMatrix);
mat4.multiply(mMove, rotMatrix, mMove);
setMatrixUniforms();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, triangleColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
yRot += 0.01;
xRot += 0.01;
}
As the name says, fromYRotation() initializes a matrix to a given rotation. Hence, you need two temporary matrices for the partial rotations, which you can then combine:
var rotMatrix = mat4.create();
var rotMatrixX = mat4.create();
var rotMatrixY = mat4.create();
mat4.fromYRotation(rotMatrixY, yRot);
mat4.fromXRotation(rotMatrixX, xRot);
mat4.multiply(rotMatrix, rotMatrixY, rotMatrixX);
And the reason why your blue face was behaving strangely, was the missing depth test. Enable it in your initialization method:
gl.enable(gl.DEPTH_TEST);
You dont need to use three matrices:
// you should do allocations outside of the renderloop
var rotMat = mat4.create();
// no need to set the matrix to identity as
// fromYRotation resets rotMats contents anyway
mat4.fromYRotation(rotMat, yRot);
mat4.rotateX(rotMat,xRot);

Is there ANY way to have the three.js camera lookat being rendered off-center?

Is there a way to setup the Three.js renderer in such a way that the lookat point of the camera is not in the center of the rendered image?
To clarify: image a scene with just one 1x1x1m cube at ( 0, 0, 0 ). The camera is located at ( 0, 0, 10 ) and the lookat point is at the origin, coinciding with the center of the cube. If I render this scene as is, I might end up with something like this:
normal render
However I'd like to be able to render this scene in such a way that the lookat point is in the upper left corner, giving me something like this:
desired render
If the normal image is 800x600, then the result I envision would be as if I rendered a 1600x1200 image with the lookat in the center and then cropped that normal image so that only the lower right part remains.
Of course, I can change the lookat to make the cube go to the upper left corner, but then I view the cube under an angle, giving me an undesired result like this:
test.moobels.com/temp/cube_angle.jpg
I could also actually render the full 1600x1200 image and hide 3/4 of the image, but one would hope there is a more elegant solution. Does anybody know it?
If you want your perspective camera to have an off-center view, the pattern you need to use is:
camera = new THREE.PerspectiveCamera( for, aspect, near, far );
camera.setViewOffset( fullWidth, fullHeight, viewX, viewY, viewWidth, viewHeight );
See the docs: https://threejs.org/docs/#api/cameras/PerspectiveCamera
You can find examples of this usage in this example and this example.
three.js r.73
Here's a simple solution:
Assuming your cube is 4 x 4 x 4, at position 0, 0, 0:
var geometry = new THREE.BoxGeometry( 4, 4, 4 );
var material = new THREE.MeshBasicMaterial( { color: 0x777777 } );
var cube = new THREE.Mesh( geometry, material );
cube.position.set( 0, 0, 0 );
Get cube's position:
var Vx = cube.position.x,
Vy = cube.position.y,
Vz = cube.position.z;
Then deduct by 2 from x position, then add 2 to y and z position, and use the values to create a new Vector3:
var newVx = Vx - 2,
newVy = Vy + 2;
newVz = Vz + 2;
var xyz = new THREE.Vector3(newVx, newVy, newVz)
Then camera lookAt:
camera.lookAt(xyz);
Using console log, it would show that the camera is now looking at -2, 2, 2, which is the upper-left of your cube.
console.log(xyz);

Resources