为什么我的着色器不能用于梯形多边形? [英] Why don't my shaders work for trapezoids polygons?

查看:227
本文介绍了为什么我的着色器不能用于梯形多边形?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 the texture appears wrong, like if each of the two triangles forming a trapezoid are half of a parrallelogram instead, they have each a different horizontal skewing, not a global perspective transformation.

在寻找解决方案时,我看到此问题很常见,原因是两个三角形不相等且着色器为2D.根据我的发现,尤其是这个答案: https://stackoverflow.com/a/25239021/3666866 ,我尝试了修复我的着色器.但这并没有改变任何东西...

Searching for a solution I see that this problem is common and the reason why is that the two triangles are not equal and the shader is 2D. From what I found, and especially this answer : https://stackoverflow.com/a/25239021/3666866 , I tried to fix my shader. But it did not change anything...

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纹理坐标.因此,而不是像

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,

它们需要分别乘以梯形点的X坐标的绝对值,然后将X的绝对值作为第三坐标.

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,

这最终以相同的纹理坐标结束,因为texture2DProj将每个坐标的xy除以z,但它会更改纹理坐标的插值方式.

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

示例

'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>

这篇关于为什么我的着色器不能用于梯形多边形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆