Sierpinsk 镂垫(二) 三维

109 阅读2分钟

四面体有个特性就是它都是凸的,所以一个顶点和四面体内任何一点之间的连线中点也在四面体内。

让每个点映射为不同的颜色。r=(1+x)/2 g=(1+y)/2 b=(1+z)/2

点代码
//着色器
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
varying vec4 fColor;

void main()
{
    fColor=vec4((1.0+vPosition.xyz)/2.0,1.0);//光栅化模块实现对fColor插值
    gl_PointSize = 1.0;
    gl_Position = vPosition;
}
</script>

<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;

varying vec4 fColor;

void main()
{
    gl_FragColor =fColor;
}
</script>



let canvas, gl, points;

const NumPoints = 5000;

window.onload = function init()
{
    canvas = document.getElementById( "gl-canvas" );

    gl = WebGLUtils.setupWebGL( canvas );
    if ( !gl ) { alert( "WebGL isn't available" ); }

    const vertices = [
        vec3( -0.5, -0.5, -0.5 ),
        vec3(  0.5, -0.5, -0.5 ),
        vec3(  0.0,  0.5,  0.0 ),
        vec3(  0.0, -0.5, 0.5 ),
    ];

  //每个四面体都是凸的,所以一个顶点和四面体内任何一点之间的连线中点也在四面体内。
  //把四面体内一点 作为初始位置  
    points = [ vec3( 0.0, 0.0, 0.0 ) ];

    for ( let i = 0; points.length < NumPoints; ++i ) {
        const j = Math.floor(Math.random() * 4);

        points.push(mix(points[i], vertices[j], 0.5) );
    }

    gl.viewport( 0, 0, canvas.width, canvas.height );
    gl.clearColor( 1.0, 1.0, 1.0, 1.0 );
    gl.enable( gl.DEPTH_TEST );//开启深度测试


    var program = initShaders( gl, "vertex-shader", "fragment-shader" );
    gl.useProgram( program );

    const bufferId = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, bufferId );
  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 );

    render();
};


function render()
{
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
    gl.drawArrays( gl.POINTS, 0, points.length );
}

效果图

image.png


image.png

图来着书中

代码
//着色器
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec3 vPosition;
attribute vec3 vColor;
varying vec4 color;

void main(){
    gl_Position = vec4(vPosition, 1.0);
    color = vec4(vColor, 1.0);
}
</script>

<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
   
varying vec4 color;

void main()
{
    gl_FragColor = color;
}
</script>


初始化代码分析

三角形分割

 const 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);

1663423838767.jpg


进行颜色的填充和三角形顶点数

function triangle( a, b, c, color )
{
    const baseColors = [
        vec3(1.0, 0.0, 0.0),
        vec3(0.0, 1.0, 0.0),
        vec3(0.0, 0.0, 1.0),
        vec3(0.0, 0.0, 0.0)
    ];

    colors.push( baseColors[color] );
    points.push( a );
    colors.push( baseColors[color] );
    points.push( b );
    colors.push( baseColors[color] );
    points.push( c );
}
function tetra( a, b, c, d )
{
    triangle( a, c, b, 0 );
    triangle( a, c, d, 1 );
    triangle( a, b, d, 2 );
    triangle( b, c, d, 3 );
}

image.png

图片来着书内 图片有误(0.0,0.0,0.0)是黑色;(0.0,0.0,1.0)蓝色

acb组成的面(左),使用的颜色坐标为(1.0, 0.0, 0.0)--红色; acd组成的面(下),使用的颜色坐标为(0,0,1.0,0.0)--绿色; abd组成的面(右),使用的颜色坐标为(0.0,0.0,1.0) --蓝色;

1663423515380.png


let canvas, gl, points = [], colors = [];

const NumTimesToSubdivide = 3;

window.onload = function init()
{
    canvas = document.getElementById( "gl-canvas" );

    gl = WebGLUtils.setupWebGL( canvas );
    if ( !gl ) { alert( "WebGL isn't available" ); }

    const 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);

    gl.viewport( 0, 0, canvas.width, canvas.height );
    gl.clearColor( 1.0, 1.0, 1.0, 1.0 );

    gl.enable(gl.DEPTH_TEST);

    const program = initShaders( gl, "vertex-shader", "fragment-shader" );
    gl.useProgram( program );

    const cBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW );

    const vColor = gl.getAttribLocation( program, "vColor" );
    gl.vertexAttribPointer( vColor, 3, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vColor );

    const vBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW );

    const vPosition = gl.getAttribLocation( program, "vPosition" );
    gl.vertexAttribPointer( vPosition, 3, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vPosition );

    render();
};

function triangle( a, b, c, color )
{
    const baseColors = [
        vec3(1.0, 0.0, 0.0),
        vec3(0.0, 1.0, 0.0),
        vec3(0.0, 0.0, 1.0),
        vec3(0.0, 0.0, 0.0)
    ];

    colors.push( baseColors[color] );
    points.push( a );
    colors.push( baseColors[color] );
    points.push( b );
    colors.push( baseColors[color] );
    points.push( c );
}

function tetra( a, b, c, d )
{
    triangle( a, c, b, 0 );
    triangle( a, c, d, 1 );
    triangle( a, b, d, 2 );
    triangle( b, c, d, 3 );
}

function divideTetra( a, b, c, d, count )
{

    if ( count === 0 ) {
        tetra( a, b, c, d );
    }


    else {
        const ab = mix( a, b, 0.5 );
        const ac = mix( a, c, 0.5 );
        const ad = mix( a, d, 0.5 );
        const bc = mix( b, c, 0.5 );
        const bd = mix( b, d, 0.5 );
        const 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 );
}

效果图

image.png