cube texture is reversed in one of the cube faces - javascript

I use an image for the cube texture, the image is shown correctly in 3 of 4 faces, and looks reversed for the 4th face.
My relevant code is the following:
//dom
var container2=document.getElementById('share');
//renderer
var renderer2 = new THREE.CanvasRenderer();
renderer2.setSize(100,100);
container2.appendChild(renderer2.domElement);
//Scene
var scene2 = new THREE.Scene();
//Camera
var camera2 = new THREE.PerspectiveCamera(50,200/200,1,1000);
camera2.up=camera.up;
//
camera2.position.z = 90;
//
scene2.add(camera2);
//Axes
var axes2= new THREE.AxisHelper();
//Add texture for the cube
//Use image as texture
var img2 = new THREE.MeshBasicMaterial({ //CHANGED to MeshBasicMaterial
map:THREE.ImageUtils.loadTexture('img/fb.jpg')
});
img2.map.needsUpdate = true;
//
var cube = new THREE.Mesh(new THREE.CubeGeometry(40,40,40),img2);
scene2.add(cube);
The image size is 600*600 px. Any suggestion is appreciated, thanx in advance.

First off, it should be pointed out for others that you are trying to develop using the javascript library "three.js". The documentation can be found here: http://mrdoob.github.com/three.js/docs
The crux of the issue is that textures get mapped to Mesh objects based upon UV coordinates stored in the Geometry objects. The THREE.CubeGeometry object has its UV coordinates stored in the array faceVertexUvs.
It contains the following arrays of UV coordinate for the 4 vertices in each of the 6 faces:
{{0,1}, {0,0}, {1,0}, {1,1}}, // Right Face (Top of texture Points "Up")
{{0,1}, {0,0}, {1,0}, {1,1}}, // Left Face (Top of texture Points "Up")
{{0,1}, {0,0}, {1,0}, {1,1}}, // Top Face (Top of texture Points "Backward")
{{0,1}, {0,0}, {1,0}, {1,1}}, // Bottom Face (Top of texture Points "Forward")
{{0,1}, {0,0}, {1,0}, {1,1}}, // Front Face (Top of texture Points "Up")
{{0,1}, {0,0}, {1,0}, {1,1}} // Back Face (Top of texture Points "Up") **Culprit**
It is mapping UV coordinate to each of the faces which make up the cube, which are:
{0, 2, 3, 1}, // Right Face (Counter-Clockwise Order Starting RTF)
{4, 6, 7, 5}, // Left Face (Counter-Clockwise Order Starting LTB)
{4, 5, 0, 1}, // Top Face (Counter-Clockwise Order Starting LTB)
{7, 6, 3, 2}, // Bottom Face (Counter-Clockwise Order Starting LBF)
{5, 7, 2, 0}, // Front Face (Counter-Clockwise Order Starting LTF)
{1, 3, 6, 4} // Back Face (Counter-Clockwise Order Starting RTB)
The above numbers are indexes into the array of vertices, which for the THREE.CubeGeometry are stored in vertices, there are 8 of them:
{20, 20, 20}, // Right-Top-Front Vertex
{20, 20, -20}, // Right-Top-Back Vertex
{20, -20, 20}, // Right-Bottom-Front Vertex
{20, -20, -20}, // Right-Bottom-Back Vertex
{-20, 20, -20}, // Left-Top-Back Vertex
{-20, 20, 20}, // Left-Top-Front Vertex
{-20, -20, -20}, // Left-Bottom-Back Vertex
{-20, -20, 20} // Left-Bottom-Front Vertex
NOTE: All relative directions above are assuming the camera is placed along the positive z axis looking towards a cube centered on the origin.
So the real culprit is the back face which has the texture's top point upwards. In this case you want the texture's top to point downwards on the back face, so when the cube if flipped upside down due to the rotations and viewed the way you have it, the image appears as you expect. It needs to change as follows:
{{1,0}, {1,1}, {0,1}, {0,0}} // FIXED: Back Face (Top of texture Points "Down")
This change can be made in the code to change the coordinates to get the display you would like:
var cubeGeometry = new THREE.CubeGeometry(40, 40, 40);
cubeGeometry.faceVertexUvs[0][5] = [new THREE.UV(1, 0), new THREE.UV(1, 1), new THREE.UV(0, 1), new THREE.UV(0, 0)];
var cube = new THREE.Mesh(cubeGeometry, img2);
For further reading, I recommend the following link on Texture Mapping with UV coordinates http://www.rozengain.com/blog/2007/08/26/uv-coordinate-basics/.

Related

Customize PlaneGeometry edges for each segment in ThreeJS

Currently PlaneGeometry has an option to change segment width and height but this has no effect on edges. Each segment currently has indexed positions to create an 'N' shape when viewing the geometry in wireframe mode:
Indexes currently are:
0 = South West
1 = North West
2 = South East
3 = North East
This gives us an 'N' shape for each segment with wireframes, however instead of this 'N' Shape i would like to create an 'X' shape with edges for every segment. Currently i'm using planes to create different heights and having an 'X' shape would make the result look less edgy shaped (screenshots below).
I think all required vertices already exists, but how is it possible to get an extra edge between point 0 and 3 for each segment?
I've tried looking for the answer online but couldn't find a clear answer on this matter, besides many articles are older than version R125 which made breaking changes to Geometries. Currently I'm using version R135.
I'm guessing i will need to create a custom Buffer Geometry, but am in doubt of how to execute this properly and not losing too much performance.
All red and blue lines are currently existing edges in wireframe mode.
All green lines are desired and currently not existing, what would be the best way to do this without losing performance?
Thanks in advance!
It took me a fair amount of attempts but in the end it didn't turn out to be too hard. I've created this custom PlaneGeometry by creating a custom BufferGeometry. Although it's probably 3x heavier to use;
At the moment it holds 36 (12 * 3) positions per tile segment as where the default PlaneGeometry holds 12 (4 * 3) positions. Although i'm not sure if 3x more positions automatically means 3x more performance usage, but it definitely uses more than the default PlaneGeometry.
Here are the results (changes in height smoothen out prettier):
Code to create the geometry:
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
// (North Face)
.5, -.5, 0, // 0: Center
1, -1, 0, // 1: NE
1, 0, 0, // 2: NW
// (East Face)
.5, -.5, 0, // 3: Center
0, -1, 0, // 4: SE
1, -1, 0, // 5: NE
// (South Face)
.5, -.5, 0, // 6: Center
0, 0, 0, // 7: SW
0, -1, 0, // 8: SE
// (West Face)
.5, -.5, 0, // 9: Center
1, 0, 0, // 10: NW
0, 0, 0, // 11: SW
]);
geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
const material = new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true } );
const mesh = new THREE.Mesh( geometry, material );
mesh.rotation.x = - Math.PI / 2;
scene.add( mesh );

Rotate a vector based on a normal in Three.js

I have a vector like this
{x: 0, y: 0, z: 1}
Then I have another vector that is a normal, a direction, like this
{x: 1, y: 0, z: 0}
How do i rotate the vector based on the direction in the normal so it looks like this?
{x: 1, y: 0, z: 0}
I'm using Three.js
After digging in to this answer I come up with a solution that seems to work
https://github.com/mrdoob/three.js/issues/1486
rotateVectorWithNormal(toRotate: Vector3, normal: Vector3) {
const newVector: Vector3 = new Vector3().copy(toRotate);
// set up direction
let up = new Vector3(0, 1, 0);
let axis: Vector3;
// we want the vector to point in the direction of the face normal
// determine an axis to rotate around
// cross will not work if vec == +up or -up, so there is a special case
if (normal.y == 1 || normal.y == -1) {
axis = new Vector3(1, 0, 0);
} else {
axis = new Vector3().cross(up, normal);
}
// determine the amount to rotate
let radians = Math.acos(normal.dot(up));
const quat = new Quaternion().setFromAxisAngle(axis, radians);
newVector.applyQuaternion(quat);
return newVector;
}
Code in Typescript
While the auto-answer is correct, here some general points about such a rotation:
If only two vectors are given, namely a and b, there are infinite rotations transforming a into b. The answer above takes the shortest rotation but requires to determine the axis of rotation via a cross product. A second solution is to take the bisector as rotation axis and rotate by Pi. Here you would normalize to a_n and b_n and rotate around (a_n + b_n).
The difference between the rotations would only affect non-rotational symmetric object.
If all vectors are normalized already it should be as simple as
var a = new THREE.Vector3( 0, 0, 1 );
var b = new THREE.Vector3( 1, 0, 0 );
var c = new THREE.Vector3( x, y, z );
var quaternion = new THREE.Quaternion();
quaternion.setFromAxisAngle( a + b, Math.PI );
c.applyQuaternion( quaternion );
If c==a then c is rotated onto b and if c==b then c is rotated onto a.

Set length of CylinderGeometry in Three.js

The following code creates an object with proportional lengths.
My question is:
How can I set the length of one of the sides? (indicated with the red line)?
Edit:
I'm also looking into rectShape but I'm not sure if I can make this into a 3d shape.
var shape = THREE.SceneUtils.createMultiMaterialObject(
new THREE.CylinderGeometry( 30, 30, 30, 7, 1 ),
multiMaterial );
shape.position.set(0, 25, 0);
scene.add( shape );
Result:
To create an image like this (top view):

Three.js: Rotate Cylinder into Vector3 direction

I've already searched, but didn't find anything that helps:
I got an vector and a CylinderGeometry Mesh. I want to acchieve, that the cylinder is facing the point where the vector is showing. As input I got a position (c) and a direction (m) (like a line equation: y = mx + c):
function draw (m,c, _color) {
//... create the geometry and mesh
// set the position
line.position.x = c.x;
line.position.y = c.y;
line.position.z = c.z;
// i've tried something like this:
line.lookAt(c.add(m));
//.. and add to scene
}
But it looks like the direction is the direct opposite of what I want to acchieve.
I've also tried stuff like translation:
geometry.applyMatrix( new THREE.Matrix4().makeTranslation(0, length/2, 0));
and tried to get the rotation manually like line.rotation.x = direction.angleTo(vec3(1,0,0))* 180 / Math.PI;. But none of them worked like I needed.
This works for me:
// Make the geometry (of "distance" length)
var geometry = new THREE.CylinderGeometry( 0.6, 0.6, distance, 8, 1, true );
// shift it so one end rests on the origin
geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, distance / 2, 0 ) );
// rotate it the right way for lookAt to work
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( THREE.Math.degToRad( 90 ) ) );
// Make a mesh with the geometry
var mesh = new THREE.Mesh( geometry, material );
// Position it where we want
mesh.position.copy( from.sceneObject.position );
// And make it point to where we want
mesh.lookAt( to.sceneObject.position );

Rotation anchor point in Three.js

I am defining a cone that I need to be able to rotate around its top point (the point where the cone thickness is the smallest one). I couldn't find yet the way to set the point around which the rotation to happen.
var coneGeometry = new THREE.CylinderGeometry(1000, 0, width, 50, 50, false);
var cone = new THREE.Mesh(coneGeometry, material);
cone.position.x = x;
cone.position.y = y + width / 2;
cone.position.z = z;
// I want this rotation to happen around the point given by the (x, y, z) location
cone.rotation.x = dip;
The cone geometry is centered at the origin. What you need to do is translate the cone geometry right after it is created so the tip of the cone is at the origin.
coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, coneHeight/2, 0 ) );
(The sign of the translation changes depending on which end of the cone is the small end.)
Now, when you rotate the cone, it will rotate around the tip. The tip will also be located at the position you set.
EDIT: You can now do this, instead:
coneGeometry.translate( 0, coneHeight/2, 0 ); // three.js r.72

Categories

Resources