aq1229 2024-03-22 14:07 采纳率: 37.5%
浏览 16

分形图形的绘制,webgl,js

怎么把Sierpinski镂垫中间去掉的三角形换成其他形状(比如换成下图的爱心形状),下面第一张图是下面代码的编译效果,第二张图是想要的效果(不是爱心形状也可),在我的代码的基础上进行修改

img

img


var NumTimesToSubdivide = 5;  //递归次数
var NumTriangles = Math.pow(3,NumTimesToSubdivide);    //产生的三角形个数
var NumVertices = 3 * NumTriangles;    //顶点数
var points = [];   //存放顶点坐标的数组,初始为空

window.onload = function main(){
    var canvas = document.getElementById("webgl");
    if(!canvas){
        alert("获取canvas元素失败!");
        return;
    }
    var gl = WebGLUtils.setupWebGL(canvas);
    if (!gl){
        alert("获取WebGL上下文失败! ");
        return;
    }
    
    //
    var vertices = [
        vec2(-1.0,-1.0),vec2(0.0,1.0),vec2(1.0,-1.0)
    ];
    
    //递归细分原始三角形
    divideTriangle(vertices[0],vertices[1],vertices[2],NumTimesToSubdivide);
    
    
    
    /*设置webGL相关属性*/
    //设置视口(此处视口占满整个canvas)
    gl.viewport(0,//视口左边界举例canvas左边界距离
                0,//视口下边界距离canvas下边界距离
                canvas.width,//视口宽度
                canvas.height);//视口高度
    gl.clearColor(1.0,1.0,1.0,1.0);
    
    
    
    /*加载shader程序并为shader中attribute变量提供数据*/
    //加载id分别为"vertex-shader","fragment-shader"的shader程序,
    //并进行编译和链接,返回shader程序对象program
    var program = initShaders(gl,"vertex-shader","fragment-shader");
    gl.useProgram(program);    //启用该shader程序对象
    
    
    /*将顶点位置属性数据传输到GPU*/
    var verticesBufferId = gl.createBuffer();    //创建buffer
    gl.bindBuffer(gl.ARRAY_BUFFER,verticesBufferId);    //将id为verticesBufferId的buffer绑定为当前Array Buffer
    //为当前Array Buffer提供数据,传输到GPU
    gl.bufferData(gl.ARRAY_BUFFER,    //Buffer类型
        flatten(points),    //Buffer数据来源,flatten将points转换为GPU可接受的格式
        gl.STATIC_DRAW);   //表明将如何使用Buffer(STATIC_DRAW表明是一次提供数据,多遍绘制)
    
    
    /*为shader属性变量与buffer数据建立关联*/
    //获取名称为"a_Position"的shader attribute变量的位置
    var a_Position = gl.getAttribLocation(program,"a_Position");
    if(a_Position < 0){    //getAttribLocation获取失败则返回-1
        alert("获取attribute变量a_Position失!");
        return;
    }
    
    //指定利用当前Array Buffer为a_Position提供数据的具体方式
    gl.vertexAttribPointer(a_Position,    //shader attribu变量位置
        2,   //每个顶点属性有2个分量
        gl.FLOAT,    //数组数据类型(浮点型)
        false,    //不进行归一化处理
        0,    //相邻顶点属性地址相差0个字节
        0);    //第一个顶点属性在Buffer中偏移量为0字节
    gl.enableVertexAttribArray(a_Position);    //启用顶点属性数组
    
    
    
    render(gl);    //进行绘制
    

};

function render(gl) {
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES,
        0,
        NumVertices);
}
//将三角形的顶点坐标加入数组中
//a,b,c为三角形的三个顶点坐标
function triangle(a,b,c){
    points.push(a);
    points.push(b);
    points.push(c);
}

//递归细分三角形    k用于控制细分次数
function divideTriangle(a,b,c,k){
    if (k>0) {          //k>0则继续细分
        //计算三角形各边的中点
        var ab = mult(0.5,add(a,b));
        var ac = mult(0.5,add(a,c));
        var bc = mult(0.5,add(b,c));
        //出来中间的那个三角形,继续细分其它的三角形
        divideTriangle(a,ab,ac,k-1);
        divideTriangle(c,ac,bc,k-1);
        divideTriangle(b,bc,ab,k-1);
    }
    else{
        triangle(a,b,c);    //递归结束时"绘制"三角形
    }
}
  • 写回答

2条回答 默认 最新

  • 码农阿豪@新空间 优质创作者: Java、后端开发技术领域 2024-03-22 14:08
    关注
    让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
    olution: 要把Sierpinski镂垫中间去掉的三角形换成其他形状,需要对原代码进行修改。具体步骤如下:
    1. 定义一个新的函数,用于绘制心形。
    function heart(a,b,c){
        var ax = a[0], ay = a[1],
            bx = b[0], by = b[1],
            cx = c[0], cy = c[1];
        points.push(vec2((ax+bx)/2, (ay+by)/2+.1));
        points.push(vec2((ax+cx)/2-.1, (ay+cy)/2-.1));
        points.push(vec2((bx+cx)/2+.1, (by+cy)/2-.1));
    }
    

    这个函数的输入是三个点的坐标,输出是在这三个点的中心位置绘制一个心形。对于一个三角形,可以调用这个函数三次,分别传入三个顶点的坐标,使得三个心形一起组成新的图形。 2. 修改divideTriangle函数,使其调用heart函数。

    function divideTriangle(a,b,c,k){
        if (k>0) {
            // 计算三角形各边的中点
            var ab = mult(0.5,add(a,b));
            var ac = mult(0.5,add(a,c));
            var bc = mult(0.5,add(b,c));
            // 细分除中间的那个三角形以外的三角形
            divideTriangle(a,ab,ac,k-1);
            divideTriangle(c,ac,bc,k-1);
            divideTriangle(b,bc,ab,k-1);
            // 绘制中间的那个心形
            heart(ab,ac,bc);
        }
        else {
            // 如果不再需要细分,则将三角形加入顶点数组中
            triangle(a,b,c);
        }
    }
    

    当递归次数达到指定值时,不再继续细分三角形,转而将三角形加入顶点数组中;而在递归过程中,调用heart函数绘制中间的心形。 3. 在main函数中调用修改后的divideTriangle函数。

    function main(){
        // ...
        var vertices = [
            vec2(-1.0,-1.0),
            vec2(0.0, 1.0),
            vec2(1.0,-1.0)
        ];
        divideTriangle(vertices[0], vertices[1], vertices[2], NumTimesToSubdivide);
        // ...
    }
    

    这样就可以将Sierpinski镂垫中间的三角形替换成心形了。 完整代码如下:

    var NumTimesToSubdivide = 5;  //递归次数
    var NumTriangles = Math.pow(3,NumTimesToSubdivide);    //产生的三角形个数
    var NumVertices = 3 * NumTriangles;    //顶点数
    var points = [];   //存放顶点坐标的数组,初始为空
    function main(){
        var canvas = document.getElementById("webgl");
        if(!canvas){
            alert("获取canvas元素失败!");
            return;
        }
        var gl = WebGLUtils.setupWebGL(canvas);
        if (!gl){
            alert("获取WebGL上下文失败!");
            return;
        }
        var vertices = [
            vec2(-1.0,-1.0),
            vec2(0.0, 1.0),
            vec2(1.0,-1.0)
        ];
        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 verticesBufferId = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, verticesBufferId);
        gl.bufferData(gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW);
        var a_Position = gl.getAttribLocation(program, "a_Position");
        gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
        gl.enableVertexAttribArray(a_Position);
        render(gl);
    }
    function render(gl) {
        gl.clear(gl.COLOR_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLES, 0, NumVertices);
    }
    function triangle(a,b,c){
        points.push(a);
        points.push(b);
        points.push(c);
    }
    function heart(a,b,c){
        var ax = a[0], ay = a[1],
            bx = b[0], by = b[1],
            cx = c[0], cy = c[1];
        points.push(vec2((ax+bx)/2, (ay+by)/2+.1));
        points.push(vec2((ax+cx)/2-.1, (ay+cy)/2-.1));
        points.push(vec2((bx+cx)/2+.1, (by+cy)/2-.1));
    }
    function divideTriangle(a,b,c,k){
        if (k>0) {
            var ab = mult(0.5,add(a,b));
            var ac = mult(0.5,add(a,c));
            var bc = mult(0.5,add(b,c));
            divideTriangle(a,ab,ac,k-1);
            divideTriangle(c,ac,bc,k-1);
            divideTriangle(b,bc,ab,k-1);
            heart(ab,ac,bc);
        }
        else {
            triangle(a,b,c);
        }
    }
    
    评论

报告相同问题?

问题事件

  • 创建了问题 3月22日