mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102.19k stars 35.34k forks source link

Use image as texture #110

Closed dandrei closed 13 years ago

dandrei commented 13 years ago

I'm trying to write a function that takes an image URL as a parameter and returns a material.

How do I make it so the image is spread among all the faces of the object?

mrdoob commented 13 years ago

Could you paste the code you have so it's easier to spot what you're missing?

dandrei commented 13 years ago

So far I've been using this simple function:

function getMaterial( path )
{
var image = new Image();
var material = new THREE.MeshBasicMaterial( { map : new THREE.Texture( image ) } );
with ( { material : material } )
{
    image.onload = function()
    {
        this.loaded = true;
        material.map.image = this;
    };
}
image.src = path;

return material;
}

This works great on predefined objects such as spheres and planes but not on objects built from scratch with vertices and faces.

Like this, I mean: scope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) ); scope.faces.push( new THREE.Face3( a, b, c ) );

So for example I used the textures/metal.jpg file that came in the three.js example pack, and the whole model just has the same shade of gray as the top left part of the image. It's as if only the top left part of the image is applied on each face.

mrdoob commented 13 years ago

Are you also creating the UV for each vertex?

dandrei commented 13 years ago

The geometry is processed separately and I only try to apply materials when the mesh is created, like so: new THREE.Mesh( geometry, material );

Also tried material = new THREE.MeshBasicMaterial( { map : ImageUtils.loadTexture( path ) } );

And now:

On WebGLRenderer The models don't show up at all.

On WebGLRenderer2 If I use: textures/land_ocean_ice_cloud_2048.jpg The model is now completely white. If I use: textures/metal.jpg The model is completely grey, as before.

Is there something else I should be doing apart from creating the mesh with geometry & material as parameters? I also call updateMatrix, but that's not material-related.

dandrei commented 13 years ago

When I create the objects I just fill the arrays with vertices / faces and then call this.computeCentroids(); this.computeFaceNormals(); Should I be doing something more here?

mrdoob commented 13 years ago

Every vertex should have UV coordinates. UV coordinates anchor specific points in the texture to each vertex. With no UV coordinates there is no way to map a texture in the object/triangles.

dandrei commented 13 years ago

I hear you!

Please link me to a sample that implements that and I'll see what I can do :)

mrdoob commented 13 years ago

https://github.com/mrdoob/three.js/blob/master/src/extras/primitives/Plane.js

dandrei commented 13 years ago

Thanks, that was of great help! My .OBJ file reader now also reads the UV data included in the file.

What if the OBJ file doesn't contain UV data and I just want to take any image and slap it on top of the model? I'm not interested in fitting particular images to the model (as in matching hair with the top of the head and stuff like that). I just want the model to be covered by the image in a way that will keep the image recognisable.

Do I need to calculate the UV values when I read the geometry or I can do something else? Thanks.

Extra question: how do I change the material on an object once the object is already in the scene? Can I do that?

mrdoob commented 13 years ago

You need to create those UV coords by hand. Like you can get the boundaries of the object from the front side and use that to relatively assign UV coords to each vertex (for projecting the texture from the front). Same thing with cylindrical projection, etc...

Re material: You should be able to do mesh.materials[ 0 ] = new_material;