Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding textures to a custom Geometry #1741

Closed
alexandrew opened this issue Apr 17, 2012 · 11 comments
Closed

Adding textures to a custom Geometry #1741

alexandrew opened this issue Apr 17, 2012 · 11 comments
Labels

Comments

@alexandrew
Copy link

Hi,
I'm new to Three.js and I have a problem with textures. I've already made a custom THREE.Geometry() by creating vertices and faces and it works well with a MeshNormalMaterial. But I have no idea on how to add a texture (in this case, an image) on each Face4. I'd like to put one different image per face. I tried to add a texture while creating each THREE.Face4, I tried to put a materials array when I create my final Mesh but it still doesn't work :( What's the right way? Thanks in advance!

PS : I have no problem while loading the textures, I've made other tests with THREE.CubeGeometry() and it works well...

var materialsArray=[];
var sphere = new THREE.Geometry();

for (var i=0;i<10;i++){

    //I create my texture

    var image=new Image();
    image.src = 'lezard.png';
    var texture = new THREE.Texture( image );
    image.tex = texture;
    image.tex.needsUpdate = true;
    var material = new THREE.MeshBasicMaterial( {color:0xffffff, map: texture } );
    materialsArray.push(material);

    // I create 4 vertices with coordinates from an external file (there is no problem here)

    var v1 = new THREE.Vector3(Coo[i][0]['x']*500,Coo[i][0]['y']*500,Coo[i][0]['z']*500);
    var v2 = new THREE.Vector3(Coo[i][1]['x']*500,Coo[i][1]['y']*500,Coo[i][1]['z']*500);
    var v3 = new THREE.Vector3(Coo[i][2]['x']*500,Coo[i][2]['y']*500,Coo[i][2]['z']*500);
    var v4 = new THREE.Vector3(Coo[i][3]['x']*500,Coo[i][3]['y']*500,Coo[i][3]['z']*500);

    // I add them to my custom THREE.Geometry() object

    sphere.vertices.push(new THREE.Vertex(v1));
    sphere.vertices.push(new THREE.Vertex(v2));
    sphere.vertices.push(new THREE.Vertex(v3));
    sphere.vertices.push(new THREE.Vertex(v4));

    // and i create the face 
    sphere.faces[i]=new THREE.Face4( i*4+0, i*4+1, i*4+2,i*4+3) ;

    //sphere.faces[i].materials=material;  --doesn't work
}

sphere.computeFaceNormals();
sphere.computeCentroids();
sphere.computeVertexNormals();

// I finally add the new mesh to the scene

//var object = new THREE.Mesh(sphere, materialsArray);                                
//var mesh = new THREE.Mesh(object,new THREE.MeshFaceMaterial());  -- doesn't work 

var object = new THREE.Mesh(sphere, new THREE.MeshFaceMaterial());
object.doubleSided = true;
scene.add(object);
@arcanis
Copy link
Contributor

arcanis commented Apr 17, 2012

Look at the code of CubeGeometry.js, it should help you.

If think you're searching for this line :
https://github.com/mrdoob/three.js/blob/master/src/extras/geometries/CubeGeometry.js#L126

@mrdoob
Copy link
Owner

mrdoob commented Apr 17, 2012

@alexandrew You just need to UVs.

@mrdoob
Copy link
Owner

mrdoob commented Apr 17, 2012

It should be something along the lines of this...

var sphere = new THREE.Geometry();
var material = new THREE.MeshBasicMaterial( {color:0xffffff, map: THREE.ImageUtils.loadTexture( 'lezard.png' } );

for (var i=0;i<10;i++){

    // I create 4 vertices with coordinates from an external file (there is no problem here)

    var v1 = new THREE.Vector3(Coo[i][0]['x']*500,Coo[i][0]['y']*500,Coo[i][0]['z']*500);
    var v2 = new THREE.Vector3(Coo[i][1]['x']*500,Coo[i][1]['y']*500,Coo[i][1]['z']*500);
    var v3 = new THREE.Vector3(Coo[i][2]['x']*500,Coo[i][2]['y']*500,Coo[i][2]['z']*500);
    var v4 = new THREE.Vector3(Coo[i][3]['x']*500,Coo[i][3]['y']*500,Coo[i][3]['z']*500);

    // I add them to my custom THREE.Geometry() object

    sphere.vertices.push(new THREE.Vertex(v1));
    sphere.vertices.push(new THREE.Vertex(v2));
    sphere.vertices.push(new THREE.Vertex(v3));
    sphere.vertices.push(new THREE.Vertex(v4));

    // and i create the face 
    sphere.faces[i]=new THREE.Face4( i*4+0, i*4+1, i*4+2,i*4+3) ;

    // add uvs
    sphere.faceVertexUvs[ 0 ].push( [
        new THREE.UV( 0, 0 ),
        new THREE.UV( 0, 1 ),
        new THREE.UV( 1, 1 ),
        new THREE.UV( 1, 0 )
    ] );
}

sphere.computeFaceNormals();
sphere.computeCentroids();
sphere.computeVertexNormals();

var object = new THREE.Mesh(sphere, material);
object.doubleSided = true;
scene.add(object);

@mrdoob
Copy link
Owner

mrdoob commented Apr 17, 2012

Also, bear in mind that Vertex is now gone in r49dev.

@alexandrew
Copy link
Author

Thank you for the quick answer! Is it the same trick if i want to create one different material per face (with one different image)? Because this is what i have to do... In my case, I load several images that I can't merge into one UV map (too numerous), I have to deal with this constraint. Thus, I'm not sure where i have to put my textures and if these Uvs need to be changed...

var sphere = new THREE.Geometry();
var materialsArray=[]
for (var i=0;i<10;i++){

    //I create my texture
    //I load one different image for each loop

    var material = new THREE.MeshBasicMaterial( {color:0xffffff, map: THREE.ImageUtils.loadTexture( 'picture'+i+'.png' } );
    materialsArray.push(material);

    //create vertices
    //create the face
    // add UVs
    sphere.faceVertexUvs[ 0 ].push( [
        new THREE.UV( 0, 0 ),
        new THREE.UV( 0, 1 ),
        new THREE.UV( 1, 1 ),
        new THREE.UV( 1, 0 )
    ] );
}
//compute functions
var object = new THREE.Mesh(sphere, materialsArray);
scene.add(object);

@arcanis
Copy link
Contributor

arcanis commented Apr 17, 2012

You have to set a materialIndex for each vertex, and sphere.materials must be the effective material list.

Then you have to use an instance of MeshFaceMaterial as mesh material.

@alexandrew
Copy link
Author

I found it! Thanks arcanis, I took your first advice and I had already used a MeshFaceMaterial. Everything was ok except for the material array. I don't know why but it doesn't work when I push a new material in sphere.materials on each loop, and it works like a charm when I push the new material in an array that I assign to sphere.materials at the end of the loop...

This doesn't work :

for(var i=0;i<10;i++){
    //vertices, face and Uvs
    sphere.faces[i].materialIndex=i;
    sphere.materials.push(new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture( 'picture'+i+'.png',overdraw:true} ));
}
var object = new THREE.Mesh(sphere, new THREE.MeshFaceMaterial());
scene.add(object);

But this works well!

var materialArray=[];
for(var i=0;i<10;i++){
    //vertices, face and Uvs
    sphere.faces[i].materialIndex=i;
    var material = new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture( 'picture'+i+'.png',overdraw:true} );
    materialArray.push(material);
}
sphere.materials = materialsArray;
var object = new THREE.Mesh(sphere, new THREE.MeshFaceMaterial());
scene.add(object);

It's a little bit weird because i don't see a big difference ^^.
Thank you both!

@vala
Copy link

vala commented Dec 2, 2012

Hi there !

I just tried the above example to create one texture per face of a Mesh with CubeGeometry and it didn't work the exact same way as the proposed one.

I don't know if it's because I don't use a custom Geometry (don't see why it would change ?), but the code I used looks like this :

var materialArray=[];
for(var i=0;i<6;i++){
    var material = new THREE.MeshBasicMaterial({ map: THREE.ImageUtils.loadTexture( 'picture'+i+'.png') ,overdraw:true } );
    materialArray.push(material);
}

var cubeGeometry = new THREE.CubeGeometry(256, 256, 256, 1, 1, 1),
    faceMaterial = new THREE.MeshFaceMaterial();

// I had to add the materialArray directly to the MeshFaceMaterial instance, 
// instead of adding them to the geometry
faceMaterial.materials = materialArray;

var object = new THREE.Mesh(sphere, faceMaterial);
scene.add(object);

Since it took me some time to find a way to figure out how to make it work, and every resource I came across wasn't working, I asked myself if it because of something new or wrong... well if you could help me understanding the reasons why I had to use another strategy.

Thanks in advance

@mrdoob
Copy link
Owner

mrdoob commented Dec 2, 2012

@vala yep, this was a change from r52 to r53:
https://github.com/mrdoob/three.js/wiki/Migration

@danielsabinasz
Copy link

Hi everyone,

I am having the same problem as the thread starter. I am using r55. The faces with the texture material just don't appear. The faces with the simple color material do however appear. If I replace the material generated from the roofTexture with a simple color material, the faces using that material do appear correctly as well.

Here is the relevant part of my code:

var geom = new THREE.Geometry();

// Load the roof texture
var roofTexture = new THREE.ImageUtils.loadTexture('gfx/textures/roof.jpg');

// Let the roof texture repeat itself
roofTexture.wrapS = roofTexture.wrapT = THREE.RepeatWrapping;
roofTexture.repeat.set(10, 10);

// Materials
var materialArray = [];
materialArray.push(new THREE.MeshLambertMaterial({color: 0xD3E3F0 }));
materialArray.push(new THREE.MeshLambertMaterial({map: roofTexture}));

// Base edges
var edge0 = new THREE.Vector2(obj.ridgeLength/2, -obj.buildingDepth/2);
var edge1 = new THREE.Vector2(obj.ridgeLength/2, obj.buildingDepth/2);
var edge2 = new THREE.Vector2(-obj.ridgeLength/2, obj.buildingDepth/2);
var edge3 = new THREE.Vector2(-obj.ridgeLength/2, -obj.buildingDepth/2);

// Floor
geom.vertices.push(new THREE.Vector3(edge0.x, -1, edge0.y));
geom.vertices.push(new THREE.Vector3(edge1.x, -1, edge1.y));
geom.vertices.push(new THREE.Vector3(edge2.x, -1, edge2.y));
geom.vertices.push(new THREE.Vector3(edge3.x, -1, edge3.y));

// Eave
geom.vertices.push(new THREE.Vector3(edge0.x, obj.eaveHeight, edge0.y));
geom.vertices.push(new THREE.Vector3(edge1.x, obj.eaveHeight, edge1.y));
geom.vertices.push(new THREE.Vector3(edge2.x, obj.eaveHeight, edge2.y));
geom.vertices.push(new THREE.Vector3(edge3.x, obj.eaveHeight, edge3.y));

// Ridge
geom.vertices.push(new THREE.Vector3(obj.ridgeLength/2, obj.ridgeHeight, 0));
geom.vertices.push(new THREE.Vector3(-obj.ridgeLength/2, obj.ridgeHeight, 0));


// Ground
geom.faces.push( new THREE.Face4(0, 0, 0, 0) );

// Front
geom.faces.push( new THREE.Face4(0, 3, 7, 4) );

// Left side
geom.faces.push( new THREE.Face4(0, 4, 5, 1) );

// Back
geom.faces.push( new THREE.Face4(1, 5, 6, 2) );

// Right side
geom.faces.push( new THREE.Face4(2, 6, 7, 3) );

// Left triangle
geom.faces.push( new THREE.Face3(4, 8, 5));

// Right triangle
geom.faces.push( new THREE.Face3(6, 9, 7));

// Front roof
geom.faces.push( new THREE.Face4(7, 9, 8, 4) );

// Back roof
geom.faces.push( new THREE.Face4(5, 8, 9, 6) );

// Assign materials to the faces
geom.faces[0].materialIndex = 0;
geom.faces[1].materialIndex = 0;
geom.faces[2].materialIndex = 0;
geom.faces[3].materialIndex = 0;
geom.faces[4].materialIndex = 0;
geom.faces[5].materialIndex = 0;
geom.faces[6].materialIndex = 0;
geom.faces[7].materialIndex = 1;
geom.faces[8].materialIndex = 1;

geom.computeFaceNormals();

obj.house = new THREE.Mesh( geom, new THREE.MeshFaceMaterial(materialArray) );
obj.house.doubleSided = true;
obj.house.castShadow = true;
obj.sun.shadowDarkness = 1.0;
obj.scene.add(obj.house);

What am I doing wrong?

Thanks in advance!

Daniel

@WestLangley
Copy link
Collaborator

As stated in the guidelines, help requests should be made in stackoverflow. This board is for bugs and feature requests.

You need to specify UVs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants