【问题标题】:Why don't my shaders work for trapezoids polygons?为什么我的着色器不适用于梯形多边形?
【发布时间】:2019-11-16 19:10:33
【问题描述】:

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

但是纹理看起来是错误的,就像形成梯形的两个三角形中的每一个都是平行四边形的一半,它们各自具有不同的水平倾斜,而不是全局透视变换。

寻找解决方案我发现这个问题很常见,原因是两个三角形不相等并且着色器是二维的。根据我的发现,尤其是这个答案: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 );

哪里出错了?

【问题讨论】:

  • 只是好奇。什么是老式假 3D 赛车游戏的例子?我之所以问,是因为我在想象像 OutrunPower Drift 这样的缩放四边形,但我不记得哪些游戏使用了梯形。
  • 至于您的代码,您没有显示纹理坐标,但您链接到的答案使用 3d 纹理坐标,但您上面的代码将 2 传递给 gl.vertexAttribPointer 以获得纹理坐标,所以您不将 3d 纹理坐标传递给着色器。
  • 我没有很好地解释自己。我不能使用旧游戏相同的扫描线技巧,这就是为什么我想使用梯形,结果应该看起来很相似(我希望)。我把它改成了 3 但 id 没有效果。
  • 您链接到的示例使用 3D 纹理坐标,但您仅使用 2D 纹理坐标。您需要为每个纹理坐标添加正确的第三个坐标,就像您链接到的答案一样。

标签: webgl shader projection-matrix


【解决方案1】:

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

这样的UV
 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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-11
    相关资源
    最近更新 更多