首页 > 解决方案 > 如何修复 3D Serpinski Triangle 的透明面

问题描述

我有一个用 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 数组,您会看到背面有一种额外的颜色。

标签: javascriptwebgl

解决方案


我不是 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 个面的四面体。


推荐阅读