Webgl 为什么我的着色器不适用于梯形多边形?

Webgl 为什么我的着色器不适用于梯形多边形?,webgl,shader,projection-matrix,Webgl,Shader,Projection Matrix,我需要在梯形多边形上绘制纹理的一部分。老式的假3D比赛游戏,道路是由这些梯形组成的,我想在它们上应用纹理 但是纹理看起来是错误的,比如,如果形成梯形的两个三角形中的每一个都是平行线的一半,那么它们都有不同的水平倾斜,而不是全局透视变换 在寻找解决方案时,我发现这个问题很常见,原因是两个三角形不相等,着色器是二维的。根据我的发现,尤其是这个答案:,我试图修复我的着色器。但这并没有改变什么 My shaders : (copied from webglfundamentals.com, edite

我需要在梯形多边形上绘制纹理的一部分。老式的假3D比赛游戏,道路是由这些梯形组成的,我想在它们上应用纹理

但是纹理看起来是错误的,比如,如果形成梯形的两个三角形中的每一个都是平行线的一半,那么它们都有不同的水平倾斜,而不是全局透视变换

在寻找解决方案时,我发现这个问题很常见,原因是两个三角形不相等,着色器是二维的。根据我的发现,尤其是这个答案:,我试图修复我的着色器。但这并没有改变什么

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 );

错误在哪里?

查看链接到的示例,您需要提供3D纹理坐标。所以不是像这样的UV

 0, 0,
 0, 1,
 1, 0,
 1, 1,
它们需要分别乘以trapizoid点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);
}
范例

"严格使用",; /*全局twgl,m4,requestAnimationFrame,文档*/ 常数m4=twgl.m4; const gl=document.querySelector'canvas.getContext'webgl'; 常数vs=` 属性向量4位置; 属性向量2 texcoord; 均匀mat4u_矩阵; 可变vec3 v_texcoord; 真空总管{ gl_位置=u_矩阵*位置; v_texcoord=vec3texcoord.xy,1*absposition.x; } `; 常数fs=` 高精度浮点; 可变vec3 v_texcoord; 均匀采样2d-tex; 真空总管{ gl_FragColor=纹理2dprojtex,v_texcoord; } `; //编译着色器、链接、查找位置 const programInfo=twgl.createProgramInfogl[vs,fs]; //制作一些顶点数据 常数W0=1; 常数W1=0.5; const bufferInfo=twgl.createBufferInfoFromArraysgl{ 职位:{ NUM组件:2, 数据:[ -1, -1, 1, -1, -.5, 1, 1, -1, .5, 1, -.5, 1, ], }, 特克斯库尔德:[ 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, ], }; 常量tex=twgl.createTexturegl{ src:[ 0xC0,0x80,0xC0,0x80, 0x80,0xC0,0x80,0xC0, 0xC0,0x80,0xC0,0x80, 0x80,0xC0,0x80,0xC0, ], 格式:gl.亮度, minMag:gl, }; 函数渲染时间{ 时间*=0.001; gl.useprograminfo.program; //调用gl.bindBuffer、gl.enableVertexAttributeArray、gl.VertexAttributePointer twgl.setBuffersAndAttributesgl、programInfo、bufferInfo; //调用gl.activeTexture、gl.bindTexture、gl.uniformXXX twgl.setUniformsprogramInfo{ u_矩阵:m4.rotationZtime, }; //调用gl.DrawArray或gl.drawElements twgl.drawBufferInfo,bufferInfo; requestAnimationFramerender; } requestAnimationFramerender;
只是好奇。什么是一个老式的假3D赛车游戏的例子?我问这个问题是因为我想象的是缩放的四边形,比如on或,但我不记得哪些游戏使用梯形。至于你的代码,你没有显示你的纹理坐标,但是你链接到的答案使用了3d纹理坐标,但是你上面的代码正在将2传递给gl.VertexAttributePointer以获得纹理坐标,因此你没有将3d纹理坐标传递给着色器。我没有很好地解释我自己。我不能使用老游戏的扫描线技巧,这就是为什么我想用梯形来代替,我希望结果应该很相似。我将其更改为3,但id无效。您链接到的示例使用3D纹理坐标,但您仅使用2D纹理坐标。您需要为每个纹理坐标添加正确的第三个坐标,就像链接到的答案一样。