将颜色从JavaScript传递到片段着色器

eCh*_*g00 2 webgl

我目前正在学习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;
}
Run Code Online (Sandbox Code Playgroud)

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

gma*_*man 5

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

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

您有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,
    ]);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 关闭a_Color属性并提供一个恒定值

    gl.disableVertexAtttibArray(a_Color);
    gl.vertexAttrib4f(a_Color, 0, 0, 1, 1);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用制服而不是属性+变化

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

    precision highp float;
    uniform vec4 u_Color;
    void main() {
      gl_FragColor = u_Color;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    现在,您可以使用

    在初始化时间

    // Lookup the location
    var u_colorLocation = gl.getUniformLocation(program, "u_Color");
    
    Run Code Online (Sandbox Code Playgroud)

    在渲染时

    // Set the uniform
    gl.uniform4f(u_colorLocation, 0, 0, 1, 1);
    
    Run Code Online (Sandbox Code Playgroud)

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

其他事宜:

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

initShader(...);
gl.getAttribLocation(gl.program, ...)
Run Code Online (Sandbox Code Playgroud)

你可能想要

var program = initShader(...);
gl.getAttribLocation(program, ...)
Run Code Online (Sandbox Code Playgroud)

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

您也正在使用precision highp float。在许多手机上都无法使用。除非您确定需要,highp否则最好使用mediump