四面体有个特性就是它都是凸的,所以一个顶点和四面体内任何一点之间的连线中点也在四面体内。
让每个点映射为不同的颜色。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 );
}
效果图
图来着书中
代码
//着色器
<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);
进行颜色的填充和三角形顶点数
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 );
}
图片来着书内 图片有误(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) --蓝色;
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 );
}