Computer Graphics Lab2

Lab2

1.taska.html+a.js

任务a. 在网页上添加交互式控件,输入剖分的层次(0-7),完成Sierpinski Gasket的绘制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!--taska.html-->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Chap2 Demo Sierpinski Gasket </title>
<script id="vertex-shader-a" type="x-shader/x-vertex">
#version 300 es
in vec4 vPosition;
void main(){
gl_Position = vPosition;
}
</script>

<script id="fragment-shader-a" type="x-shader/x-fragment">
#version 300 es
precision mediump float;
out vec4 fColor;
void main(){
fColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
</script>

<script type="text/javascript" src="../js/common/webgl-utils.js"></script>
<script type="text/javascript" src="../js/common/initShaders.js"></script>
<script type="text/javascript" src="../js/common/gl-matrix-min.js"></script>

<script type="text/javascript" src="../js/ch02/a.js"></script>

<script>
window.onload = function() {
AppA.init();
};
</script>
</head>

<body>
<h2>Sierpinski Gasket in 2D</h2>
<canvas id="gl-canvas-a" width="512" height="512">你的浏览器不支持HTML5 canvas元素</canvas>
<!-- 滑块控件 -->
<div>
<label for="subdivision-slider-a">剖分层次:</label>
<input type="range" id="subdivision-slider-a" min="0" max="7" step="1">
<span id="slider-value-a">4</span>
</div>

</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// a.js
"use strict";

const {
vec3
} = glMatrix;

var AppA = {
canvas: null,
gl: null,
points: [],
numTimesToSubdivide: 4,

init: function() {
this.canvas = document.getElementById("gl-canvas-a");
this.gl = this.canvas.getContext("webgl2");
if (!this.gl) {
alert("WebGL isn't available");
}

this.gl.enable(this.gl.DEPTH_TEST);
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);

// 初始化滑块控件并设置事件监听器
const sliderA = document.getElementById("subdivision-slider-a");
const sliderValueA = document.getElementById("slider-value-a");
sliderA.value = this.numTimesToSubdivide;
sliderValueA.innerHTML = this.numTimesToSubdivide;

sliderA.oninput = (function() {
this.numTimesToSubdivide = parseInt(sliderA.value);
sliderValueA.innerHTML = this.numTimesToSubdivide;
this.points = [];
this.divideTriangle(vec3.fromValues(-1, -1, 0), vec3.fromValues(0, 1, 0), vec3.fromValues(1,
-1, 0), this.numTimesToSubdivide);
this.renderTriangles();
}).bind(this);

// 初始化三角形
this.divideTriangle(vec3.fromValues(-1, -1, 0), vec3.fromValues(0, 1, 0), vec3.fromValues(1, -1, 0),
this.numTimesToSubdivide);

// 配置 WebGL
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
this.gl.clearColor(1.0, 1.0, 1.0, 1.0);

// 加载着色器并初始化缓冲区
var programA = initShaders(this.gl, "vertex-shader-a", "fragment-shader-a");
this.gl.useProgram(programA);

var vertexBufferA = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, vertexBufferA);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.points), this.gl.STATIC_DRAW);

var vPositionA = this.gl.getAttribLocation(programA, "vPosition");
this.gl.vertexAttribPointer(vPositionA, 3, this.gl.FLOAT, false, 0, 0);
this.gl.enableVertexAttribArray(vPositionA);

this.renderTriangles();
},

triangle: function(a, b, c) {
this.points.push(a[0], a[1], a[2]);
this.points.push(b[0], b[1], b[2]);
this.points.push(c[0], c[1], c[2]);
},

divideTriangle: function(a, b, c, count) {
if (count == 0) {
this.triangle(a, b, c);
} else {
var ab = vec3.create();
vec3.lerp(ab, a, b, 0.5);
var bc = vec3.create();
vec3.lerp(bc, b, c, 0.5);
var ca = vec3.create();
vec3.lerp(ca, c, a, 0.5);

this.divideTriangle(a, ab, ca, count - 1);
this.divideTriangle(b, bc, ab, count - 1);
this.divideTriangle(c, ca, bc, count - 1);
}
},

renderTriangles: function() {
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.points), this.gl.STATIC_DRAW);
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.points.length / 3);
}
};

例:剖分层次为4层的图形如下:

taska.html页面链接

2.taskb.html+b.js

任务b. 绘制三维效果的Sierpinski Gasket, 要求同任务a,可与任务a集成在同一个界面中。(详细代码略)
例:剖分层次为4层的图形如下:

taskb.html页面链接

3.taskc.html+c.js

任务c. 完成不同层次剖分效果的绘制,这里的绘制采用线框模式,可以同任务a及任务b集成在同一个界面中。(详细代码略)
例:剖分层次为4层的图形如下:

taskc.html页面链接

4.taskd.html+d.js

任务d. 对任务c中剖分后的三角形添加旋转效果。只涉及二维平面,让图案在xoy平面上绕原点逆时针旋转(详细代码略)
例:旋转角度为60°,剖分层次为4层的图形如下:

taskd.html页面链接

5.taske.html+e.js

任务e. 在任务d的基础上,旋转角度根据点到原点的距离d设定。(详细代码略)
例:旋转角度为180°,剖分层次为4层的图形如下:

taske.html页面链接

whole.html+a.js+b.js+c.js+d.js+e.js

将任务a至任务e集成在一个交互式界面中,不同的任务对应不同的选项及参数设置,用同一套控件完成相应选项及参数的设置。(详细代码略)
效果如下:

whole.html页面链接

以上所有完整代码在我的github库存放


Computer Graphics Lab2
https://curreny.github.io/2024/09/28/post2/
作者
Curreny
发布于
2024年9月28日
许可协议