I need to draw parts of a texture on trapezoids polygons. (old school fake-3D race game, the road is made of these trapezoids and I want to apply a texture on them.)
But
Looking at the examples you linked to you need to provide 3D texture coordinates. So instead of UVs like
0, 0,
0, 1,
1, 0,
1, 1,
They need to each be multiplied by the absolute value of the X coordinate of the trapizoid's points and then that absolute value of X needs to be the 3rd coordinate
0 * X0, 0 * X0, X0,
0 * X1, 1 * X1, X1,
1 * X2, 0 * X2, X2,
1 * X3, 1 * X3, X3,
This ends up with the same texture coordinates because texture2DProj
divides the xy
of each coordinate by z
but it changes how the texture coordinate is interpolated.
You can provide that those texture coordinates by supplying them manually and putting them in a buffer or you can do it by calculating them in the vertex shader
attribute vec4 position;
attribute vec2 texcoord;
uniform mat4 u_matrix;
varying vec3 v_texcoord;
void main() {
gl_Position = u_matrix * position;
v_texcoord = vec3(texcoord.xy, 1) * abs(position.x);
}
example
'use strict';
/* global twgl, m4, requestAnimationFrame, document */
const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
attribute vec2 texcoord;
uniform mat4 u_matrix;
varying vec3 v_texcoord;
void main() {
gl_Position = u_matrix * position;
v_texcoord = vec3(texcoord.xy, 1) * abs(position.x);
}
`;
const fs = `
precision highp float;
varying vec3 v_texcoord;
uniform sampler2D tex;
void main() {
gl_FragColor = texture2DProj(tex, v_texcoord);
}
`;
// compile shader, link, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// make some vertex data
const W0 = 1;
const W1 = 0.5;
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-1, -1,
1, -1,
-.5, 1,
1, -1,
.5, 1,
-.5, 1,
],
},
texcoord: [
0, 0,
1, 0,
0, 1,
1, 0,
1, 1,
0, 1,
],
});
const tex = twgl.createTexture(gl, {
src: [
0xC0, 0x80, 0xC0, 0x80,
0x80, 0xC0, 0x80, 0xC0,
0xC0, 0x80, 0xC0, 0x80,
0x80, 0xC0, 0x80, 0xC0,
],
format: gl.LUMINANCE,
minMag: gl.NEAREST,
});
function render(time) {
time *= 0.001;
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
// calls gl.activeTexture, gl.bindTexture, gl.uniformXXX
twgl.setUniforms(programInfo, {
u_matrix: m4.rotationZ(time),
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);