【问题标题】:Passing color to fragment shader from Javascript从 Javascript 将颜色传递给片段着色器
【发布时间】:2021-07-30 04:20:14
【问题描述】:

我目前正在学习 webgl 并且有一个问题。 我正在尝试制作一个三角形并将颜色信息从 js 文件传递​​到片段着色器中。以下是我的js代码:

var VSHADER_SOURCE = 
    'attribute vec4 a_Position;\n'+
    'attribute vec4 a_Color;\n'+
    'varying vec4 v_Color;\n'+
    'void main(){\n'+
        'gl_Position = a_Position;\n'+
        'v_Color = a_Color;\n'+
    '}\n';


var FSHADER_SOURCE = 
    'precision highp float;\n'+
    'varying vec4 v_Color;\n'+
    'void main() {\n'+
        'gl_FragColor = v_Color;\n'+
    '}\n';

function main(){
    var canvas = document.getElementById('webgl');
    var gl = getWebGLContext(canvas);
    if(!gl){
        console.log('Error!');
        return;
    }
    //Init shaders.
    if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)){
        console.log('Error!');
        return;
    }
    var vertices = new Float32Array([-0.8, -0.8, 0.8, -0.8, 0.0, 0.8]);
    var color = new Float32Array([0.0, 0.0, 1.0, 1.0]);
    var buffer_object = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer_object);
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(a_Position);

    var color_object = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, color_object);
    gl.bufferData(gl.ARRAY_BUFFER, color, gl.STATIC_DRAW);
    var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
    gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(a_Color);

    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);


    return 0;
}

这必须创建一个蓝色三角形,但我唯一看到的是一个充满黑色的画布。谁能告诉我缺少什么?我创建了两个缓冲区对象,一个用于顶点,另一个用于颜色。

【问题讨论】:

    标签: javascript webgl


    【解决方案1】:

    您的示例存在很多问题,但是...具体问题。

    您只为第一个顶点提供颜色。

    您有 3 个顶点,但只有 1 种颜色。你应该得到一个错误。 您检查 JavaScript 控制台是否有错误?

    你有 3 个选项来解决这个问题

    1. 为每个顶点提供一种颜色

      new Float32Array([
        0.0, 0.0, 1.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
      ]);
      
    2. 关闭 a_Color 属性并提供一个常量值

      gl.disableVertexAtttibArray(a_Color);
      gl.vertexAttrib4f(a_Color, 0, 0, 1, 1);
      
    3. 使用统一而不是属性+变化

      删除a_Colorv_color 的所有引用,取而代之的是 片段着色器是

      precision highp float;
      uniform vec4 u_Color;
      void main() {
        gl_FragColor = u_Color;
      }
      

      现在你可以设置颜色了

      在初始化时

      // Lookup the location
      var u_colorLocation = gl.getUniformLocation(program, "u_Color");
      

      在渲染时

      // Set the uniform
      gl.uniform4f(u_colorLocation, 0, 0, 1, 1);
      

    如果您选择 #2,您可能会遇到另一个问题,即您会收到未启用属性 0 的警告,因为至少在我的计算机上,a_Color 已分配给属性 0。关闭它意味着它必须被模拟,这很慢。解决方案是通过 链接程序之前调用 gl.bindAttribLocation 来确保 a_Position 在属性 0 中。

    其他问题:

    您的 initShader 函数显然正在创建一个程序并将其附加到 WebGLRenderContext (gl.program)。大多数 WebGL 项目都有许多着色器程序,因此最好只返回程序。换句话说,而不是

    initShader(...);
    gl.getAttribLocation(gl.program, ...)
    

    你可能想要

    var program = initShader(...);
    gl.getAttribLocation(program, ...)
    

    您需要修复 initShader 以便它返回创建的程序,而不是将其破解到 WebGLRenderingContext。

    您也在使用precision highp float。这在许多手机上都行不通。除非您确定需要highp,否则最好使用mediump

    【讨论】:

    • 谢谢。你帮了我。 :)
    猜你喜欢
    • 2014-06-27
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    相关资源
    最近更新 更多