Map image on 3D model



model.obj (90.9 KB)

Hello,

I’m trying to map an image on 3D model using the ThreeJS editor, I juste want to display my image on the two principals faces of my model. I have exported my 3D object in obj extension but I don’t know if it’s better with another extension. How can I map my image on my model ?
(You can find all my files in attachement)

Thank you in advance for your answers :slight_smile:

Or if someone knows how I can do that with code, that can be very helpful for me :blush:

If your model has UVs generated… then you should only need to set material.map = new THREE.TextureLoader().load( “yourMapURL.jpg”)

If it doesn’t have UVs generated… you’ll need to generate them in a modeller… or in code…

You might be able to do something in code like…

let p=mesh.geometry.attributes.position.array;
let u=mesh.geometry.attributes.uv.array;
for(let i=0,j=0;i<p.length;i+=3,j+=2){
u[j]=p[i];
u[j+1]=p[i+1]
}

after the mesh is loaded… (but before you render it!) (and you may have to swap some +1 with +2 to get the right axes… and/or multiply then to scale it into the range you want.

As far as I understand the question, @Nolann is trying to do this in the editor, not in code.

I also tried, but failed – I could not find how to change texture repeat, scale and wrapping in the editor. Either the editor does not have these properties editable, or I have not found how to change them.

Most likely alternative approaches are:

  • edit the UV in Blender, so that the texture could be mapped per se in the editor
  • use the scripting mechanism in the editor (which I’m not familiar with) to do the mapping in code
  • add an MTL file (I’m not sure whether the editor can load OBJ with MTLs)
  • use code to load the OBJ model, apply the texture and then export the textured model as GLB … which should be importable in the editor
  • map in Blender and export to GLB, then import the GLB in the editor

I managed to find how to have this render on my object with the using of TextureLoader and this code

const texture = new THREE.TextureLoader().load( "./map.jpg" );
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.rotation = Math.PI;
texture.repeat.set( 1, 1 );

Now I have to find how to configure correctly the texture to display the full image only one time, to fill the face of my object, let me know if you have the code to do this :wink:

This will make it 10 times larger

texture.repeat.set( 1/10, 1/10 );

Scale it as much as you need. After scaling you may also want to shift the image left/right and up/down. Do this with the offset property, if needed.

Is it possible to automatically adapt the size of my texture so that the image takes up the entire face of the object, can import the 3D object that I wish to load ?

I’m almost done, I found a solution for the texture image size. I just need to find how to calculate the offset, whatever the 3D object I want to load. That is my code for now :

const texture = new THREE.TextureLoader().load( "./map.jpg" );
let boxSize = new THREE.Vector3();
let measure = new THREE.Box3().setFromObject(mesh, true);
measure.getSize(boxSize);
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.flipY = false;
texture.repeat.set( 1/boxSize.x, 1/boxSize.y );
material.map = texture;
1 Like

In my case, I found a good position for my texture with this offset

texture.offset.set(0.86, 0.64);

But that is not good with another 3D model so I don’t know what is the correct formula for the offset. Does someone have an idea ?

Can someone help me to find the correct formula for the offset and/or the center please ?

There are 2 problems. One is that you need to find the bounds of the geometry. The other is that you need UVs generated as I mentioned in my first reply.
I showed how to generate arbitrary UVs, similar to Blenders “Project From View” UV generation, in an orthographic context.

To get UVs that range from 0 to 1 across the extents of the object… we need to change that UV generation to take the bounding box into account…

So instead of writing just X and Z, or X and Y as the UV, we need to normalize them with the bounding box…

So like…

let p=mesh.geometry.attributes.position.array;
let u=mesh.geometry.attributes.uv.array;
for(let i=0,j=0;i<p.length;i+=3,j+=2){
let x = p[i];
let y = p[i+1]
x = ( x - bounds.min.x ) / (bounds.max.x-bounds.min.x);
y = ( y - bounds.min.y ) / (bounds.max.y-bounds.min.y);
u[j]=x;
u[j+1]=y;
}

This should map the whole te4xture to the whole X/Y plane of the object… but then the texture will also have the objects aspect ratio… which may be stretched.

You can do the same transformation on y as you do on x if you want a square aspect ratio, (or vice versa, or pick the largest axis and normalize the other axis to that.)

Your model is weirdly done. I fixed the broken geometry and UVd it for you, also I reset the world origin and rotation to match the picture provided. So if its in a wrong place, you may need to move your model in code. Also, keep in mind you are trying to put a rectangular image to a weird shape. I have exported an example of the file. If you want to see more of your image, download blender, and adjust the UV island yourself. This will distort the projection on the model ofcourse. The UV editor should be open by default. Recommend you export as gltf, as in contains all the info in one place.

modelhelp.rar (764.4 KB)