【问题标题】:WebGL texture creation troubleWebGL 纹理创建问题
【发布时间】:2017-01-02 23:17:27
【问题描述】:

我正在编写一个光线追踪程序,主要思想是将 .obj 模型的三角形和索引保存到 2 个纹理中:

a) 顶点纹理 b) 索引纹理

我这样做是为了在我的 GLSL 片段着色器中做一个光线三角形相交,浏览器告诉我我的纹理有这个问题:

a) Mozilla Firefox

错误 #1(带有顶点纹理):错误:WebGL:texImage2D:无效类型 0x1406

错误 #2(带有索引纹理):错误:WebGL:texImage2D:无效类型 0x1403

b) 谷歌浏览器

两种纹理都出错:webgl invalid_enum teximage2d 纹理类型无效

代码如下:

Obj.prototype.initTextures = function(){

this.vertexTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, this.vertexTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, this.vertexSize, 1, 0, gl.RGB, gl.FLOAT, new Float32Array(this.vertexArray));
gl.bindTexture(gl.TEXTURE_2D, null);

this.trianglesTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, this.trianglesTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, this.faceSize, 1, 0, gl.RGB,  gl.UNSIGNED_SHORT, new Uint16Array(this.faceArray));
gl.bindTexture(gl.TEXTURE_2D, null);

}

由于显而易见的原因 this.vertexArray 和 this.faceArray 有数据。

【问题讨论】:

    标签: javascript google-chrome firefox opengl-es webgl


    【解决方案1】:

    gl.RGB / gl.FLOAT 纹理仅在您检查并启用浮点纹理时才允许使用。

    var floatTextures = gl.getExtension('OES_texture_float');
    if (!floatTextures) {
        alert('no floating point texture support');
        return;
    }
    

    gl.RGB / gl.UNSIGNED_SHORT 纹理在 WebGL 上不存在句点。您可以尝试将无符号短值编码为R * 256 + G * 65536 或类似的东西。或者在这里也使用浮点数。

    注意:过滤浮动,如gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR),是一个单独的扩展OES_texture_float_linear,但在你的情况下,因为你只使用gl.NEAREST,你不需要检查那个扩展

    至于将顶点数据放入纹理中,您可能会发现您必须做一些工作才能提取出正确的值。

    要索引纹理中的值,您需要计算一个纹理坐标,该坐标将访问正确的纹素。为此,您需要从第一个纹素的中间访问到最后一个纹素的中间。

    换句话说,如果我们有 3 个值(因此有 3 个纹素),我们就会有这样的东西

         ------3x1 ----- texels ----------
         [         ][         ][         ]
     0.0 |<----------------------------->| 1.0
    

    如果我们只是用 index / numValues 来计算我们会得到的纹理坐标

         [         ][         ][         ]
         |          |          |
         0.0       0.333       0.666
    

    这在纹素之间是正确的,所以我们添加一个半纹素来得到它

         [         ][         ][         ]
              |          |          |
            0.167       0.5       0.833
    

    希望这是有道理的。这是一个sn-p

    var gl = document.querySelector("canvas").getContext("webgl");
    var ext = gl.getExtension("OES_texture_float");
    if (!ext) {
      alert("need OES_texture_float extension cause I'm lazy");
      //return;
    }
    if (gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) < 2) {
      alert("need to be able to access textures from vertex shaders");
      //return;
    }
    
    var m4 = twgl.m4;
    var v3 = twgl.v3;
    var program = twgl.createProgramFromScripts(gl, ["vshader", "fshader"]);
    
    var positionIndexLoc = gl.getAttribLocation(program, "a_positionIndex");
    var normalIndexLoc = gl.getAttribLocation(program, "a_normalIndex");
    
    var colorLoc = gl.getUniformLocation(program, "u_color");
    var mvpMatrixLoc = gl.getUniformLocation(program, "u_mvpMatrix");
    var mvMatrixLoc = gl.getUniformLocation(program, "u_mvMatrix");
    var lightDirLoc = gl.getUniformLocation(
      program, "u_lightDirection");
    var u_positionsLoc = gl.getUniformLocation(
      program, "u_positions");
    var u_normalsLoc = gl.getUniformLocation(
      program, "u_normals");
    gl.uniform1i(u_positionsLoc, 0); // use texture unit 0 for positions
    gl.uniform1i(u_normalsLoc, 1);   // use texture unit 1 for normals
    
    // Cube data
    var positions = [
      -1, -1, -1, // 0 lbb
      +1, -1, -1, // 1 rbb      2---3
      -1, +1, -1, // 2 ltb     /|  /|
      +1, +1, -1, // 3 rtb    6---7 |
      -1, -1, +1, // 4 lbf    | | | |
      +1, -1, +1, // 5 rbf    | 0-|-1
      -1, +1, +1, // 6 ltf    |/  |/
      +1, +1, +1, // 7 rtf    4---5
    ];
    var positionIndices = [
      3, 7, 5, 3, 5, 1, // right
      6, 2, 0, 6, 0, 4, // left
      6, 7, 3, 6, 3, 2, // top
      0, 1, 5, 0, 5, 4, // bottom
      7, 6, 4, 7, 4, 5, // front
      2, 3, 1, 2, 1, 0, // back
    ];
    var normals = [
      +1,  0,  0,
      -1,  0,  0,
      0, +1,  0,
      0, -1,  0,
      0,  0, +1,
      0,  0, -1,
    ]
      var normalIndices = [
      0, 0, 0, 0, 0, 0,  // right
      1, 1, 1, 1, 1, 1,  // left
      2, 2, 2, 2, 2, 2,  // top
      3, 3, 3, 3, 3, 3,  // bottom
      4, 4, 4, 4, 4, 4,  // front
      5, 5, 5, 5, 5, 5,  // back
    ];
    
    function degToRad(deg) {
      return deg * Math.PI / 180;
    }
    
    function uploadIndices(loc, data, indices) {
      // scale indices into texture coordinates
      var scaledIndices = new Float32Array(indices.length);
    
      // to index the value in the texture we need to
      // compute a texture coordinate that will access
      // the correct texel. To do that we need access from
      // the middle of the first texel to the middle of the
      // last texel.
      //
      // In other words if we had 3 values (and therefore
      // 3 texels) we'd have something like this
      //
      //     ------3x1 ----- texels ----------
      //     [         ][         ][         ]
      // 0.0 |<----------------------------->| 1.0
      //
      // If we just did index / numValues we'd get
      //
      //     [         ][         ][         ]
      //     |          |          |
      //     0.0       0.333       0.666
      //
      // Which is right between texels so we add a
      // a halfTexel to get this
      //
      //     [         ][         ][         ]
      //          |          |          |
      //        0.167       0.5       0.833
    
    
      var size = data.length / 3;
      var texel = 1 / size;
      var halfTexel = texel / 2;
      for (var ii = 0; ii < indices.length; ++ii) {
        scaledIndices[ii] = indices[ii] / size + halfTexel;
      }
      var buffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      gl.bufferData(gl.ARRAY_BUFFER,
                    scaledIndices,
                    gl.STATIC_DRAW);
      gl.enableVertexAttribArray(loc);
      gl.vertexAttribPointer(loc, 1, gl.FLOAT, false, 0, 0);
    }
    
    function uploadTexture(unit, data) {
      gl.activeTexture(gl.TEXTURE0 + unit);
      var tex = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, tex);
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB,
                    data.length / 3, 1, 0,
                    gl.RGB, gl.FLOAT, new Float32Array(data));
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
                       gl.NEAREST);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,
                       gl.NEAREST);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,
                       gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,
                       gl.CLAMP_TO_EDGE);
    }
    
    uploadIndices(positionIndexLoc, positions, positionIndices);
    uploadIndices(normalIndexLoc, normals, normalIndices);
    uploadTexture(0, positions);
    uploadTexture(1, normals);
    
    var xRot = 30;
    var yRot = 20;
    var zRot = 0;
    
    var lightDir = v3.normalize([-0.2, -0.1, 0.5]);
    
    function draw() {
      xRot += 0;
      yRot += 1;
      
      twgl.resizeCanvasToDisplaySize(gl.canvas);
      gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
      
      gl.enable(gl.DEPTH_TEST);
      gl.enable(gl.CULL_FACE);
      gl.clearColor(0, 0, 0, 1);
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
      gl.useProgram(program);  
    
      var projection = m4.perspective(
        degToRad(45),
        gl.canvas.clientWidth / gl.canvas.clientHeight,
        0.1, 100.0);
    
      var world = m4.identity();
      world = m4.translate(world, [0.0, 0.0, -5.0]);
    
      world = m4.rotateX(world, degToRad(xRot));
      world = m4.rotateY(world, degToRad(yRot));
      world = m4.rotateZ(world, degToRad(zRot));
    
      var mvp = m4.multiply(projection, world);
    
      gl.uniformMatrix4fv(mvMatrixLoc, false, world);
      gl.uniformMatrix4fv(mvpMatrixLoc, false, mvp);
    
      gl.uniform4f(colorLoc, 0.5, 0.8, 1, 1);
      gl.uniform3fv(lightDirLoc, lightDir);
    
      gl.drawArrays(gl.TRIANGLES, 0, 36);
      requestAnimationFrame(draw);
    }
    draw();
    body {
      margin: 0;
    }
    canvas {
      width: 100vw;
      height: 100vh;
      display: block;
    }
    <script src="//twgljs.org/dist/2.x/twgl-full.min.js"></script>
    <script id="vshader" type="whatever">
    attribute float a_positionIndex;
    attribute float a_normalIndex;
    attribute vec4 a_pos;
    
    uniform sampler2D u_positions;
    uniform sampler2D u_normals;
    uniform mat4 u_mvpMatrix;
    uniform mat4 u_mvMatrix;
    
    varying vec3 v_normal;
    
    void main() {
      vec3 position = texture2D(
          u_positions, vec2(a_positionIndex, 0.5)).rgb;
      vec3 normal = texture2D(
          u_normals, vec2(a_normalIndex, 0.5)).rgb;
      gl_Position = u_mvpMatrix * vec4(position, 1);
      v_normal = (u_mvMatrix * vec4(normal, 0)).xyz;
    }
    </script>
    <script id="fshader" type="whatever">
    precision mediump float;
    
    uniform vec4 u_color;
    uniform vec3 u_lightDirection;
    
    varying vec3 v_normal;
    
    void main() {
      float light = dot(
          normalize(v_normal), u_lightDirection) * 0.5 + 0.5;
      gl_FragColor = vec4(u_color.rgb * light, u_color.a);
    }
    </script>
    <canvas></canvas>

    【讨论】:

      猜你喜欢
      • 2012-02-21
      • 2017-01-19
      • 1970-01-01
      • 1970-01-01
      • 2016-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-17
      相关资源
      最近更新 更多