在webgl中获取投影曲面的法线

时间:2015-04-13 20:16:28

标签: webgl projection

我使用drawArrays(gl.TRIANGLES,...)在画布上绘制了一些曲面的顶点。我需要为特定的摄像机视点绘制这些曲面,因此所有3d点都投影到2d,我使用toDataUrl下载最终图像。这是下载的图像:

enter image description here

我之后使用gl.readPixels来检索每个像素的数据。

对于所有边缘顶点,我都有法线信息。就像我得到2d图像中每个像素的颜色一样,我想得到2d图像的每个像素的法线。由于我只在边缘顶点处有法线,所以我决定渲染法线的方式与渲染上面的图像相同,并决定使用gl.readpixels。这不起作用。以下是相关代码:

这是调用drawOverlayTriangeNormals的函数。 drawOverlayTriangles函数(在这篇文章中不可见)用于生成上面显示的图像。

    //Saving BIM
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.vertexAttrib1f(shaderProgram.aIsDepth, 0.0);
    drawOverlayTriangles();
    saveBlob('element');

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.vertexAttrib1f(shaderProgram.aIsDepth, 0.0);
    drawOverlayTrianglesNormals();
    saveBlob('element');

    var pixels = new Uint8Array(glCanvas.width*glCanvas.height*4);
    gl.readPixels(0, 0, glCanvas.width, glCanvas.height, gl.RGBA, gl.UNSIGNED_BYTE,pixels);
    pixels = new Float32Array(pixels.buffer);   
}

这是drawOverlayTrianglesNormals函数:

function drawOverlayTrianglesNormals()
{
if (overlay.numElements <= 0)
    return;

//Creating the matrix for normal transform
var normal_matrix = mat4.create();
var u_Normal_Matrix = mat4.create();
mat4.invert(normal_matrix,pMVMatrix);
mat4.transpose(u_Normal_Matrix,normal_matrix);  

gl.enable(gl.DEPTH_TEST);   

gl.enableVertexAttribArray(shaderProgram.aVertexPosition);
gl.enableVertexAttribArray(shaderProgram.aVertexColor);
gl.enableVertexAttribArray(shaderProgram.aNormal);
gl.vertexAttrib1f(shaderProgram.aIsNormal, 1.0);

//Matrix upload
gl.uniformMatrix4fv(shaderProgram.uMVMatrix, false, pMVMatrix);
gl.uniformMatrix4fv(shaderProgram.uPMatrix, false, perspM);
gl.uniformMatrix4fv(shaderProgram.uNMatrix, false, u_Normal_Matrix);

//Create normals buffer
normals_buffer = gl.createBuffer();

for (var i = 0; i < overlay.numElements; i++) {
    // Upload overlay vertices                      
    gl.bindBuffer(gl.ARRAY_BUFFER, overlayVertices[i]);
    gl.vertexAttribPointer(shaderProgram.aVertexPosition, 3, gl.FLOAT, false, 0, 0);

    // Upload overlay colors
    gl.bindBuffer(gl.ARRAY_BUFFER, overlayTriangleColors[i]);       
    gl.vertexAttribPointer(shaderProgram.aVertexColor, 4, gl.FLOAT, false, 0, 0);

    var normal_vertex = [];

    //Upload Normals
        var normals_element = overlay.elementNormals[i];
        for( var j=0; j< overlay.elementNumVertices[i]; j++)
    {   
        var x = normals_element[3*j+0];
        var y = normals_element[3*j+1];
        var z = normals_element[3*j+2];
        var length = Math.sqrt(x*x + y*y + z*z);

        normal_vertex[3*j+0] = x/length;
        normal_vertex[3*j+1] = y/length;
        normal_vertex[3*j+2] = z/length;
    }
    gl.bindBuffer(gl.ARRAY_BUFFER, normals_buffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normal_vertex),gl.STATIC_DRAW);
    gl.vertexAttribPointer(shaderProgram.aNormal, 3, gl.FLOAT, false, 0, 0);    

    // Draw overlay
    gl.drawArrays(gl.TRIANGLES, 0, overlay.elementNumVertices[i]);
}

gl.disableVertexAttribArray(shaderProgram.aVertexPosition);
gl.disableVertexAttribArray(shaderProgram.aVertexColor);
gl.vertexAttrib1f(shaderProgram.aisdepth, 0.0);
}

以下是相关的顶点着色器代码:

 void main(void) {
        gl_PointSize = aPointSize;
            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
        position_1 = gl_Position;
        vColor = aVertexColor;
        vIsDepth = aIsDepth;
        vIsNormal = aIsNormal;
        vHasTexture = aHasTexture;
        normals = uNMatrix*vec4(aNormal,1.0);
        if (aHasTexture > 0.5)
            vTextureCoord = aTextureCoord;

    }

片段着色器:

 if (vIsNormal > 0.5)
        {
            gl_FragColor = vec4(normals.xyz*0.5+0.5,1);

        }
    }

现在我的输出是灰度相同的图像。我不确定出了什么问题。我觉得这种方法很有意义,但似乎有点圆了。

1 个答案:

答案 0 :(得分:0)

我不完全确定我明白你要做的是什么,但似乎你只是想要能够访问法线来计算灯光效果,所以让我试着回答一下。

请勿使用gl.readPixels()!这主要用于点击交互和内容,或修改少量像素。使用它必须非常低效,因为您必须绘制像素,然后读取它们,然后在计算适当的光照后重绘它们。 WebGL的精彩之处在于它允许您从头开始执行所有这些操作:片段着色器将插入它给出的信息,以便在两个相邻顶点之间平滑地绘制效果。

大多数照明取决于将表面法线与光线方向进行比较(正如您所理解的那样,根据您的评论判断)。请参阅Phong shading

现在,您提到您想要所有渲染点的法线,而不仅仅是顶点。但是顶点的法线将与曲面上每个点的法线相同,因此您甚至不需要比顶点法线更多的法线。这是因为所有WebGL都知道如何绘制三角形(我相信),它们是平面或平面的表面。并且由于飞机上的每个点与任何其他点具有相同的法线,因此您只需要一个法线来了解所有法线!

因为看起来你要绘制的所有东西都是圆柱和矩形棱镜,所以指定你创建的对象的法线应该很简单。矩形棱镜的法线是微不足道的,但是圆柱体的法线也是如此:法线平行于从圆柱轴到表面的直线。

由于WebGL的片段着色器会插入您在相邻顶点之间传递的任何varying变量,您可以告诉它在顶点之间平滑地插入这些法线,以实现在Phong shadin页面中看到的平滑光照! :d