实验内容
- 修改程序HelloPoint2,使用uniform变量来获取颜色值。
- 绘制曲线
。参考程序MultiPoint。
- 通过点击鼠标选取点绘制三角形,添加菜单改变三角形的颜色。
参考程序ClickedPoints和rotatingSquare2。
实验设计思路
注:由于只有实验相关的文档,给我提供文档的人没有给我相关的示例代码,因此所有的程序都是自己编写,非常可能与示例程序有较大出入,但是实现的原理基本一致。后面的几篇实验也是如此。实验中要求使用cuon-matrix.js作为矩阵操作函数库,而这里是用glMatrix.js作为矩阵操作函数库。
任务1:最基本的webgl在canvas上进行图形绘制操作。以下是需要实现的步骤
①获取webgl上下文
②编写顶点着色器和片元着色器
③创建和编译着色器
④创建着色器程序并链接
⑤准备顶点数据并创建缓冲区
⑥向着色器程序传入所需的数据
⑦进行绘图操作
任务2:将曲线细分为大量的点,再将这些点用直线连起来,能够得到非常接近该曲线的图形
任务3:对canvas画布进行onclick事件绑定,发生点击事件后,通过点击事件的坐标,计算出点击的点在画布中的坐标{ (x,y)|x∈[-1,1],y∈[-1,1] },并将该点记录到indices数组中。当indices数组满足绘制三角形所需的顶点个数时,进行绘制操作。设置三个改变颜色的button,点击后会向着色器程序传入对应的颜色数据,并进行重新绘制。
实验结果
任务1
任务2
任务3
实验代码
任务1
//获取上下文
const canvas = document.getElementById("my_Canvas");
gl = canvas.getContext("experimental-webgl");
//编写Shader代码,并编译
const vertCode =
'attribute vec3 coordinates;' +
'void main(void){' +
'gl_Position = vec4(coordinates,1.0);' +
'}';
const vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
const fragCode =
'precision mediump float;' +
'uniform vec3 u_Color;' +
'void main(void){' +
'gl_FragColor = vec4(u_Color, 1.0);' +
'}';
const fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//创建并设置着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
//定义顶点,索引
const vertices = new Float32Array([
-0.5, 0.5, 0.0,
-0.5, -0.5, 0.0,
1, -1, 0.0,
]);
const indices = new Uint16Array([
0, 1, 2
]);
//创建缓冲区并向缓冲区传入数据
const vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const index_Buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_Buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
//利用缓冲区向attribute变量传入数据
const coord = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coord);
//向uniform变量传入数据
const u_ColorLocation = gl.getUniformLocation(shaderProgram, 'u_Color');
gl.uniform3f(u_ColorLocation, 1.0, 0.0, 0.0);
//进行绘制
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
任务2
//获取上下文
const canvas = document.getElementById("my_Canvas");
const gl = canvas.getContext("experimental-webgl");
//编写Shader代码,并编译
const vertCode =
'attribute vec3 coordinates;' +
'void main(void){' +
'gl_Position = vec4(coordinates,1.0);' +
'}';
const vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
const fragCode =
'precision mediump float;' +
'void main(void){' +
'gl_FragColor = vec4(0,0,0, 1);' +
'}';
const fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//创建并设置着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
//求出曲线上的点
var vertices = [];
const dx = 0.01;
for (let i = -1; i <= 1; i = i + dx) {
vertices.push(i); //x轴坐标
vertices.push((Math.E ** (-i)) * Math.cos(2 * i * Math.PI)); //y轴坐标
vertices.push(0); //z轴坐标
}
//创建缓冲区并向缓冲区传入数据
const vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
//利用缓冲区向attribute变量传入数据
const coord = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coord);
//绘制
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.LINE_STRIP, 0, vertices.length / 3);
任务3
//获取上下文
const canvas = document.getElementById("my_Canvas");
gl = canvas.getContext("experimental-webgl");
//编写Shader代码,并编译
const vertCode =
'attribute vec3 coordinates;' +
'void main(void){' +
'gl_Position = vec4(coordinates,1.0);' +
'}';
const vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
const fragCode =
'precision mediump float;' +
'uniform vec4 u_Color;' +
'void main(void){' +
'gl_FragColor = vec4(u_Color);' +
'}';
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//创建并设置着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
//定义顶点,并创建对应的缓冲区
var vertices = [];
const vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
//传入顶点数据
const coord = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coord);
//设置默认颜色为黑色
const color = gl.getUniformLocation(shaderProgram, 'u_Color');
gl.uniform4f(color, 0.0, 0.0, 0.0, 1.0);
//初始化画布
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT);
//对canvas画布绑定点击需要处理的事件
canvas.addEventListener('click', function (event) {
const click_x = event.clientX;
const click_y = event.clientY;
let x = (click_x / canvas.width) * 2 - 1;
let y = 1 - (click_y / canvas.height) * 2;
//z轴坐标默认为0,将顶点数据压入vertices数组,当其满足绘制三角形的条件时进行一次绘制
vertices.push(x, y, 0);
if (vertices.length % 9 == 0) {
draw();
}
})
//以下三个为切换颜色按钮的事件
function toRed() {
gl.uniform4f(color, 1.0, 0.0, 0.0, 1.0);
draw();
}
function toGreen() {
gl.uniform4f(color, 0.0, 1.0, 0.0, 1.0);
draw();
}
function toBlue() {
gl.uniform4f(color, 0.0, 0.0, 1.0, 1.0);
draw();
}
//绘制操作
function draw() {
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, vertices.length);
}