【问题标题】:GLSL shader to support coloring and texturing支持着色和纹理的 GLSL 着色器
【发布时间】:2016-10-23 11:23:56
【问题描述】:

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

获取位置:

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

【问题讨论】:

  • 思想出错时的样子? gl_FragColor = mix(texColor, vertexColor, 0.5);?
  • @PauliNieminen - 纹理不起作用,只有颜色
  • 对。我不完全理解你原来的问题。着色器对我来说看起来不错。纹理采样无法读取值听起来像纹理未绑定到单元或 uSampler 或 vTextureCoord 未正确设置以从 javascript/vbo 传播到片段着色器。

标签: javascript glsl webgl


【解决方案1】:

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

  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>

【讨论】:

  • 非常感谢您的出色回答。无论如何 - 尝试了保利所说的,我只得到颜色部分,不明白为什么。
  • 正如你所说,它可能是程序某处的错误
  • 您检查 JavaScript 控制台是否有错误?如果您的纹理设置错误,那么它将只是 0,0,0,0,因此您将看不到纹理。当您将uUseTexture 设置为true 时,您是否至少没有看到顶点颜色?
  • 我添加了 gl.disableVertexAttribArray(shaderProgram.vertexColorAttribute);在使用纹理之前。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-04
  • 1970-01-01
  • 2012-03-05
  • 1970-01-01
  • 2013-09-17
  • 2010-10-27
  • 1970-01-01
相关资源
最近更新 更多