支持着色和纹理的 GLSL 着色器

GLSL shader to support coloring and texturing

我正在尝试编写一个同时支持颜色和纹理的着色器。
出于某种原因,我可以让它工作。
没有错误抛出,每个都完美地单独工作,

获取位置:

shaderProgram.useTextureUniform = gl.getUniformLocation(shaderProgram, "uUseTexture");

绘图时我这样更改值:

    var uUseTexture=false;
    gl.uniform1f(shaderProgram.useTextureUniform, uUseTexture);

以及 GLSL 本身:

片段:

precision mediump float;
uniform sampler2D uSampler;
varying vec2 vTextureCoord;
varying vec4 vColor;
uniform bool uUseTexture;
void main(void) {
    vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
    vec4 texColor = vec4(textureColor.rgb, textureColor.a);
    vec4 vertexColor = vColor; 
    if (!uUseTexture){
        gl_FragColor = vertexColor;
    }
    else{
        gl_FragColor = texColor; 
    }
}

顶点:

    attribute vec3 aVertexPosition;
    attribute vec3 aVertexNormal;
    attribute vec2 aTextureCoord;
    attribute vec4 aVertexColor;

    uniform mat4 uMVMatrix;
    uniform mat4 uPMatrix;
    uniform mat3 uNMatrix;

    varying vec2 vTextureCoord;
    varying vec4 vColor;


    void main(void){
        vec4 mvPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
        gl_Position = uPMatrix * mvPosition;
        vTextureCoord = aTextureCoord;
        vColor = aVertexColor;}

在我告诉你如何让你的着色器工作之前,你可能不应该那样做。你应该

  1. 制作 2 个着色器

    制作一个使用纹理的着色器和另一个使用顶点颜色的着色器。这几乎是所有专业游戏引擎都会做的。

  2. 制作一个将两种颜色相乘并将一种设置为白色的着色器

    如果你有

    gl_FragColor = vertexColor * textureColor;
    

    那么如果 textureColor1,1,1,1 那意味着你要乘以 1 所以结果只是 vertexColor。同样,如果 vertexColor1,1,1,1 然后你乘以 1 所以结果就是 textureColor

    只需制作一个像素的白色纹理即可获得白色纹理

    var tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA,
                  gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 255, 255]));
    

    然后任何时候你只希望顶点颜色将该纹理绑定到纹理 单位并告诉采样器你把它放在哪个单位

    您可能还想关闭纹理坐标

    gl.disableVertexAttribArray(texcoordLocation);
    

    当你只需要纹理颜色时,你可以这样做

    // turn off the attribute
    gl.disableVertexAttribArray(aVertexColorLocation);
    
    // set the attribute's constant value
    gl.vertexAttrib4f(aVertexColorLocation, 1, 1, 1, 1);
    

    此方法还有一个额外的好处,即您还可以同时使用纹理颜色和顶点颜色来修改纹理颜色或为纹理颜色着色。许多游戏引擎也会这样做,专门利用这种混合颜色的能力。

  3. Pauli 提到了另一种选择,即使用 mix

    uniform float u_mixAmount;
    
    gl_FragColor = mix(textureColor, vertexColor, u_mixAmount);
    

    这也可以,因为您可以在需要时将 u_mixAmount 设置为 0.0 textureColor 和 1.0 当你想要 vertexColor 但不像你的 布尔示例,您还可以在具有值的 2 种颜色之间淡入淡出 在 0.0 和 1.0 之间。例如 0.3 是 vertexColor 的 30% 和 70% 共 textureColor

其他一些事情

这一行

vec4 texColor = vec4(textureColor.rgb, textureColor.a);

没有区别
vec4 texColor = textureColor;

只是尝试你的着色器,它似乎按原样工作,这表明问题不是你的着色器,而是你代码的其他部分。

var gl = document.querySelector("canvas").getContext("webgl");
var m4 = twgl.m4;

var arrays = {
  aVertexPosition: [
    -1, -1, 0,
     1, -1, 0,
    -1,  1, 0,
     1,  1, 0,
  ],
  aVertexNormal: [
     0,  0,  1,
     0,  0,  1,
     0,  0,  1,
     0,  0,  1,
  ],
  aTextureCoord: [
     0,  0, 
     1,  0,
     0,  1,
     1,  1,
  ],
  aVertexColor: [
     1, 0, 0, 1,
     0, 1, 0, 1,
     0, 0, 1, 1,
     1, 0, 1, 1,
  ],
  indices: [
    0, 1, 2,
    2, 1, 3,
  ],
};
    
var tex = twgl.createTexture(gl, {
  format: gl.LUMINANCE,
  mag: gl.NEAREST,
  src: [224, 64, 128, 192],
});
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var programInfo = twgl.createProgramInfo(gl, ['vs', 'fs']);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
for (var i = 0; i < 2; ++i) {
  twgl.setUniforms(programInfo, {
    uMVMatrix: m4.identity(),
    uPMatrix: m4.scale(m4.translation([i === 0 ? -0.5 : 0.5, 0, 0]), [0.5, 1, 1]),
    uNMatrix: m4.identity(),
    uSampler: tex,
    uUseTexture: i === 1,
  });
  twgl.drawBufferInfo(gl, bufferInfo);
}
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/2.x/twgl-full.min.js"></script>
<script id="fs" type="not-js">
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vTextureCoord;
varying vec4 vColor;
uniform bool uUseTexture;
void main(void) {
    vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
    vec4 texColor = vec4(textureColor.rgb, textureColor.a);
    vec4 vertexColor = vColor; 
    if (!uUseTexture){
        gl_FragColor = vertexColor;
    }
    else{
        gl_FragColor = texColor; 
    }
}
</script>
<script id="vs" type="not-js">
    attribute vec3 aVertexPosition;
    attribute vec3 aVertexNormal;
    attribute vec2 aTextureCoord;
    attribute vec4 aVertexColor;

    uniform mat4 uMVMatrix;
    uniform mat4 uPMatrix;
    uniform mat3 uNMatrix;

    varying vec2 vTextureCoord;
    varying vec4 vColor;


    void main(void){
        vec4 mvPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
        gl_Position = uPMatrix * mvPosition;
        vTextureCoord = aTextureCoord;
        vColor = aVertexColor;}
</script>
<canvas></canvas>