Lab3

预览
taska页面链接
taskb页面链接

1.taska.html+rotsquareslider.js

任务a. 复刻旋转的正方形示例,可通过滑杆拖拉选择包括正n边方形、控制转动速度快慢、选择转动方向

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
<!--taska.html-->

<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Chap3 Demo -- Rotating Square Slider</title>
<style>
body {
text-align: center;
font-family: Arial, sans-serif;
}

button {
background-color: #4CAF50;
border: none;
color: white;
padding: 10px 20px;
text-align: center;
cursor: pointer;
border-radius: 12px;
}
</style>
<script id="rot-v-shader" type="x-shader/x-vertex">
#version 300 es
in vec4 vPosition;
uniform float theta;

void main()
{
float u = cos( theta );
float v = sin( theta );

gl_Position.x = vPosition.x * u - vPosition.y * v;
gl_Position.y = vPosition.x * v + vPosition.y * u;
gl_Position.z = 0.0;
gl_Position.w = 1.0;
}
</script>

<script id="rot-f-shader" 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/ch03/rotsquareslider.js"></script>
</head>

<body onload="initRotSquare()">
<h1>Control rotation using Menus</h1><br>
<canvas id="rot-canvas" width="512" height="512">你的浏览器不支持HTML5 canvas元素</canvas>
<br><br><br><br>
<button id="direction" onclick="changeDir()">换个转动方向</button><br><br>
Speed<input type="range" id="speedcon" min="0" max="100" value="50" step="1">
<span id="speedValue">50</span><br><br>

选择正多边形边数:<input type="range" id="sidesRange" min="3" max="20" value="4" step="1">
<span id="sidesValue">4</span> 边形
</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
91
// rotsquareslider.js
"use strict";

var canvas;
var gl;

var theta = 0.0;
var thetaLoc;
var direction = 1;
var speed = 50;
var sides = 4; // 默认值为四边形

function changeDir() {
direction *= -1;
}

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

gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);

var program = initShaders(gl, "rot-v-shader", "rot-f-shader");
gl.useProgram(program);

// 根据 sides 动态生成顶点
updateVertices(sides);

thetaLoc = gl.getUniformLocation(program, "theta");

// 更新速度滑杆
document.getElementById("speedcon").oninput = function(event) {
speed = 100 - event.target.value;
updateSpeedDisplay(event.target.value);
}

// 更新边数滑杆
document.getElementById("sidesRange").oninput = function(event) {
sides = event.target.value;
updatePolygonSidesDisplay(sides); // 实时更新显示边数
updateVertices(sides); // 更新多边形的顶点
}

renderSquare();
}

// 生成多边形的顶点
function updateVertices(numSides) {
var vertices = [];
var angleStep = (2 * Math.PI) / numSides;

for (var i = 0; i < numSides; i++) {
var angle = i * angleStep;
vertices.push(Math.cos(angle), Math.sin(angle), 0);
}

vertices = new Float32Array(vertices);

// 创建并绑定缓冲区
var bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

var vPosition = gl.getAttribLocation(gl.getParameter(gl.CURRENT_PROGRAM), "vPosition");
gl.vertexAttribPointer(vPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
}

function renderSquare() {
gl.clear(gl.COLOR_BUFFER_BIT);
theta += direction * 0.1;
gl.uniform1f(thetaLoc, theta);
gl.drawArrays(gl.TRIANGLE_FAN, 0, sides); // 使用 TRIANGLE_FAN 绘制多边形
setTimeout(function() {
requestAnimFrame(renderSquare);
}, speed);
}

// 实时更新速度值
function updateSpeedDisplay(value) {
document.getElementById("speedValue").textContent = value;
}

// 实时更新边数值
function updatePolygonSidesDisplay(value) {
document.getElementById("sidesValue").textContent = value;
}

taska页面链接


2.taskb.html

任务b. 旋转的正方形与移动的圆形。可通过方向键”上下左右”控制圆形移动的速度。

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
91
92
93
94
95
96
97
98
99
100
101
102
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>计算机图形学作业 - 动画作品</title>
<style>
canvas {
border: 1px solid black;
display: block;
margin: 0 auto;
}

body {
text-align: center;
}
</style>
</head>
<body>
<h1>旋转的正方形与移动的圆形</h1>
<canvas id="animationCanvas" width="600" height="400"></canvas>
<p>通过方向键"上下左右"控制圆形移动的速度</p>

<script>
const canvas = document.getElementById('animationCanvas');
const ctx = canvas.getContext('2d');

// 动画元素 - 正方形
let squareAngle = 0;
let squareSpeed = 0.03;

// 动画元素 - 圆形
let circleX = 300;
let circleY = 200;
let circleRadius = 30;
let circleSpeedX = 2;
let circleSpeedY = 1.5;

// 交互行为 - 使用方向键控制圆形移动速度
document.addEventListener('keydown', function(event) {
if (event.key === 'ArrowUp') {
circleSpeedY -= 0.2; // 向上移动
} else if (event.key === 'ArrowDown') {
circleSpeedY += 0.2; // 向下移动
} else if (event.key === 'ArrowLeft') {
circleSpeedX -= 0.2; // 向左移动
} else if (event.key === 'ArrowRight') {
circleSpeedX += 0.2; // 向右移动
}
});

function drawSquare() {
const squareSize = 80;
ctx.save();
ctx.translate(150, 150); // 正方形中心点
ctx.rotate(squareAngle); // 旋转
ctx.fillStyle = 'red';
ctx.fillRect(-squareSize / 2, -squareSize / 2, squareSize, squareSize);
ctx.restore();
}

function drawCircle() {
ctx.beginPath();
ctx.arc(circleX, circleY, circleRadius, 0, 2 * Math.PI);
ctx.fillStyle = 'blue';
ctx.fill();
ctx.closePath();
}

function update() {
// 更新正方形角度
squareAngle += squareSpeed;

// 更新圆形位置
circleX += circleSpeedX;
circleY += circleSpeedY;

// 碰撞检测,防止圆形移出画布
if (circleX + circleRadius > canvas.width || circleX - circleRadius < 0) {
circleSpeedX = -circleSpeedX;
}
if (circleY + circleRadius > canvas.height || circleY - circleRadius < 0) {
circleSpeedY = -circleSpeedY;
}
}

function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除画布
drawSquare(); // 绘制旋转正方形
drawCircle(); // 绘制移动圆形
}

function animate() {
update(); // 更新动画状态
draw(); // 绘制动画帧
requestAnimationFrame(animate); // 循环调用动画
}

// 初始化动画
animate();
</script>
</body>
</html>

taskb页面链接