实验内容
- 已知某三角形的三顶点坐标{0.0,1.0},{-1.0,-1.0},{1.0,-1.0}。绘制一个由上述顶点所描绘的三角形;对三角形进行下列的几何变换:首先使三角形沿着其中心的x轴,y轴方向缩小到原来的25%;然后绕中心旋转-90度;最后沿着x轴平移0.5个单位,绘制出变换后的结果。通过按键或者鼠标点击来控制变换的执行。
- 绘制一个彩色的正三棱锥,对三棱锥分别进行缩放、旋转和平移变换,绘制出变换后的结果。正三棱锥四个顶点坐标可以取 ( 0.0, 0.0, -1.0 ), ( 0.0, 0.942809, 0.333333 ), ( -0.816497, -0.471405, 0.333333 ), ( 0.816497, -0.471405, 0.333333 )。
- 通过摆放摄像机,绘制上题三棱锥的透视投影图,并使三棱锥旋转起来,通过按键来选择旋转轴(x轴,y轴或z轴)。
实验设计思路
任务1:总体和实验一中的绘制三角形变化不大,和之前的相比,多了变换矩阵。这里采用glMatrix的mat4里的相关功能,如生成平移矩阵mat4.translate(),生成旋转矩阵mat4.rotateX(),生成缩放矩阵mat4.scale(),矩阵乘法mat4.multiply()等来进行图形变换操作。首先创建一个单位矩阵modelMatrix,当变换时,modelMatrix左乘变换矩阵再将计算结果传入着色器中进行一次绘制即可得到变换后的图形。
任务2:将任务1中二维的点改为三维的点,并修改索引和颜色,得到正三棱锥的数据。这里比前面多了视图矩阵和正交投影矩阵,因此在着色器中应当将mvpMatrix拆开成modelMatrix,visionMatrix,orthoMatrix,gl_Position的结果为orthoMatrix * visionMatrix * modelMatrix *vec4(position,1.0)。在着色器外分别计算出模型矩阵、视图矩阵、正交投影矩阵并传入着色器。
任务3:将任务2中的正交投影矩阵orthoMatrix改为透视投影矩阵perspectiveMatrix,其他差别不大。
实验结果
任务1
任务2
任务3
绕x轴旋转
绕y轴旋转
绕z轴旋转
实验代码
任务1
// 获取WebGL上下文
const canvas = document.getElementById('webglCanvas');
const gl = canvas.getContext('webgl');
//编写Shader代码并编译
const vertexShaderSource = `
attribute vec2 position;
uniform mat4 mvpMatrix;
void main() {
gl_Position = mvpMatrix * vec4(position, 0.0, 1.0);
}
`;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
}
`;
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
//创建并设置着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
//初始化数据
const vertices = new Float32Array([
-1, -1,
0, 1,
1, -1
]);
var mvpMatrix = glMatrix.mat4.create();
// 创建顶点缓冲区
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
//传入顶点数据
const positionAttributeLocation = gl.getAttribLocation(shaderProgram, 'position');
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionAttributeLocation);
//传入默认mvp矩阵数据
const mvpMatrixUniformLocation = gl.getUniformLocation(shaderProgram, 'mvpMatrix');
gl.uniformMatrix4fv(mvpMatrixUniformLocation, false, mvpMatrix);
//绘制初始图形
gl.clearColor(0, 0, 0, 0.5)
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
//平移、旋转、缩放
function rotate1() {
let rotateMatrix = glMatrix.mat4.rotateZ(glMatrix.mat4.create(), glMatrix.mat4.create(), -Math.PI / 2);
mvpMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), rotateMatrix, mvpMatrix);
drawTriangle();
}
function translate1() {
let translateMatrix = glMatrix.mat4.translate(glMatrix.mat4.create(), glMatrix.mat4.create(), [0.5, 0, 0]);
mvpMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), translateMatrix, mvpMatrix);
drawTriangle();
}
function scale1() {
let scaleMatrix = glMatrix.mat4.scale(glMatrix.mat4.create(), glMatrix.mat4.create(), [0.25, 0.25, 1]);
mvpMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), scaleMatrix, mvpMatrix);
drawTriangle();
}
//绘制图形
function drawTriangle() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniformMatrix4fv(mvpMatrixUniformLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
任务2
// 获取WebGL上下文
const canvas = document.getElementById('webglCanvas');
const gl = canvas.getContext('webgl');
var transformMatrix = [];
// 编写Shader代码并编译
const vertexShaderSource = `
attribute vec3 position;
attribute vec3 color;
uniform mat4 transformMatrix;
uniform mat4 visionMatrix;
uniform mat4 orthoMatrix;
varying vec3 vColor;
void main() {
gl_Position =orthoMatrix* visionMatrix * transformMatrix * vec4(position, 1.0);
vColor = color;
}
`;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
const fragmentShaderSource = `
precision mediump float;
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor ,1.0);
}
`;
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
//创建并设置着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
//初始化数据
const vertices = new Float32Array([
0, 0, -1,
0, 0.942809, 0.333333,
-0.816497, -0.471405, 0.333333,
0.816497, -0.471405, 0.333333
]);
const indices = new Uint16Array([
1, 2, 3,
1, 2, 0,
1, 3, 0,
2, 3, 0,
]);
const colors = new Float32Array([
1, 0, 0,
0, 1, 0,
0, 0, 1,
1, 1, 0,
])
// 创建缓冲区并传入数据
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const positionAttributeLocation = gl.getAttribLocation(shaderProgram, 'position');
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionAttributeLocation);
const indicesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
const colorAttributeLocation = gl.getAttribLocation(shaderProgram, 'color');
gl.vertexAttribPointer(colorAttributeLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(colorAttributeLocation);
//设置默认模型矩阵
const modelMatrixUniformLocation = gl.getUniformLocation(shaderProgram, 'transformMatrix');
var modelMatrix = glMatrix.mat4.create();
gl.uniformMatrix4fv(modelMatrixUniformLocation, false, modelMatrix);
//设置视图矩阵
const visionMatrixUniformLocation = gl.getUniformLocation(shaderProgram, 'visionMatrix');
const eye = glMatrix.vec3.fromValues(0, 0, 1);
const look = glMatrix.vec3.fromValues(0, 0, 0);
const up = glMatrix.vec3.fromValues(0, 1, 0);
const visionMatrix = glMatrix.mat4.lookAt(glMatrix.mat4.create(), eye, look, up);
gl.uniformMatrix4fv(visionMatrixUniformLocation, false, visionMatrix);
//设置正交投影矩阵
const orthoMatrixUniformLocation = gl.getUniformLocation(shaderProgram, 'orthoMatrix');
const orthoMatrix = glMatrix.mat4.ortho(glMatrix.mat4.create(), -1, 1, -1, 1, -100, 100);
gl.uniformMatrix4fv(orthoMatrixUniformLocation, false, orthoMatrix);
//绘制初始图形
gl.clearColor(0, 0, 0, 0.5);
gl.enable(gl.DEPTH_TEST)
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
//功能相关
function rotateX() {
let rotateMatrix = glMatrix.mat4.rotateX(glMatrix.mat4.create(), glMatrix.mat4.create(), -Math.PI / 2);
modelMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), rotateMatrix, modelMatrix);
drawTriangle();
}
function rotateY() {
let rotateMatrix = glMatrix.mat4.rotateY(glMatrix.mat4.create(), glMatrix.mat4.create(), -Math.PI / 2);
modelMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), rotateMatrix, modelMatrix);
drawTriangle();
}
function rotateZ() {
let rotateMatrix = glMatrix.mat4.rotateZ(glMatrix.mat4.create(), glMatrix.mat4.create(), -Math.PI / 2);
modelMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), rotateMatrix, modelMatrix);
drawTriangle();
}
function translate1() {
let translateMatrix = glMatrix.mat4.translate(glMatrix.mat4.create(), glMatrix.mat4.create(), [0.5, 0, 0]);
modelMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), translateMatrix, modelMatrix);
drawTriangle();
}
function scale1() {
let scaleMatrix = glMatrix.mat4.scale(glMatrix.mat4.create(), glMatrix.mat4.create(), [0.25, 0.25, 0.25]);
modelMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), scaleMatrix, modelMatrix);
drawTriangle();
}
function drawTriangle() {
gl.clearColor(0, 0, 0, 0.5)
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniformMatrix4fv(modelMatrixUniformLocation, false, modelMatrix);
gl.drawElements(gl.TRIANGLES, 12, gl.UNSIGNED_SHORT, 0)
}
任务3
// 获取WebGL上下文
const canvas = document.getElementById('webglCanvas');
const gl = canvas.getContext('webgl');
// 初始化着色器
const vertexShaderSource = `
attribute vec3 a_Position;
attribute vec3 a_Color;
uniform mat4 modelMatrix;
uniform mat4 visionMatrix;
uniform mat4 perspectiveMatrix;
varying vec3 v_Color;
void main() {
gl_Position =perspectiveMatrix* visionMatrix * modelMatrix * vec4(a_Position, 1.0);
v_Color = a_Color;
}
`;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
const fragmentShaderSource = `
precision mediump float;
varying vec3 v_Color;
void main() {
gl_FragColor = vec4(v_Color ,1.0);
}
`;
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
//创建并设置着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
//初始化数据
const vertices = new Float32Array([
0, 0, -1,
0, 0.942809, 0.333333,
-0.816497, -0.471405, 0.333333,
0.816497, -0.471405, 0.333333
]);
const indices = new Uint16Array([
1, 2, 3,
1, 2, 0,
1, 3, 0,
2, 3, 0,
]);
const colors = new Float32Array([
1, 0, 0,
0, 1, 0,
0, 0, 1,
1, 1, 0,
])
var t1, t2, t3 = null; //t1,t2,t3作为三种旋转的计时器
// 传入数据
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const positionAttributeLocation = gl.getAttribLocation(shaderProgram, 'a_Position');
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(positionAttributeLocation);
const indicesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
const colorAttributeLocation = gl.getAttribLocation(shaderProgram, 'a_Color');
gl.vertexAttribPointer(colorAttributeLocation, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(colorAttributeLocation);
//设置模型变换矩阵
const modelMatrixUniformLocation = gl.getUniformLocation(shaderProgram, 'modelMatrix');
var modelMatrix = glMatrix.mat4.create();
gl.uniformMatrix4fv(modelMatrixUniformLocation, false, modelMatrix);
//设置视图变换矩阵
const visionMatrixUniformLocation = gl.getUniformLocation(shaderProgram, 'visionMatrix');
const eye = glMatrix.vec3.fromValues(1, 1, 2);
const look = glMatrix.vec3.fromValues(1, 1, 0);
const up = glMatrix.vec3.fromValues(0, 1, 0);
const visionMatrix = glMatrix.mat4.lookAt(glMatrix.mat4.create(), eye, look, up);
gl.uniformMatrix4fv(visionMatrixUniformLocation, false, visionMatrix);
//设置透视投影矩阵
const perspectiveMatrixUniformLocation = gl.getUniformLocation(shaderProgram, 'perspectiveMatrix');
const perspectiveMatrix = glMatrix.mat4.perspective(glMatrix.mat4.create(), Math.PI / 2, 1 / 1, 1, -100);
gl.uniformMatrix4fv(perspectiveMatrixUniformLocation, false, perspectiveMatrix);
gl.clearColor(0, 0, 0, 0.5);
gl.enable(gl.DEPTH_TEST)
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, 12, gl.UNSIGNED_SHORT, 0);
//功能相关
function rotateX() {
clearInterval(t1);
clearInterval(t2);
clearInterval(t3);
t1 = setInterval(function () {
let rotateMatrix = glMatrix.mat4.rotateX(glMatrix.mat4.create(), glMatrix.mat4.create(), -Math.PI / 200);
modelMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), rotateMatrix, modelMatrix);
drawTriangle();
}, 10)
}
function rotateY() {
clearInterval(t1);
clearInterval(t2);
clearInterval(t3);
t2 = setInterval(function () {
let rotateMatrix = glMatrix.mat4.rotateY(glMatrix.mat4.create(), glMatrix.mat4.create(), -Math.PI / 200);
modelMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), rotateMatrix, modelMatrix);
drawTriangle();
}, 10)
}
function rotateZ() {
clearInterval(t1);
clearInterval(t2);
clearInterval(t3);
t3 = setInterval(function () {
let rotateMatrix = glMatrix.mat4.rotateZ(glMatrix.mat4.create(), glMatrix.mat4.create(), -Math.PI / 200);
modelMatrix = glMatrix.mat4.multiply(glMatrix.mat4.create(), rotateMatrix, modelMatrix);
drawTriangle();
}, 10)
}
function drawTriangle() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniformMatrix4fv(modelMatrixUniformLocation, false, modelMatrix);
gl.drawElements(gl.TRIANGLES, 12, gl.UNSIGNED_SHORT, 0)
}