Three.js: Set UV of BoxGeometry - three.js

I'm wondering if its possible to change the UV map of the Box Geometry to unfolded, like that:
https://upload.wikimedia.org/wikipedia/commons/thumb/e/ea/Cube_map.svg/599px-Cube_map.svg.png
By default the projection is the same on all faces, which is very limiting in my opinion. Or can you recommend another way to use the three.js geometry and use different projections on its faces?
thanks

I found a useful tutorial answering my questions:
http://www.geofx.com/graphics/nehe-three-js/lessons17-24/lesson17/lesson17.html
Here is the Code that helped me:
var face1 = [
new THREE.Vector2(0, .666),
new THREE.Vector2(.5, .666),
new THREE.Vector2(.5, 1),
new THREE.Vector2(0, 1)];
var face2 = [
new THREE.Vector2(.5, .666),
new THREE.Vector2(1, .666),
new THREE.Vector2(1, 1),
new THREE.Vector2(.5, 1)];
var face3 = [
new THREE.Vector2(0, .333),
new THREE.Vector2(.5, .333),
new THREE.Vector2(.5, .666),
new THREE.Vector2(0, .666)];
var face4 = [
new THREE.Vector2(.5, .333),
new THREE.Vector2(1, .333),
new THREE.Vector2(1, .666),
new THREE.Vector2(.5, .666)];
var face5 = [
new THREE.Vector2(0, 0),
new THREE.Vector2(.5, 0),
new THREE.Vector2(.5, .333),
new THREE.Vector2(0, .333)];
var face6 = [
new THREE.Vector2(.5, 0),
new THREE.Vector2(1, 0),
new THREE.Vector2(1, .333),
new THREE.Vector2(.5, .333)];
Then we assign those vectors to the faceVertex coordinates in the BoxGeometry we created.
geometry.faceVertexUvs[0][0] = [ face1[0], face1[1], face1[3] ];
geometry.faceVertexUvs[0][1] = [ face1[1], face1[2], face1[3] ];
geometry.faceVertexUvs[0][2] = [ face2[0], face2[1], face2[3] ];
geometry.faceVertexUvs[0][3] = [ face2[1], face2[2], face2[3] ];
geometry.faceVertexUvs[0][4] = [ face3[0], face3[1], face3[3] ];
geometry.faceVertexUvs[0][5] = [ face3[1], face3[2], face3[3] ];
geometry.faceVertexUvs[0][6] = [ face4[0], face4[1], face4[3] ];
geometry.faceVertexUvs[0][7] = [ face4[1], face4[2], face4[3] ];
geometry.faceVertexUvs[0][8] = [ face5[0], face5[1], face5[3] ];
geometry.faceVertexUvs[0][9] = [ face5[1], face5[2], face5[3] ];
geometry.faceVertexUvs[0][10] = [ face6[0], face6[1], face6[3] ];
geometry.faceVertexUvs[0][11] = [ face6[1], face6[2], face6[3] ];

Related

THREE.js Where does Line intersect mesh

I've got a Mesh myMesh:
const vertices = new Float32Array( [
0, 1, 0, 0, 1, 2, 2, 1, 2,
0, 1, 0, 2, 1, 2, 2, 1, 0
]);
const myGeometry = new THREE.BufferGeometry();
myGeometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
const myMesh = new THREE.Mesh(myGeometry, new THREE.MeshBasicMaterial({color: 0x00ff00, side: THREE.DoubleSide}));
scene.add(myMesh);
and a line myLine:
var material = new THREE.LineBasicMaterial( { color: "#0000ff"});
var geometry = new THREE.BufferGeometry();
const lineVerts = new Float32Array([ 1, 0, 1, 1, 2, 1]);
geometry.setAttribute('position', new THREE.BufferAttribute(lineVerts, 3));
var myLine = new THREE.Line( geometry, material );
scene.add(myLine);
jsfiddle
I'd like to get the point where the line and the mesh intersect with each other. Is this possible?
function getIntersection(mesh, line) {
// get point where they intersect (if they do so)
return point
}
Thank you for the provided link #WestLangley
Maybe the solution can help others with the same problem:
Create a normalized Vector between the Points of the line
Iterate each face (triangle) of the mesh
Check with .intersectTriangle of THREE.Ray if the line intersects the face
var v1 = new THREE.Vector3(0.5,0,1);
var v2 = new THREE.Vector3(0.5, 2, 1);
var dir = new THREE.Vector3();
dir.subVectors( v2, v1 ).normalize();
dir.normalize();
var ray = new THREE.Ray(v1, dir);
for (var i = 0; i < vertices.length; i+=9) {
var a = new THREE.Vector3(vertices[i], vertices[i+1], vertices[i+2]);
var b = new THREE.Vector3(vertices[i+3], vertices[i+4], vertices[i+5]);
var c = new THREE.Vector3(vertices[i+6], vertices[i+7], vertices[i+8]);
var target = new THREE.Vector3();
ray.intersectTriangle(a, b, c, false, target);
console.log(target);
}
jsfiddle

Video texture on THREE.Geometry

The only examples i can find are of video textures being used on PlaneGeometry's or BoxGeometry's. I have a custom plane that i have a video applied to. The video plays (colors change) and shows however the scale is off (looks like its zoomed in).
Video playing on top right, green plane is a custom Geometry which the video is on.
THREE.Geometry
this.geometry = new THREE.Geometry();
this.geometry.vertices.push(
new THREE.Vector3(900, 0, 840)
new THREE.Vector3(-900, 0, 1200),
new THREE.Vector3(900, 900, 840),
new THREE.Vector3(-900, 900, 1200),
);
this.geometry.faces.push(
new THREE.Face3(0, 1, 2),
new THREE.Face3(1, 3, 2),
);
this.geometry.computeFaceNormals();
this.object = new THREE.Mesh(this.geometry, this._videoMaterial());
videoMaterial function
_videoMaterial() {
let videoImage = document.createElement('canvas');
videoImage.width = 480;
videoImage.height = 204;
this.videoImageContext = videoImage.getContext('2d');
this.videoImageContext.fillStyle = '#211e79';
this.videoImageContext.fillRect(0, 0, videoImage.width, videoImage.height);
this.videoTexture = new THREE.Texture(videoImage);
this.videoTexture.minFilter = THREE.LinearFilter;
this.videoTexture.magFilter = THREE.LinearFilter;
this.videoTexture.format = THREE.RGBFormat;
return new THREE.MeshBasicMaterial({
map: this.videoTexture,
overdraw: true,
side: THREE.DoubleSide
});
}
As prisoner849 said, you need to add UVs to your geometry so it knows how to map the texture on its surface
// Add UVs of face 1
this.geometry.faceVertexUvs[0].push([
new THREE.Vector2(0, 0)
new THREE.Vector2(0, 1),
new THREE.Vector2(1, 0)
]);
// Add UVs of face 2
this.geometry.faceVertexUvs[0].push([
new THREE.Vector2(0, 1)
new THREE.Vector2(1, 0),
new THREE.Vector2(1, 1)
]);
this.geometry.uvsNeedUpdate();
You might need to tweak the order of the UVs to match the order of your vertices on the faces, but you want an arrangement like this:
https://threejs.org/docs/index.html#api/en/core/Geometry.faceVertexUvs

Vertically repeat texture on side faces only

I have a geometry of a cube that I need to texture,
In the top of the cube - need to be one image
And in each side of the cube - need to be a second image that vertically repeat based on the cube height
This is the texture:
This is what I need:
And this is what I have so far: three.js/texture1
Any ideas how to achieve what I need, but stay with one material and a few faces as possible?
Thanks.
My code:
function create_geometry() {
var geometry = new THREE.Geometry();
var w = 0.5;
var h = 1;
geometry.vertices.push(
new THREE.Vector3(w, h, w),
new THREE.Vector3(w, h, -w),
new THREE.Vector3(w, 0, w),
new THREE.Vector3(w, 0, -w),
new THREE.Vector3(-w, h, -w),
new THREE.Vector3(-w, h, w),
new THREE.Vector3(-w, 0, -w),
new THREE.Vector3(-w, 0, w)
);
geometry.faces.push(
// wall
new THREE.Face3(0, 2, 1),
new THREE.Face3(2, 3, 1),
// wall
new THREE.Face3(4, 6, 5),
new THREE.Face3(6, 7, 5),
// wall
new THREE.Face3(5, 7, 0),
new THREE.Face3(7, 2, 0),
// wall
new THREE.Face3(1, 3, 4),
new THREE.Face3(3, 6, 4),
//roof
new THREE.Face3(4, 5, 1),
new THREE.Face3(5, 0, 1),
);
geometry.computeFaceNormals();
geometry.faceVertexUvs[0] = [];
geometry.faces[0].materialIndex = 0;
geometry.faces[1].materialIndex = 0;
geometry.faces[2].materialIndex = 0;
geometry.faces[3].materialIndex = 0;
geometry.faces[4].materialIndex = 0;
geometry.faces[5].materialIndex = 0;
geometry.faces[6].materialIndex = 0;
geometry.faces[7].materialIndex = 0;
geometry.faces[8].materialIndex = 0;
geometry.faces[9].materialIndex = 0;
var roof = [
new THREE.Vector2(0.0,1.0),
new THREE.Vector2(0.0,0.5),
new THREE.Vector2(1.0,0.5),
new THREE.Vector2(1.0,1.0),
];
var wall = [
new THREE.Vector2(0.0,0.5),
new THREE.Vector2(0.0,0.0),
new THREE.Vector2(1.0,0.0),
new THREE.Vector2(1.0,0.5),
];
// wall
geometry.faceVertexUvs[0][0] = [ wall[0], wall[1], wall[3] ];
geometry.faceVertexUvs[0][1] = [ wall[1], wall[2], wall[3] ];
// wall
geometry.faceVertexUvs[0][2] = [ wall[0], wall[1], wall[3] ];
geometry.faceVertexUvs[0][3] = [ wall[1], wall[2], wall[3] ];
// wall
geometry.faceVertexUvs[0][4] = [ wall[0], wall[1], wall[3] ];
geometry.faceVertexUvs[0][5] = [ wall[1], wall[2], wall[3] ];
// wall
geometry.faceVertexUvs[0][6] = [ wall[0], wall[1], wall[3] ];
geometry.faceVertexUvs[0][7] = [ wall[1], wall[2], wall[3] ];
// roof
geometry.faceVertexUvs[0][8] = [ roof[0], roof[1], roof[3] ];
geometry.faceVertexUvs[0][9] = [ roof[1], roof[2], roof[3] ];
var matrix = new THREE.Matrix4();
//matrix.makeRotationX ( (270 * Math.PI)/180 );
geometry.applyMatrix( matrix );
geometry.uvsNeedUpdate = true;
return geometry;
}
var renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(800,800);
var container = document.getElementById("container");
container.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45,800/800,1,1000);
camera.position.set(0,10,20);
scene.add(camera);
var controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.minDistance = 15;
controls.maxDistance = 100;
var stats = new Stats();
container.appendChild( stats.dom );
var rendererStats = new THREEx.RendererStats();
rendererStats.domElement.style.position = 'absolute';
rendererStats.domElement.style.right = '0px';
rendererStats.domElement.style.top = '0px';
document.body.appendChild( rendererStats.domElement );
// plane
var plane = new THREE.Mesh(
new THREE.PlaneGeometry( 80, 80, 1 ),
new THREE.MeshBasicMaterial( {color: 0x333333, side: THREE.DoubleSide} )
);
plane.rotation.x = (90 * Math.PI)/180;
scene.add(plane);
//
var geometry = create_geometry();
var texture = new THREE.TextureLoader().load( "texture1.png" );
var material = new THREE.MeshBasicMaterial({ map:texture });
for(var i=0; i<10; i++) {
var cube = new THREE.Mesh( geometry, material );
cube.position.x = i*1.5 - 5*1.5;
//cube.position.y = Math.random()*80 - 40;
cube.scale.y = i + 1;
scene.add( cube );
}
function render() {
controls.update();
stats.update();
rendererStats.update(renderer);
renderer.render( scene, camera );
requestAnimationFrame( render );
}
render();

Stretch a texture across multiple faces using Three.js

I'm trying to apply a texture on an Object3D with a custom geometry that consists of multiple faces. From the user's point of view this should be a single surface and the texture should stretch ideally keeping the sides ratio. I've tried various texture settings but so far no luck.
The top image is what I'm getting and the bottom one what I'm trying to achieve: https://dl.dropboxusercontent.com/u/20925853/combined.jpg
I've extracted a sample code to JsFiddle: http://jsfiddle.net/Immugio/Lg5vbzot/
function render() {
renderer.render(scene, camera);
};
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var light = new THREE.DirectionalLight(0xffffff);
light.intensity = 0.5;
light.position.set(0, 1, 1).normalize();
scene.add(light);
var ambient = new THREE.AmbientLight(0x777777);
scene.add(ambient);
var controls = new THREE.OrbitControls(camera);
controls.damping = 0.2;
controls.addEventListener('change', render);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
THREE.ImageUtils.crossOrigin = '';
var textureMaterial = new THREE.MeshPhongMaterial({
map: THREE.ImageUtils.loadTexture('https://dl.dropboxusercontent.com/u/20925853/crate.jpg', null, function() {
render();
})
});
var geo = new THREE.Geometry();
geo.vertices = [
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 4, 0),
new THREE.Vector3(4, 4, 0),
new THREE.Vector3(4, 0, 0),
new THREE.Vector3(1, 4, 0),
new THREE.Vector3(1, 6, 0),
new THREE.Vector3(3, 6, 0),
new THREE.Vector3(3, 4, 0)
];
geo.faces = [
new THREE.Face3(0, 1, 2),
new THREE.Face3(0, 2, 3),
new THREE.Face3(4, 5, 6),
new THREE.Face3(4, 6, 7)
];
var faceuv = [
new THREE.Vector2(0, 1),
new THREE.Vector2(1, 1),
new THREE.Vector2(1, 0),
new THREE.Vector2(0, 0)
];
geo.faceVertexUvs[0] = [];
geo.faceVertexUvs[0][0] = [faceuv[0], faceuv[1], faceuv[2]];
geo.faceVertexUvs[0][1] = [faceuv[0], faceuv[2], faceuv[3]];
geo.faceVertexUvs[0][2] = [faceuv[0], faceuv[1], faceuv[2]];
geo.faceVertexUvs[0][3] = [faceuv[0], faceuv[2], faceuv[3]];
geo.computeFaceNormals();
var mesh = new THREE.Mesh(geo, textureMaterial);
mesh.rotation.x = Math.PI / 180 * 135;
mesh.rotation.z = Math.PI / 180 * 135;
scene.add(mesh);
camera.position.z = 10;
In order to strech the texture you need to map the UV accros yours multiple faces.
JsFiddle :http://jsfiddle.net/Lg5vbzot/1/
Replacing with the following code
var faceuv = [
new THREE.Vector2(0, 0),
new THREE.Vector2(0, 0.66),
new THREE.Vector2(1, 0.66),
new THREE.Vector2(1, 0),
new THREE.Vector2(0.25, 0.66),
new THREE.Vector2(0.25, 1),
new THREE.Vector2(0.75, 1),
new THREE.Vector2(0.75, 0.66)
];
geo.faceVertexUvs[0] = [];
geo.faceVertexUvs[0][0] = [faceuv[0], faceuv[1], faceuv[2]];
geo.faceVertexUvs[0][1] = [faceuv[0], faceuv[2], faceuv[3]];
geo.faceVertexUvs[0][2] = [faceuv[4], faceuv[5], faceuv[6]];
geo.faceVertexUvs[0][3] = [faceuv[4], faceuv[6], faceuv[7]];

Texture mapping on extrude geometry ThreeJS

I'm creating random shapes with extrude geometry on ThreeJS, now I want to apply textures on it but the result is ugly. I can't figure out how to generate UVMapping in order to display the texture correctly.
I fiddled my issue:
http://jsfiddle.net/PsBtn/8/
On the left mesh, one face is not correctly textured, as the face is flat I want the texture not to be skewed.
On the right, the texture is rotated but I don't want this result.
Is there an automatically way to generate UVMapping in order to get the texture render the same on these two meshes (Extrude Geometry) ?
Here is how I generate my meshes:
var points = []
points.push(new THREE.Vector2(-1000, -700));
points.push(new THREE.Vector2(-1000, -300));
points.push(new THREE.Vector2(-300, -300));
points.push(new THREE.Vector2(-300, -500));
shape = new THREE.Shape(points);
var geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings),
texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var material = new THREE.MeshBasicMaterial({
color: 0xFF00FF,
map: texture
});
geometry.faceUvs = [[]];
geometry.faceVertexUvs = [[]];
for (var f = 0; f < geometry.faces.length; f++) {
var faceuv = [
new THREE.Vector2(0, 1),
new THREE.Vector2(1, 1),
new THREE.Vector2(1, 0),
new THREE.Vector2(0, 0)
];
geometry.faceUvs[0].push(new THREE.Vector2(0, 1));
geometry.faceVertexUvs[0].push(faceuv);
}
mesh = THREE.SceneUtils.createMultiMaterialObject(geometry, [material, new THREE.MeshBasicMaterial({
color: 0x000000,
wireframe: true,
transparent: true
})]);
mesh.position.z = -100;
mesh.position.y = 200;
scene.add(mesh);
I found a solution, I have to compute the uv form my custom forms. This web page is really usefull for it :
http://paulyg.f2s.com/uv.htm

Resources