Sierpinski 镂垫的生成

128 阅读2分钟
Sierpinski 镂垫数据构造

步骤

1. 在**三角形内**随机选取一个初始点p(x,y,0);
2. 随机选3个顶点之一 A3. 找出p和顶点A之间的中点q;
4. 显示器显示q点;
5. 递归执行2-4步骤;

裁剪窗口 视口 显示窗口

image.png

图片来着书本

vertexAttribPointer

参数参数说明参数值
location指定分配 attribute 中的存储地址-
size指定缓冲区每个顶点分量的个数 1-4-
type指定数据类型-
normalize是否将非浮点型数据归一化true-
stride指定相邻两个顶点间的字节数默认 0
offset指定缓冲区对象中的偏移量默认 0

由点形成效果展示

image.png

代码:

//着色器
<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);
  }
}

展示效果--由多边形(三角形)

image.png

divideTriangle代码分析

1663414310056.png

代码

"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的效果

image.png

image.png