如何修复 3D 塞尔平斯基三角形的透明边



我有一个用Javascript和WebGL编写的3D Serpinski Triangle,使用位于以下位置的Common文件夹: https://github.com/esangel/WebGL/tree/master/Common

每一面都应该有不同的颜色。三角形按预期呈现和旋转,但问题是背面是透明的。

我尝试在三角形函数内更改 baseColors 中的 vec3,我什至尝试将另一种颜色推到颜色数组上。我在另一篇文章中读到,当某些多边形被绘制时,可能会发生这种情况。我唯一的猜测是有几行代码需要重新排列。

"use strict";
 var canvas;
 var gl;
 var theta = 0.0;
 var dtheta = 0.1;
 var thetaLoc;
 var speed = 50;
 var bufferId;
 var vertices;
 var dir = 1;
var points = [];
var colors = [];
var NumTimesToSubdivide = 3;
window.onload = function init()
{
 canvas = document.getElementById( "gl-canvas" );
 gl = WebGLUtils.setupWebGL( canvas );
 if (!gl) { alert("WebGL isn't available"); }
 //
 //  Initialize our data for the Sierpinski Gasket
 //
 // First, initialize the vertices of our 3D gasket
 // Four vertices on unit circle
 // Intial tetrahedron with equal length sides
 var vertices = [
     vec3(  0.0000,  0.0000, -1.0000 ),
     vec3(  0.0000,  0.9428,  0.3333 ),
     vec3( -0.8165, -0.4714,  0.3333 ),
     vec3(  0.8165, -0.4714,  0.3333 )
 ];
 divideTetra( vertices[0], vertices[1], vertices[2], vertices[3],
              NumTimesToSubdivide);
 //
 //  Configure WebGL
 //
 gl.viewport( 0, 0, canvas.width, canvas.height );
 gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
 // enable hidden-surface removal
 gl.enable(gl.DEPTH_TEST);
 //  Load shaders and initialize attribute buffers
 var program = initShaders( gl, "vertex-shader", "fragment-shader" );
 gl.useProgram( program );
 // Create a buffer object, initialize it, and associate it with the
 //  associated attribute variable in our vertex shader
 var cBuffer = gl.createBuffer();
 gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
 gl.bufferData( gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW );
 var vColor = gl.getAttribLocation( program, "vColor" );
 gl.vertexAttribPointer( vColor, 3, gl.FLOAT, false, 0, 0 );
 gl.enableVertexAttribArray( vColor );
 var vBuffer = gl.createBuffer();
 gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer );
 gl.bufferData( gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW );
 var vPosition = gl.getAttribLocation( program, "vPosition" );
 gl.vertexAttribPointer( vPosition, 3, gl.FLOAT, false, 0, 0 );
 gl.enableVertexAttribArray(vPosition);
 thetaLoc = gl.getUniformLocation(program, "theta");
 gl.uniform1f(thetaLoc, theta);
 render();
};
function triangle( a, b, c, color )
{
 // add colors and vertices for one triangle
 var baseColors = [
     vec3(1.0, 0.0, 0.0),
     vec3(0.0, 1.0, 0.0),
     vec3(0.0, 0.0, 1.0),
     vec3(1.0, 1.0, 0.0)
 ];
 colors.push( baseColors[color] );
 points.push( a );
 colors.push( baseColors[color] );
 points.push( b );
 colors.push( baseColors[color] );
 points.push(c);
 //colors.push(baseColors[color]);
// points.push(a);

}
function tetra( a, b, c, d )
{
 // tetrahedron with each side using
 // a different color
 triangle( a, c, b, 0 );
 triangle( a, c, d, 1 );
 triangle( a, b, d, 2 );
 triangle( b, c, d, 3 ); //bcd
}
function divideTetra( a, b, c, d, count )
{
 // check for end of recursion
 if ( count === 0 ) {
     tetra( a, b, c, d );
 }
 // find midpoints of sides
 // divide four smaller tetrahedra
 else {
     var ab = mix( a, b, 0.5 );
     var ac = mix( a, c, 0.5 );
     var ad = mix( a, d, 0.5 );
     var bc = mix( b, c, 0.5 );
     var bd = mix( b, d, 0.5 );
     var cd = mix( c, d, 0.5 );
     --count;
     divideTetra(  a, ab, ac, ad, count );
     divideTetra( ab,  b, bc, bd, count );
     divideTetra( ac, bc,  c, cd, count );
     divideTetra( ad, bd, cd,  d, count );
 }
}

function render()
{

 gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
 //gl.drawArrays(gl.TRIANGLES, 0, points.length);
 theta += dir * dtheta * (speed / 100);
 gl.uniform1f(thetaLoc, theta);
 gl.drawArrays(gl.TRIANGLES, 0, points.length);
 requestAnimFrame(render);
}

这是 HTML:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
<title>3D Sierpinski Gasket</title>

<script id="vertex-shader" type="x-shader/x-vertex">
    attribute vec3 vPosition;
    attribute vec3 vColor;
    varying vec4 color;
    uniform float theta;
    void
    main()
    {
    gl_Position = vec4(vPosition, 1.0);
    color = vec4(vColor, 1.0);
    float s = sin( theta );
    float c = cos( theta );
    gl_Position.x = -s * vPosition.z + c * vPosition.x;
    gl_Position.z =  s * vPosition.x + c * vPosition.z;
    gl_Position.z = 0.0;
    gl_Position.w = 1.0;
    }
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
    precision mediump float;
    varying vec4 color;
    void
    main()
    {
    gl_FragColor = color;
    }
</script>
<script type="text/javascript" src="Common/webgl-utils.js"></script>
<script type="text/javascript" src="Common/initShaders.js"></script>
<script type="text/javascript" src="Common/MV.js"></script>
<script type="text/javascript" src="3DSierpinskiTriangle.js"></script>
</head>   
<body>
<canvas id="gl-canvas" width="512" height="512">
Oops ... your browser doesn't support the HTML5 canvas element
</canvas>
</body>
</html>

三角形的背面是透明的,但如果你查看baseColors数组,你会看到背面有一个额外的颜色。

我不是 WebGL 专家,但看起来您正在顶点着色器中覆盖gl_Position.z的值。

gl_Position.x = -s * vPosition.z + c * vPosition.x;
gl_Position.z =  s * vPosition.x + c * vPosition.z;
gl_Position.z = 0.0; // <--- REMOVE THIS LINE
gl_Position.w = 1.0;

删除该线可以正确呈现所有 4 个边的四面体。

最新更新