three.js: texture on shapegeometry - three.js

I'm working with three.js and I have a plane shape. This shape should get a texture. Below you can see how I try this. The problem is, that the texture is only shown in two stripes at two edges of the shape. If I take higher values for texture.repeat this stripes get thinner.
I know there is a related topic here Three.JS Is it possible to render a texture on shapeGeometry?, but I can't understand how that could help me.
//Draw Floorshape
var points_floor = [];
points_floor.push(new THREE.Vector2(edges[edges.length-1][edges[3].length-1][0], edges[edges.length-1][edges[3].length-1][1]));
for (var i = 0; i < edges.length; i++) {
for (var j = 0; j < edges[i].length; j++) {
points_floor.push(new THREE.Vector2(edges[i][j][0], edges[i][j][1]));
}
}
var shape_floor = new THREE.Shape(points_floor);
var floorGeometry = new THREE.ShapeGeometry(shape_floor);
var texture = new THREE.ImageUtils.loadTexture("./img/tileable_wood_texture_by_ftIsis_Stock.jpg");
texture.repeat.set(0.1, 0.1);
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
var materialFloor = new THREE.MeshBasicMaterial({
map : texture,
side : THREE.DoubleSide
});
var floor = new THREE.Mesh(floorGeometry, materialFloor);
floor.overdraw = true;

Related

THREE.js planeGeometry clipped inside the walls

I want to make a 3D building using Three.js. For example, I made 6 walls and a floor by checkerboard texture. I used clippingPlanes for wall1 and wall4:
floor1.material.clippingPlanes = [plane1,plane4];
I made my planes(plane1 and plane4) by my walls(wall1 and wall4). For example, my wall4 planeGeometry and plane4 code is here:
var wallGeometry4 = new THREE.PlaneGeometry(40, Floor_Height, 1, 1);
var wall4 = createMesh(wallGeometry4, "brick_diffuse.jpg", THREE.DoubleSide, 1024, 1024);
unit1.add(wall4);
wall4.position.x = -10;
wall4.position.y = 0;
wall4.position.z = -20;
wall4.rotation.y = 1.5 * Math.PI;
wall4.add(new THREE.EdgesHelper(wall4, 0x000000));
var plane4 = new THREE.Plane();
var normal4 = new THREE.Vector3();
var point4 = new THREE.Vector3();
normal4.set(0, 0, -1).applyQuaternion(wall4.quaternion);
point4.copy(wall4.position);
plane4.setFromNormalAndCoplanarPoint(normal4, point4);
But I see an empty area between wall5 and wall6, because plane4(that used for clipping the floor) isn't the same size of wall4. I think Plane4 is whole of the scene. How to change size of my plane to clip correctly? Or Is there any way to make floor bounded in walls?
One way to achieve this as suggested is to use ShapeGeometry.
When you are creating your walls you can save the x and z co-ordinate of their starting and ending points in an array to form a loop of points of Vector2. Then you can create a new custom shape from these points using shapeGeometry.
points = [{x:0,y:0},{x:0,y:10},{x:10,y:10},{x:10,y:0},{x:0,y:0}]
function getShapeFromPoints(points){
const shape = new THREE.Shape();
shape.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
shape.lineTo(points[i].x, points[i].y);
}
return shape;
}
function createPlaneFromPoints(points) {
const planeMaterial = getPlaneMaterial();
const shape = getShapeFromPoints(points);
const geometry = new THREE.ShapeBufferGeometry(shape);
geometry.rotateX(degreeToRadians(-90));
const mesh = new THREE.Mesh(geometry, planeMaterial);
return mesh;
}
Hope that helps you!

ShapePath auto closing

I'm having an issue with ShapePath where the shape is automatically being closed when converting to geometry?
var path = new THREE.ShapePath();
path.moveTo(0, 0);
path.lineTo(0,50);
path.lineTo(50,50);
var shapes = path.toShapes(true);
for ( var j = 0; j < shapes.length; j ++ ) {
var shape = shapes[ j ];
console.log(shape);
var material = new THREE.MeshLambertMaterial( {
color: Math.random() * 0xffffff
});
var geometry = new THREE.ShapeBufferGeometry( shape );
var mesh = new THREE.Mesh( geometry, material );
scene.add(mesh);
}
JS Fiddle
What I'm expecting to have is a L style shape, instead i'm getting a triangle being rendered.
I really just want to extrude the path to a solid L shape.
Any ideas on the best approach?
You can draw your intended result if you create an enclosing contour of the L shape like shown in the following example: https://jsfiddle.net/zbeLk6jw/1/
var path = new THREE.ShapePath();
path.moveTo(0, 0);
path.lineTo(0,50);
path.lineTo(10,50);
path.lineTo(10,10);
path.lineTo(25,10);
path.lineTo(25,0);

Texture map to control pixel colors in a THREE.Points mesh

I'm fairly new to Three.js, but I'm trying to use a Texture map to control pixel colors in a THREE.Points mesh. My desired outcome is that vertex 0 will be colored as image pixel x=0, y=0. Vertex 1 will be colored as image x=1, y=0, and so on.
All attempts I have make result is each vertex point being rendered with the whole image (not use one color according to the coordinates.)
Here is a snippet of my code.
... Define Geometry ...
var texture = new THREE.TextureLoader().load("img/MyImage.jpg");
var mat = new THREE.PointsMaterial({ size: 2.5, vertexColors: THREE.VertexColors, map: texture });
var points = new THREE.Points(geo, mat);
If you don't feel like you have to use a texure (maybe that is possible with a similar approach) you could just read the pixeldata of the image and use that to set colors similar to WestLangleys suggestion.
I'm not sure if the difference between colors size and number of vertices are going to be a problem, but it's working fine for me. Good luck!
var img = new Image();
img.src = "Image1.png";
img.onload = function(){
// apply image to canvas
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img,0,0,img.width,img.height);
var colors = [];
// geometry of choice
var geo = new THREE.SphereGeometry(50,50);
for(var i = 0; i < img.width; i++){
for(var j = 0; j < img.height; j++){
// pd - pixeldata array in the format of rgba. example: [53, 53, 130, 255]
var pd = canvas.getContext('2d').getImageData(i,j,1,1).data;
// not pretty, but works
colors.push(new THREE.Color("rgb("+pd[0]+","+pd[1]+","+pd[2]+")"));
}
}
geo.colors = colors;
var material = new THREE.PointsMaterial( {size: 10, vertexColors: THREE.VertexColors });
var point = new THREE.Points(geo, material);
scene.add(point);
};

Texture mapping from one Face4 to two Face3 on Three.js

I am playing with Three.js. I am working on a project that uses an old version of Three.js. I'm trying to replace the old library with the new one (r71). Everything is going well except the texture mapping.
In the old project we use the Face4 which is deprecated and have been removed in the newest version of Three.js. So I have created two Face3 instead of just one Face4. Now the question is: how can I make one texture to cover both Face3 as they were like a single Face4?
Old pseudo-code using Face4
numberOfFaces = 10;
function createMyGeometry(){
var geometry = new THREE.Geometry();
...
for (var i = 0; i < numberOfFaces; i++) {
var face = new THREE.Face4(v1.index, v2.index, v3.index, v4.index, [v1.clone(), v2.clone(), v3.clone(), v4.clone()]);
face.centroid.add(v1).add(v2).add(v3).add(v4).divideScalar(4);
face.normal = face.centroid.clone().normalize();
face.materialIndex = matIdx;
geometry.faces.push(face);
geometry.faceVertexUvs[0].push([uv1.clone(), uv2.clone(), uv3.clone(), uv4.clone()]);
}
...
return geometry;
}
for (var i = 0; i < numberOfFaces; i++) {
var texture = THREE.ImageUtils.loadTexture("MyImage"+ i + '.jpg');
var material = new THREE.MeshBasicMaterial();
material.map = texture;
material.side = THREE.FrontSide;
materials.push(material);
}
materials = new THREE.MeshFaceMaterial(materials);
myGeometry = new THREE.Mesh(createMyGeometry(), materials);
scene.add(myGeometry);
Pseudo-code using Face3
numberOfFaces = 10;
function createMyGeometry(){
var geometry = new THREE.Geometry();
...
for (var i = 0; i < numberOfFaces; i++) {
var face1 = new THREE.Face3(v1.index, v2.index, v3.index, [v1.clone(), v2.clone(), v3.clone()]);
var face2 = new THREE.Face3(v1.index, v3.index, v4.index, [v1.clone(), v3.clone(), v4.clone()]);
face1.materialIndex = matIdx;
face2.materialIndex = matIdx;
geometry.faces.push(face1);
geometry.faces.push(face2);
geometry.faceVertexUvs[0].push([uv1.clone(), uv2.clone(), uv3.clone(), uv4.clone()]);
}
...
return geometry;
}
for (var i = 0; i < numberOfFaces; i++) {
var texture = THREE.ImageUtils.loadTexture("MyImage"+ i + '.jpg');
var material = new THREE.MeshBasicMaterial();
material.map = texture;
material.side = THREE.FrontSide;
materials.push(material);
}
materials = new THREE.MeshFaceMaterial(materials);
myGeometry = new THREE.Mesh(createMyGeometry(), materials);
scene.add(myGeometry);
You should just do the same thing with vertex uvs as with vertices.
For example:
geometry.faceVertexUvs[0].push([uv1.clone(), uv2.clone(), uv3.clone()]);
geometry.faceVertexUvs[0].push([uv1.clone(), uv3.clone(), uv4.clone()]);

Three.js incorrect texture mapping orientation

I'm trying apply a simple texture mapping to a cube, but when the texture is applied it's rotated 90° CCW.
Just for my tests I'm using the same uv mapping for all faces:
window.head = function(){
var txSplitX = 1/64;
var txSplitY = 1/32;
var mesh;
var cube = new THREE.CubeGeometry( 100, 100, 100);
var material = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture('assets/charSkin/Superman.png') } );
var faceTx= [
new THREE.Vector2(0.125,0.75),
new THREE.Vector2(0.25,0.75),
new THREE.Vector2(0.25,0.5),
new THREE.Vector2(0.125,0.5)
];
var j=0, k=1;
for(var i=0; i<6;i++){
cube.faceVertexUvs[0][j] = [faceTx[0],faceTx[1],faceTx[3]];
cube.faceVertexUvs[0][k] = [faceTx[1],faceTx[2],faceTx[3]];
j+=2;
k+=2;
}
this.mesh = new THREE.Mesh(cube, material);
}
The result I have :
http://securilabs.free.fr/images/result.png
My texture :
http://securilabs.free.fr/images/Superman.png
How can I get the correct orientation of the texture on each face ?

Resources