我需要在梯形多边形上绘制纹理的一部分。 (老式的假3D赛车游戏,道路是由这些梯形构成的,我想在其上应用纹理。)
但是纹理似乎是错误的,例如,如果形成梯形的两个三角形中的每个都是平行四边形的一半,那么它们每个都有不同的水平倾斜,而不是全局透视变换。
在寻找解决方案时,我看到此问题很常见,原因是两个三角形不相等,并且着色器为2D。根据发现的内容,尤其是这个答案:https://stackoverflow.com/a/25239021/3666866,我尝试修复着色器。但这并没有改变任何东西...
My shaders : (copied from webglfundamentals.com, edited according to https://stackoverflow.com/a/25239021/3666866)
<script id="3d-vertex-shader" type="x-shader/x-vertex">
attribute vec4 a_position ;
//attribute vec2 a_texcoord ;
attribute vec4 a_texcoord ;
uniform mat4 u_matrix ;
//varying vec2 v_texcoord ;
varying vec4 v_texcoord ;
void main() {
gl_Position = u_matrix * a_position ;
v_texcoord = a_texcoord ;
}
</script>
<script id="3d-fragment-shader" type="x-shader/x-fragment">
precision mediump float ;
//varying vec2 v_texcoord ;
varying vec4 v_texcoord ;
uniform sampler2D u_texture ;
void main() {
//gl_FragColor = texture2D(u_texture, v_texcoord) ;
gl_FragColor = texture2DProj( u_texture , v_texcoord ) ;
}
</script>
code :
gl_.positionLocation = gl.getAttribLocation( gl_.program, "a_position" );
gl_.texcoordLocation = gl.getAttribLocation( gl_.program, "a_texcoord" );
gl.matrixLocation = gl.getUniformLocation( gl_.program, "u_matrix" );
gl.textureLocation = gl.getUniformLocation( gl_.program, "u_texture" );
gl_.positionBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, gl_.positionBuffer );
var positions = new Float32Array(
[
-1.5, -0.5, 0.5,
1.5, -0.5, 0.5,
-0.5, 0.5, 0.5,
-0.5, 0.5, 0.5,
1.5, -0.5, 0.5,
0.5, 0.5, 0.5,
]);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
gl_.texcoordBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, gl_.texcoordBuffer );
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(
[
0.25, 0 ,
0.5 , 0 ,
0.25, 0.5,
0.25, 0.5,
0.5 , 0 ,
0.5 , 0.5,
]),
gl.STATIC_DRAW);
The render code :
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.bindBuffer( gl.ARRAY_BUFFER, positionBuffer );
gl.vertexAttribPointer(positionLocation,3,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray( texcoordLocation );
gl.bindBuffer( gl.ARRAY_BUFFER, texcoordBuffer );
gl.vertexAttribPointer(texcoordLocation,3,gl.FLOAT,false,0,0);
let projectionMatrix = m4.perspective( fieldOfViewRadians, aspect, 1, 2000);
let viewProjectionMatrix = m4.multiply( projectionMatrix, viewMatrix );
let matrix = m4.xRotate( viewProjectionMatrix, modelXRotationRadians );
gl.uniformMatrix4fv( matrixLocation , false , viewProjectionMatrix );
gl.uniform1i( textureLocation , 0 );
gl.drawArrays(gl.TRIANGLES, 0, 6 * 1 );
错误在哪里?
答案 0 :(得分:1)
查看链接到的示例,您需要提供3D纹理坐标。因此,而不是像
0, 0,
0, 1,
1, 0,
1, 1,
它们需要分别乘以梯形点的X坐标的绝对值,然后将X的绝对值作为第三坐标。
0 * X0, 0 * X0, X0,
0 * X1, 1 * X1, X1,
1 * X2, 0 * X2, X2,
1 * X3, 1 * X3, X3,
这最终以相同的纹理坐标结束,因为texture2DProj
将每个坐标的xy
除以z
,但是它改变了如何插入纹理坐标。
您可以通过手动提供这些纹理坐标并将其放在缓冲区中来提供这些纹理坐标,也可以通过在顶点着色器中对其进行计算来实现
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);
}
示例
'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);
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>