mrdoob / three.js

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

Image Texture on Arbitrary Shapes? #2065

Closed s0235499 closed 11 years ago

s0235499 commented 12 years ago

I am a beginner on 3D development. Many thanks for any helps in advance.

My question is quite similar to the thread: https://github.com/mrdoob/three.js/issues/676

I want to generate flat surfaces what arbitrary shapes. For example, like those shapes generated in "webgl_geometry_shapes.html". I followed the "webgl_geometry_shapes.html" example:

1) create THREE.Shape(); 2) then call the extrude() method of my THREE.Shape object; 3) finally create THREE.Mesh object with my shape geometry generated from stage 2 and a single color material.

Now I have two problems:

1) I want to use an image to be projected onto the surface, for example, the rectangle image just occupies a rectangle sub-area on the shape. After some search, I guess I need to implement a UV mapping? But I am not sure where to start with and what to look into. It would be great if someone can direct me to the right sources.

2) I want to apply different textures on the 2 sides of these shapes. Again, helps really appreciated.

s0235499 commented 12 years ago

I have solved the second problem by tweaking the source code of ExtrudeGeometry. I am still looking for the solutions to the first problem.

ColasMarko commented 12 years ago

You can compute a simple planar projection mapping with this code. In this code i assume that minX, maxX, minY and maxY are the extrem coordinate of your shape (easy to compute) and my geometry only uses Face3 (no Face4 but it should be simple to adapt the code and handle this case)

var deltaX = maxX - minX;
var deltaY = maxY - minY;

var faceCount = geometry.faces.length;
var faceUvs;
var uvA = new THREE.UV( 0, 0 );
var uvB = new THREE.UV( 0, 0 );
var uvC = new THREE.UV( 0, 0 );
for( var faceIdx = 0; faceIdx < faceCount; ++faceIdx )
{
    var face = g.faces[ faceIdx ];
    var vtx = g.vertices[ face.a ];
    uvA.set( ( vtx.x - minX ) / deltaX, ( vtx.y - minY ) / deltaY );

    vtx = g.vertices[ face.b ];
    uvB.set( ( vtx.x - minX ) / deltaX, ( vtx.y - minY ) / deltaY );

    vtx = g.vertices[ face.c ];
    uvC.set( ( vtx.x - minX ) / deltaX, ( vtx.y - minY ) / deltaY );

    g.faceVertexUvs[ 0 ].push( [ uvA.clone(), uvB.clone(), uvC.clone() ] );
}
s0235499 commented 12 years ago

Hello kovleouf,

If you replied to me yesterday, I wouldn't understand what you are talking about. But after some hardwork last night, the only missing piece now is what you posted. :) Thanks a lot!.

I only use on my spare time to play with three.js. I will try your idea tonight.

s0235499 commented 12 years ago

Hi @kovleouf,

The surface made by ExtrudeGeometry is Face3 as well. The code you provided just worked fine except a small issue. ExtrudeGeometry uses the x- and y- axis for the extruded shape. The coordiante system in 2D is the same as the x-z axis in 3D but different from the x-y axis in 3D. The current projected texture is a up-side-down and mirrored image. I have look at the source code in PlaneGeometry. PlaneGeometry uses x and z axis, therefore the texture applied to a plane geometry is correct. I will try to figure it out. Thanks.

s0235499 commented 12 years ago

Problem solved by doing the following for all the 3 vertices of Fae3.

uvA.set( ( vtx.x - minX ) / deltaX, (- ( vtx.y - minY ) + deltaY ) / deltaY );

It helps to map the (x,y) coordiantes in a 2D space onto the (x, y) coordinates in a 3D space.

gandonov commented 11 years ago

Hi there,

I'm also very new to three.js, but so far it looks very promising. I want to do the exactly same thing you did, but seem to be missing something because changes made by function that was kindly given by kovleouf doesn't seem to take any effect. Perhaps I should specify something in the material?

The steps that I am taking are the following:

1.) make shape 2.) THREE.ShapeGeometry(shape) 3.) calculate MinMax 4.) call the following:

private native void mapUVs(Geometry geometry, double minX, double minY, double maxX, double maxY)/*-{
    var deltaX = maxX - minX;
    var deltaY = maxY - minY;

    var faceCount = geometry.faces.length;
    var faceUvs;
    var uvA = new $wnd.THREE.UV( 0, 0 );
    var uvB = new $wnd.THREE.UV( 0, 0 );
    var uvC = new $wnd.THREE.UV( 0, 0 );
for( var faceIdx = 0; faceIdx < faceCount; ++faceIdx )
{
    var face = geometry.faces[ faceIdx ];
    var vtx = geometry.vertices[ face.a ];
    uvA.set( ( vtx.x - minX ) / deltaX, (- ( vtx.y - minY ) + deltaY ) / deltaY );

    vtx = geometry.vertices[ face.b ];
    uvB.set( ( vtx.x - minX ) / deltaX, ( vtx.y - minY ) / deltaY );

    vtx = geometry.vertices[ face.c ];
    uvC.set( ( vtx.x - minX ) / deltaX, ( vtx.y - minY ) / deltaY );

    geometry.faceVertexUvs[0].push( [ uvA.clone(), uvB.clone(), uvC.clone() ] );

}
    console.debug(geometry);
    }-*/;

// I'm using GWT, so this is a wrapper to the whole thing, where geometry is the geometry constructed from the shape

5.) Material material = THREE.MeshBasicMaterial().map(texture).build(); 6.) Mesh mesh = THREE.Mesh(geometry, material);

For some reason step 4 takes no effect and I get following: output

and the image I'm trying to put on it is: testMesh

(image is 64x64)

Any help is greatly appreciated

Thanks, -D

mrdoob commented 11 years ago

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