Sierpinski 镂垫数据构造
步骤:
1. 在**三角形内**随机选取一个初始点p(x,y,0);
2. 随机选3个顶点之一 A;
3. 找出p和顶点A之间的中点q;
4. 显示器显示q点;
5. 递归执行2-4步骤;
裁剪窗口 视口 显示窗口
图片来着书本
vertexAttribPointer
参数 | 参数说明 | 参数值 |
---|---|---|
location | 指定分配 attribute 中的存储地址 | - |
size | 指定缓冲区每个顶点分量的个数 1-4 | - |
type | 指定数据类型 | - |
normalize | 是否将非浮点型数据归一化true | - |
stride | 指定相邻两个顶点间的字节数 | 默认 0 |
offset | 指定缓冲区对象中的偏移量 | 默认 0 |
由点形成效果展示
代码:
//着色器
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
void main()
{
gl_PointSize = 1.0;
gl_Position = vPosition;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
void main()
{
gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
</script>
window.onload = function init() {
const numPoints = 500;
let points = [];
const canvas = document.getElementById( "gl-canvas" );
const gl = WebGLUtils.setupWebGL( canvas );
if (!gl) { alert("WebGL isn't available"); }
//三角形三个顶点坐标
const vertices = [
vec2(-1, -1),
vec2(0, 1),
vec2(1, -1)
];
const u = add(vertices[0], vertices[1]);
const v = add(vertices[0], vertices[2]);
const p = scale(0.5, add(u, v));//步骤1:随机取三角形内一个点
points.push(p);
for (let i = 0; points.length < numPoints; ++i){
let j = Math.floor(Math.random() * 3);//随机取三个顶点之一
let p = add(points[i], vertices[j]);
p = scale(0.5, p);//中点
points.push(p);
}
gl.viewport(0, 0, canvas.width, canvas.height);//视口是显示窗口中的一块矩形区域
gl.clearColor(1.0,1.0,1.0,1.0);
const program = initShaders(gl, 'vertex-shader', 'fragment-shader');
gl.useProgram(program);
// 把points数据发送到GPU缓存中
//创建一个顶点缓存区对象 Vertex Buffer Ojbect,VBO)
const bufferId = gl.createBuffer();//返回一个标识符buffer:当前缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER,bufferId);//gl.ARRAY_BUFFER 顶点属性数据
// -- gl.bufferData()函数只接受原生数据类型值的数组 --js 类型化数据
gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW);
//将着色器的变量和缓存区的变量相关联起来
var vPosition = gl.getAttribLocation( program, "vPosition" );
gl.vertexAttribPointer( vPosition, 2, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( vPosition );
render();
function render() {
gl.clear(gl.COLOR_BUFFER_BIT);//清除帧缓存
gl.drawArrays(gl.POINTS, 0, numPoints);
}
}
展示效果--由多边形(三角形)
divideTriangle代码分析
代码
"use strict";
let canvas, gl, points = [];
const NumTimesToSubdivide = 5;//调整总的被分割数
window.onload = function init() {
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas );
if (!gl) { alert("WebGL isn't available"); }
var vertices = [
vec2(-1, -1),
vec2(0, 1),
vec2(1,-1)
];
divideTriangle(vertices[0],vertices[1],vertices[2],NumTimesToSubdivide)
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0,1.0);
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram(program);
var 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, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray( vPosition );
render();
}
function render() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES,0,points.length)
}
function triangle(a, b, c) {
points.push(a, b, c);//三角形三个顶点数
}
//分割由a,b,c三个顶点左侧的三角形 count为被分割的个数 递归
function divideTriangle(a, b, c, count) {
if (count===0) {
triangle(a,b,c);
} else {
// mix()执行两个向量之间的线性插值 mix(a,b,s)=s*a+(1-s)*b
var ab = mix( a, b, 0.5 );//获取a,b之间的中点
var ac = mix( a, c, 0.5 );//获取a,c之间的中点
var bc = mix( b, c, 0.5 );//获取b,c之间的中点
--count;
// 三个新的三角形
divideTriangle( a, ab, ac, count );
divideTriangle( c, ac, bc, count );
divideTriangle( b, bc, ab, count );
}
}
下图是NumTimesToSubdivide分别为3和10的效果