How to map texture on a custom non square quad in THREE JS

2.4k views Asked by At

playing around with ThreeJS, i encoutered a classic problem of non square quad texturing : http://www.xyzw.us/~cass/qcoord/

Problem is ThreeJS only let you set texture coordinates with a vec2 (for what i know ..) And after spending hours on this, and finally found a working solution, i wanted to share it with the community, and maybe get some better ideas ? So here is the code:

First, the javascript to make my Quad using three JS:

var planeGeom = new THREE.Geometry();
planeGeom.vertices.push(new THREE.Vector3(0, 0, 10));
planeGeom.vertices.push(new THREE.Vector3(10, 0, 10));
planeGeom.vertices.push(new THREE.Vector3(20, 0,0));
planeGeom.vertices.push(new THREE.Vector3(-10, 0, 0));

//create the 2 faces , maybe i should play with CW or CCW order... ;)
planeGeom.faces.push(new THREE.Face3(0,1,3));
planeGeom.faces.push(new THREE.Face3(1,2,3));

//Compute widths ratio
var topWidth = Math.abs(Plane.TR.x - Plane.TL.x);
var bottomWidth = Math.abs(Plane.BR.x - Plane.BL.x);
var ratio = topWidth / bottomWidth;

//create UV's  as barely explained in the link above (www.xyzw.us)
 var UVS = [
    new THREE.Vector2(0, ratio),
    new THREE.Vector2(0, 0),
    new THREE.Vector2(1.0, 0),
    new THREE.Vector2(ratio, ratio)
];

 //faceVertexUvs[materialID] [face index] [vertex index among face]
planeGeom.faceVertexUvs[0][0] = [UVS[0],UVS[1],UVS[3]];
planeGeom.faceVertexUvs[0][1] = [UVS[1],UVS[2],UVS[3]];

//load the image
var checkerTexture = THREE.ImageUtils.loadTexture('./resources/images/checker_largeColor.gif');

//Now create custom shader parts
customUniforms =
{
    uSampler: { type: "t", value: checkerTexture },
};

var customMaterial = new THREE.ShaderMaterial(
    {
        uniforms: customUniforms,
        vertexShader:   document.getElementById( 'vertexShader').textContent,
        fragmentShader: document.getElementById( 'fragmentShader').textContent,
        side: THREE.DoubleSide
    }   );


//create the mesh with the custom geometry and material
var planeMesh = new THREE.Mesh(planeGeom, customMaterial);

//add the object to the threeJS scene
this.m_Scene.add(planeMesh);

and now the custom shader code:

Vertex shader:

varying vec4 textureCoord;

        void main()
        {
            //here i reCreate the Vec4 i would have liked to have in threeJS
            textureCoord = vec4(uv,0.0, 1.0);
            if(uv.y != 0.0)
            {
                textureCoord.w *= (uv.y);
            }

            gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }

and the fragment shader:

uniform sampler2D uSampler;
        varying vec4 textureCoord;

        void main()
        {
            gl_FragColor  = texture2D(uSampler, vec2(textureCoord.x/textureCoord.w, textureCoord.y/textureCoord.w));
        }

voilaaa. I hope it could help some, or maybe myself in a few years... ;)

0

There are 0 answers