Opengl es WebGL-设置属性/制服的位置示例

Opengl es WebGL-设置属性/制服的位置示例,opengl-es,webgl,fragment-shader,vertex-shader,Opengl Es,Webgl,Fragment Shader,Vertex Shader,我已经看过几个WebGL示例/教程,其中调用了gl.getAttributeLocation()或gl.getUniformLocation()等。然而,这些都在演示/教程场景中 问题/担忧在于: 例如,gl.getAttributeLocation将字符串作为第二个参数。这是着色器代码中变量的名称 例如: var a_Position = gl.getAttribLocation(gl.program, 'a_Position'); 对我来说,这似乎有点糟糕,因为如果我碰巧稍微更改了着色器代

我已经看过几个WebGL示例/教程,其中调用了gl.getAttributeLocation()或gl.getUniformLocation()等。然而,这些都在演示/教程场景中

问题/担忧在于: 例如,gl.getAttributeLocation将字符串作为第二个参数。这是着色器代码中变量的名称

例如:

var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
对我来说,这似乎有点糟糕,因为如果我碰巧稍微更改了着色器代码(比如变量名),那么它可能会导致各种各样的麻烦,因为我必须在引用更改变量名的任何地方进行重构

我希望我能把我的担忧表达出来。请让我知道,如果这是不清楚的,我会尝试详细说明一些

问题: 我是一名Opengl ES/WebGL初学者,所以我知道我肯定错过了一些东西。有经验的程序员如何将着色器代码中的变量名与其应用程序代码相关联


谢谢

这个想法是以某种方式将所有属性和制服组织在一个地方

我将用一个例子向你展示他们是如何做到这一点的。以下是完整的源代码,我只展示其中的一部分:

attributes = {
    displacement: { type: 'f', value: [] }
};

uniforms = {

    amplitude: { type: "f", value: 1.0 },
    color:     { type: "c", value: new THREE.Color( 0xff2200 ) },
    texture:   { type: "t", value: THREE.ImageUtils.loadTexture( "img.jpg")
};
所以,开发人员通过指定名称(只写一次,所以您不需要关心名称的多个版本)、变量类型(f-float、c-color、t-texture等)和变量值来设置他想要使用的制服和属性

所以你在一个地方创建属性/制服,一次,就这样。引擎还可以自动添加几个其他属性/一致性(在本例中,它可以这样做,用于顶点的位置和顶点的法线等,但在代码中的任何地方都看不到(如果需要,可以覆盖该行为))

引擎然后会尝试渲染场景,它会注意到特定网格的着色器尚未准备好。现在,您只需要设置JavaScript变量,但接下来就要由引擎来完成着色器中的所有管理了。引擎可能使用您提供的相同变量,但可以使用附加数据(如AttriblLocation、uniformLocation等)对其进行扩展,。。。但这不应该影响你的编码。因此,引擎获取所有属性/制服的一些逻辑组织输入(如上面的代码),并从中生成部分着色器代码

因此,变量扩展为如下内容,其中的数据可以直接用于gl.drawerelements、gl.uniform1f等:

myMesh.uniforms = {

    amplitude: { type: "f", value: 1.0,
                 shaderLocation: ..., shaderType: "float"},
    ...
};

myMesh.attributes = {
    displacement: { type: 'f', value: [],
                    shaderLocation: ..., shaderType: "float", bufferedData: ... }
};
然后,它将生成其余的着色器代码,然后设置一些标志,表明材质/着色器已准备好使用。如果更改某些属性,则需要手动通知引擎更新,以便它可以对着色器进行另一次准备

JavaScript在这方面很好,因为对象的组织方式和动态类型,但是OpenGL引擎会使用一些字典,这些字典将属性/统一名称作为键,其余的重要数据作为字典中的值


希望这能有所帮助。

我想你的担心可能放错地方了。您的意思是,如果更改着色器的统一名称和/或属性名称,则可能必须更改使用它们的代码。这与编程的其他部分有何不同?如果我做一个物体

Animal = function(height, weight, numLegs) {
  this.height = height;
  this.weight = weight;
  this.numLegs = numLegs;
}
我有使用它的代码

var a = new Animal(1, 150, 4);
console.log(a.numLegs);
function applyUniforms(uniformSetters, uniforms) {
  for (var name in uniforms) {
    var setter = uniformSetters[name];
    if (setter) {
      setter(uniforms[name]);
    }
  }
}
后来我换了动物

Animal = function(height, weight, numLegs) {
  this.heightInFeet = height;
  this.weightInLbs = weight;
  this.numberOfLegs = numLegs;
}
我在上面写的代码,
console.log(a.numLegs),也必须更改

换句话说,在GLSL中更改名称并在其他地方更改代码的问题不是WebGL独有的,事实上,这是编程中最常见的事情之一

至于人们如何组织事情,我不知道大多数人都做什么。我是这样做的:

假设您有一个有效的链接程序,我将遍历位置和制服,并创建一个具有预设设置器的对象。然后,我可以向该对象传递一个javascript对象,该对象具有与着色器程序匹配的名称/值对

function createUniformSetters(program) {

  function createUniformSetter(info) {
    var loc = gl.getUniformLocation(program, info.name);
    var type = info.type;
    if (type == gl.FLOAT)
      return function(v) { gl.uniform1f(loc, v); };
    if (type == gl.FLOAT_VEC2)
      return function(v) { gl.uniform2fv(loc, v); };
    if (type == gl.FLOAT_VEC3)
      return function(v) { gl.uniform3fv(loc, v); };
    if (type == gl.FLOAT_VEC4)
      return function(v) { gl.uniform4fv(loc, v); };
    if (type == gl.INT)
      return function(v) { gl.uniform1i(loc, v); };
    if (type == gl.INT_VEC2)
      return function(v) { gl.uniform2iv(loc, v); };
    if (type == gl.INT_VEC3)
      return function(v) { gl.uniform3iv(loc, v); };
    if (type == gl.INT_VEC4)
      return function(v) { gl.uniform4iv(loc, v); };
    if (type == gl.BOOL)
      return function(v) { gl.uniform1i(loc, v); };
    if (type == gl.BOOL_VEC2)
      return function(v) { gl.uniform2iv(loc, v); };
    if (type == gl.BOOL_VEC3)
      return function(v) { gl.uniform3iv(loc, v); };
    if (type == gl.BOOL_VEC4)
      return function(v) { gl.uniform4iv(loc, v); };
    if (type == gl.FLOAT_MAT2)
      return function(v) { gl.uniformMatrix2fv(loc, false, v); };
    if (type == gl.FLOAT_MAT3)
      return function(v) { gl.uniformMatrix3fv(loc, false, v); };
    if (type == gl.FLOAT_MAT4)
      return function(v) { gl.uniformMatrix4fv(loc, false, v); };
    if (type == gl.SAMPLER_2D || type == gl.SAMPLER_CUBE) {
      return function(unit) {
        return function(v) {
          gl.uniform1i(loc, unit);
          v.bindToUnit(unit);
        };
      }(textureUnit++);
    }
    throw ("unknown type: 0x" + type.toString(16));
  }

  // name to setter object for uniforms
  var uniformSetters = {
  };

  // Look up uniforms
  var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
  var textureUnit = 0;

  for (var ii = 0; ii < numUniforms; ++ii) {
    var info = gl.getActiveUniform(program, ii);
    if (!info) {
      break;
    }
    var setter = createUniformSetter(info);
    uniformSetters[info.name] = setter;
  }

  return uniformSetters;
}
然后给了一个GLSL计划,像这样的制服

uniform vec2 u_texcoordOffset;
uniform vec4 u_color;
uniform float u_multiplier
我可以在运行时这样做

// at init time
var uniformSetters = createUniformSetters(someProgram)

var uniforms = {
  u_texcoordOffset: [1, 2],
  u_color: [1, 0, 0, 1],
  u_multiplier: 0.56
};

// -- at draw time --
gl.useProgram(someProgram);
applyUniforms(uniformSetters, uniforms);
我为属性做了类似的事情

注意:以上只是伪代码。它缺少对阵列的支持,如果不是这样的话 清晰的纹理已被某些对象包裹