Three.js: texture loaded unproperly - three.js

I use some data to create a model in three.js. It can load texture, but with a weird problem. I load the texture in this way.
`function createMesh(geom, imageFile){
var loader = new THREE.TextureLoader();
texture = loader.load(imageFile);
var mat = new THREE.MeshLambertMaterial({
side: THREE.DoubleSide,
});
mat.map = texture;
var mesh = new THREE.Mesh(geom, mat);
return mesh;}
var geom = new THREE.Geometry();
geom.vertices = vertices;
geom.faces = faces;
geom.computeFaceNormals();
var myModel = createMesh(geom, './tex1.jpg');
scene.add(myModel);`
Here is the screenshot before the texture is loaded.
Here is the screenshot after the texture is loaded.
My texture file(2048*2048.jpg)
I have tested to load the texture in a common cube, and it works. So I can't figure out why the texture can't be loaded in my model. Any suggestions? Thank you very much!

For customized geometry in Three.js, we need to do UV mapping to define how texture is mapped to the geometry.
Firstly, load the texture by var material = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('texture.jpg') } );
Then here is how I did UV mapping:
create n arrarys, each corresponding to a sub-image of the texture and contains 4 points which define the boudaries of the sub-image. (0, 0) represents the lower left corner and (1, 1) represents the upper right corner.
clear the existed UV mapping by geometry.faceVertexUvs[0] = [];
Map the sub-image of the texture to each triangle face of the geometry.
geometry.faceVertexUvs[0][0] = [ sub_image_1[0], sub_image_1[1], sub_image_1[3] ];
geometry.faceVertexUvs[0][1] = [ sub_image_1[1], sub_image_1[2], sub_image_1[3] ];
Finally, mesh = new THREE.Mesh(geometry, material);

Related

How to add particular texture to particular faces of BoxGeometry using ShaderMaterial in THREE.JS?

I am trying to add texture for each face of BoxGeometry.
I have tried passing an array of ShaderMaterial object into the mesh but its not working.
createMaterials(texture){
return new ShaderMaterial({
uniforms:{
texture:{
value:texture
}
}
})
}
var mat0 = this.createMaterials(brownImageTexture);
var mat1 = this.createMaterials(texture1);
var mat2 = this.createMaterials(texture2);
var mat3 = this.createMaterials(texture3);
var mat4 = this.createMaterials(texture4);
var mat5 = this.createMaterials(texture5);
var cube = new THREE.Mesh(geometry, [mat0 ,mat1, mat2, mat3, mat4, mat5] );
Not able to add texture for each face of Box Geometry.
Note : I want to use Shader Materials because I was able to add a texture to the cube over another texture.
Any guidance, reference or help would be really appreciated !! Thanks

Same image texture for merged shape

I have made a closed hemisphere by merging geometries of a hemisphere and a circle. I have a 360degree image for texture. I want the image to be applied as the texture to the combined geometry. Currently it is applying the texture twice: to the hemisphere and the circle separately.
I have seen some answers on editing the UV mapping, but I am not sure how to go about it.
Here is the code.
var loader = new THREE.TextureLoader();
loader.setPath(srcPath);
loader.load("./texture.jpg", function(texture) {
var hemiSphereGeom = new THREE.SphereGeometry(radius, radialSegments, Math.round(radialSegments / 4), 0, Math.PI * 2, 0, Math.PI * 0.5);
var objMaterial = new THREE.MeshPhongMaterial({
map: texture,
shading: THREE.FlatShading
});
objMaterial.side = THREE.BackSide;
var capGeom = new THREE.CircleGeometry(radius, radialSegments);
capGeom.rotateX(Math.PI * 0.5);
var singleGeometry = new THREE.Geometry();
var cap = new THREE.Mesh(capGeom);
var hemiSphere = new THREE.Mesh(hemiSphereGeom);
hemiSphere.updateMatrix();
singleGeometry.merge(hemiSphere.geometry, hemiSphere.matrix);
cap.updateMatrix();
singleGeometry.merge(cap.geometry, cap.matrix);
el.setObject3D('hemisphere',new THREE.Mesh(singleGeometry , objMaterial));
});
It appears that the code is seeing the closed hemisphere as the two separate entities still. I would try a 3D modeling program and make the shape there and loading it into the AFrame code. Then load the texture on the back side of the geometry.

THREE.JS : Change material color behind PNG texture ? Assign 2 materials to a mesh imported from GLTF model?

I am trying to change the color of my 3D model "behind" the png texture I set (which includes transparency).
I have done a lot of researches, and i finally found an example with a cube which actually works, but I can't understand how to make that with my gltf 3D model (not a BoxGeometry).
METHOD :
Define an array of two materials,
first one is my png texture with transparency = true;
second one is a basic material with its plain color (the color i will be able to change later...)
var materialBack = new THREE.MeshBasicMaterial({color: 0xfadce6});
var materialTxt = new THREE.MeshBasicMaterial({map: mytexture,transparent: true});
var materials = [materialBack, materialTxt];
It works perfect with a cube :
var geometry = new THREE.BoxBufferGeometry();
geometry.clearGroups();
geometry.addGroup( 0, Infinity, 0 );
geometry.addGroup( 0, Infinity, 1 );
var cube = new THREE.Mesh( geometry, materials );
Problem : I can't figure out how to do the same when my model is actually an imported GLTF, and not a "BoxBufferGeometry". It looks like we can't assign an array to o.material :
var loader = new THREE.GLTFLoader();
loader.load(mymodel.glb, function(gltf) {
gltf.scene.traverse((o) => {
if (o.isMesh) {
o.material = materials;
}
scene.add(gltf.scene);
});
I also tried to extract geometry from gltf, then create a new mesh, but without success :
var loader = new THREE.GLTFLoader();
loader.load(mymodel.glb, function(gltf) {
var geometry = gltf.scene.getObjectByName("name").geometry;
mymesh = new THREE.Mesh(geometry,materials);
scene.add(mymesh);
});
Can someone please help ?

How to apply a texture to a custom geometry in Three.js

I successfully applied a texture to a cube geometry with this:
var geometry = new THREE.CubeGeometry(10, 10, 10);
var meshMaterial = new THREE.MeshPhongMaterial({ transparent: false, map: THREE.ImageUtils.loadTexture('/app/images/wood.jpg') });
meshMaterial.side = THREE.DoubleSide;
var mesh = new THREE.Mesh(geometry, meshMaterial);
With this I get a nice textured cube like this:
Now I want to apply the same texture (512x512 jpg image) to a custom model I'm loading from an STL and this is what I get (in this case a pyramid):
This is the code:
loader.load(jsonParam.url, function (geometry) {
var meshMaterial = new THREE.MeshPhongMaterial({ transparent: false, map: THREE.ImageUtils.loadTexture('/app/images/wood.jpg') });
meshMaterial.side = THREE.DoubleSide;
var mesh = new THREE.Mesh(geometry, meshMaterial);
mesh.castShadow = false;
mesh.receiveShadow = true;
scene.add(mesh);
});
Why the texture is not being applied and I get only what seems to be an average of the texture colors?
You need UV mapping.
You can either edit the model in modelling software to add UV coordinates or maybe generate them as in the answers posted here.
I suppose another option would be to create your own shader that maps the texture to the model surface without using UV coordinates.

Lightmap texture tiling with Three.js

I know about texture tiling. However can a lightmap be tiled the same way?
I can't manage to tile a lightmap texture using the following snippet of code. No repeat or offset is taken into account.
var map = THREE.ImageUtils.loadTexture('Map.jpg');
var lightMap = THREE.ImageUtils.loadTexture('Light map.png');
lightMap.wrapS = lightMap.wrapT = THREE.RepeatWrapping;
lightMap.repeat.set(.455078, .455078);
lightMap.offset.set(.472343, .546562);
var material = new THREE.MeshLambertMaterial({map: map, lightMap: lightMap});
jsonLoader.load('Model.json', function (geometry) {
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
});
Thank you for your help.
Lightmaps do not support offset/repeat in three.js, and in fact require a separate set of UVs.
three.js r.69

Resources