Local clipping of planes based on local axis - three.js

I was trying to clip left half of a planeBuffer using material.clippingPlanes.
When the object is at center with rotation (0,0,0) then the clipping works.
object.material.clippingPlanes =
[object.getWorldDirection().cross(object.up).normalize(), object.position.z )];
But this code fails when the object is at a non-zero position with non-zero rotation and the cut does not change with orientation of object.

From Material.clippingPlanes:
User-defined clipping planes specified as THREE.Plane objects in world space.
Because the planes are in world space, they won't orient within your object's local space. You would need to apply your object's world transformation matrix to the planes in order to align them with your object.
myMesh.material.clippingPlanes[0].applyMatrix4(myMesh.matrixWorld);
Note that if your mesh is moving around, you'd need to store the original clipping plane for application of the new matrixWorld from each transformation.
// somehwere else in the code:
var clipPlane1 = new THREE.Plane(); // however you configure it is up to you
// later, probably in your render method:
myMesh.material.clippingPlanes[0].copy(clipPlane1);
myMesh.material.clippingPlanes[0].applyMatrix4(myMesh.matrixWorld);

Related

Rotate around World Axis

I tried to rotate an object arount the Worlds-Y-Axis, with
myObject.rotateOnWorldAxis(new THREE.Vector3(0,1,0),THREE.Math.degToRad(1));
but the result was, that the object is only rotated in object space.
To be sure that I used the correct method I looked into the documentation and found that there are three methods to rotate an object:
.RotateY(rad) // rotate in Local Space
.rotateOnAxis(axis,rad) // rotation in Object Space
.rotateOnWorldAxis(axis,rad) // rotation in World Space
It seems that I used the correct method.
Is this a bug or an understanding problem on my side?
Here is a JSFiddle which illustrates my problem (the blue cube should rotate around the world axis).
Here is a second Fiddle where thy cyan cube is a child of another object.
It looks to me like your real question isn't regarding world space or object space rotations, cause those are working as expected in your examples.
You probably meant, how to change the point of rotation of an object. If that is the case, you have two options, you can either translate all your geometry vertices in respect to a pivot point of rotation. That way, your pivot will be centered at (0,0,0) and your vertices will rotate in respect to that.
mesh.geometry.translate( x, y, z );
Or you can make your object a child of a different Object3D (pivot), position your original mesh similarly to what was described above and rotate your pivot mesh.
var cube = new THREE.Mesh( geometry, material );
var pivot = new THREE.Object3D();
cube.position.set( 0, 12, 30 ); // offset from center
pivot.add( cube );
scene.add( pivot );
//...
pivot.rotation.y += Math.PI/2;
JSFiddle

How can I rotate around the center of an object in three.js?

I am dynamically adding a number of different objects of various sizes into a scene (one per click) and scaling and positioning them. Now I want to be able to rotate the objects around the Y axis at their center. I have added a boundingBox and an axesHelper, but the latter is showing up in the bottom corner of the objects. Reading this answer, which is similar to mine, it seems like this might be because of an offset. I can find the center of the object fine with this:
var box3 = new THREE.Box3();
var boundingBox = new THREE.BoxHelper( mesh, 0xffff00 );
scene.add( boundingBox );
box3.setFromObject( boundingBox );
center = box3.getCenter( boundingBox.position );
console.log( "center: ", center );
But when I try to reset the center to this position, following this answer, my object shoots way off into space.
box3.center(mesh.position);
mesh.position.multiplyScalar( -1 );
And I’m not really clear (even after reading the documentation) what “multiplyScalar” does/means. By playing with that number, I can get the object closer to the desired position, but the object still doesn't rotate around its center, and the AxesHelper is still at the original location.
Your object is not rotating around its center. Likely, your object's geometry is offset from the origin.
If you are dealing with a single Mesh or Line, you can center the object's geometry by calling
geometry.center();
This method will translate the vertices of the geometry so the geometry's bounding box is centered at the origin.
three.js r.97

three.js bind Plane to proxy Object transformations

I'm trying to transform a Plane according to a Object3D (position and rotation). That Plane is used as a clippingPlane.
If I call Plane.applyMatrix4( Object.matrixWorld ) it just applies the matrix once, and doesn't bind the Plane to that matrix for future transformations.
However if I call the same function in a loop the transformations applied to the Plane are continuous.
EG if I call Object.rotate.z = 1 once, and then Plane.applyMatrix4( Object.matrixWorld ) in a loop, the Plane rotates 1 unit along the Z axis at every loop.
Any ideas?
Being this Plane used as a clipping plane, I also tried to transform it in the shader material of the mesh being clipped, and it maybe would be the best performance-wise, but I'm not so skilled to accomplish that.
I would just to this:
object.add( plane );
In this way, plane is a child of object. All transformations applied to object are also applied to plane. Besides, it's now very easy to transform plane relative to object.
The quickest solution I found is to reset and apply Object's .matrixWorld to the Plane. As I said before, it would be great to add useful transformation and "binding" methods to the THREE.Plane object, since it's used as clipping plane too.
Right now I did this way:
// will store the object's inverse transformations matrix in world coords
var inversePrevMatrix = new THREE.Matrix4();
function loop(){
// reset plane previous transformations
plane.applyMatrix4( inversePrevMatrix );
// apply actual object matrix in world coordinates
plane.applyMatrix4( object.matrixWorld );
// set prevMatrix
inversePrevMatrix.getInverse( object.matrixWorld );
}

How to plot country names on the globe, so the mesh will be aligned with the surfaces

I'm trying to plot country names of the globe, so the text meshes will be aligned with the surface, but I'm failing to calculate proper rotations. For text I'm using THREE.TextGeometry. The name appears on the click of the mesh of the country at the point of intersection using raycasting. I'm lacking knowledge of how to turn these coordinates to proper rotation angles. I'm not posting my code, as it's complete mess and I believe for a knowldgeable person will be easier to explain how to achieve this in general.
Here is desired result:
The other solution, which I tried (and which, of course, is not the ultimate), based on this SO answer. The idea is to use the normal of the face you intersect with the raycaster.
Obtain the point of intersection.
Obtain the face of intersection.
Obtain the normal of the face (2).
Get the normal (3) in world coordinates.
Set position of the text object as sum of point of intersection (1) and the normal in world coordinates (4).
Set lookAt() vector of the text object as sum of its position (5) and the normal in world coordinates (4).
Seems long, but actually it makes not so much of code:
var PGHelper = new THREE.PolarGridHelper(...); // let's imagine it's your text object ;)
var PGlookAt = new THREE.Vector3(); // point of lookAt for the "text" object
var normalMatrix = new THREE.Matrix3();
var worldNormal = new THREE.Vector3();
and in the animation loop:
for ( var i = 0; i < intersects.length; i++ ) {
normalMatrix.getNormalMatrix( intersects[i].object.matrixWorld );
worldNormal.copy(intersects[i].face.normal).applyMatrix3( normalMatrix ).normalize();
PGHelper.position.addVectors(intersects[i].point, worldNormal);
PGlookAt.addVectors(PGHelper.position, worldNormal);
PGHelper.lookAt(PGlookAt);
}
jsfiddle exmaple
The method works with meshes of any geometry (checked with spheres and boxes though ;) ). And I'm sure there are another better methods.
very interesting question.I have tried this way, we can regard the text as a plane. lets define a normal vector n from your sphere center(or position) to point on the sphere surface where you want to display text. I have a simple way to make normal vector right.
1. put the text mesh on sphere center. text.position.copy(sphere.position)
2. make text to the point on sphere surface, text.lookAt(point)
3.relocate text to the point. text.position.copy(point)

openGL reverse image texturing logic

I'm about to project image into cylindrical panorama. But first I need to get the pixel (or color from pixel) I'm going to draw, then then do some Math in shaders with polar coordinates to get new position of pixel and then finally draw pixel.
Using this way I'll be able to change shape of image from polygon shape to whatever I want.
But I cannot find anything about this method (get pixel first, then do the Math and get new position for pixel).
Is there something like this, please?
OpenGL historically doesn't work that way around; it forward renders — from geometry to pixels — rather than backwards — from pixel to geometry.
The most natural way to achieve what you want to do is to calculate texture coordinates based on geometry, then render as usual. For a cylindrical mapping:
establish a mapping from cylindrical coordinates to texture coordinates;
with your actual geometry, imagine it placed within the cylinder, then from each vertex proceed along the normal until you intersect the cylinder. Use that location to determine the texture coordinate for the original vertex.
The latter is most easily and conveniently done within your geometry shader; it's a simple ray intersection test, with attributes therefore being only vertex location and vertex normal, and texture location being a varying that is calculated purely from the location and normal.
Extemporaneously, something like:
// get intersection as if ray hits the circular region of the cylinder,
// i.e. where |(position + n*normal).xy| = 1
float planarLengthOfPosition = length(position.xy);
float planarLengthOfNormal = length(normal.xy);
float planarDistanceToPerimeter = 1.0 - planarLengthOfNormal;
vec3 circularIntersection = position +
(planarDistanceToPerimeter/planarLengthOfNormal)*normal;
// get intersection as if ray hits the bottom or top of the cylinder,
// i.e. where |(position + n*normal).z| = 1
float linearLengthOfPosition = abs(position.z);
float linearLengthOfNormal = abs(normal.z);
float linearDistanceToEdge = 1.0 - linearLengthOfPosition;
vec3 endIntersection = position +
(linearDistanceToEdge/linearLengthOfNormal)*normal;
// pick whichever of those was lesser
vec3 cylindricalIntersection = mix(circularIntersection,
endIntersection,
step(linearDistanceToEdge,
planarDistanceToPerimeter));
// ... do something to map cylindrical intersection to texture coordinates ...
textureCoordinateVarying =
coordinateFromCylindricalPosition(cylindricalIntersection);
With a common implementation of coordinateFromCylindricalPosition possibly being simply return vec2(atan(cylindricalIntersection.y, cylindricalIntersection.x) / 6.28318530717959, cylindricalIntersection.z * 0.5);.

Resources