How to apply a texture to a custom geometry in Three.js - 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.

Related

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 ?

Three.js: texture loaded unproperly

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);

Three.js: Add a texture to an object just on the outside

I'm very new with Three.js and I'm trying to make a ring:
http://www.websuvius.it/atma/myring/preview.html
I have a background texture ( the silver one ) and another one with a text.
I want the text only on the ring external face.
This is part of my code:
var loader = new THREE.OBJLoader( manager );
var textureLoader = new THREE.TextureLoader( manager );
loader.load( 'assets/3d/ring.obj', function ( event ) {
var object = event;
var geometry = object.children[ 0 ].geometry;
var materials = [];
var backgroundTexture = textureLoader.load('img/texture/silver.jpg');
backgroundTexture.flipY = false;
var background = new THREE.MeshBasicMaterial({
map: backgroundTexture,
color: 0xffffff
});
materials.push(background);
var customTexture = textureLoader.load('img/text.png');
customTexture.flipY = false;
var custom = new THREE.MeshBasicMaterial({
map: customTexture,
transparent: true,
opacity: 1,
color: 0xffffff
});
materials.push(custom);
mesh = THREE.SceneUtils.createMultiMaterialObject(geometry, materials);
mesh.position.y=-50;
scene.add(mesh);
}, onProgress, onError );
It is possible?
Thanks
The reason behind your issue appears to be in your .obj file. Judging from a quick glance at the texture coordinates stored in the file, the inside of the ring uses the same part of the texture image as the outside of the ring.
Increasing the transparent parts of the image won't help. Neither will the attempts to stop the texture from repeating. Those would help if the texture coordinates were larger than 1 but this is not your case unfortunately.
However, there are several solutions:
Split the object in a 3D modeling software to two objects - outside and inside of the ring - and apply the texture only to the first one.
Adjust the UV coordinates of the object in a 3D modeling software.
Adjust the UV coordinates of the vertices programmatically after loading the object to Three.JS

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

invert mesh in three.js

How to invert a mesh using three.js
I had a mesh created using THREE.Mesh
var geometry = new THREE.ExtrudeGeometry( featurePts,extrudeSettings);
var mat = new THREE.MeshBasicMaterial( { color: color, wireframe: true, transparent: true } );
var mesh = new THREE.Mesh(geometry, mat );
But my shape looks inverted. Is there any way in Three.js to invert my shape?
shape used above is a list of THREE.Vector2
var featurePts = [];
featurePts.push(new THREE.Vector2 (550,107));
If you mean it looks inside out, try reversing your normals.

Resources