投影是指将三维空间中的对象或图形映射到二维平面上的过程。在计算机图形学中,投影是一个重要的概念,因为屏幕上只有二维的显示空间,需要将三维场景投影到屏幕上才能呈现给用户。投影有两种常见的方式:透视投影和正交投影。透视投影模拟了真实世界的视觉效果,使远处的物体更小,近处的物体更大,增强了视觉感受。而正交投影则是在平面上进行垂直投影,可以保留物体的大小和比例,但会失去深度感。无论是哪种投影方式,都需要计算投影矩阵来进行投影。
透视投影是一种绘画和制图技术,它模拟了人眼在三维空间中观察物体时所产生的视觉效果。透视投影通过将一个三维物体映射到一个二维平面上,来呈现物体的透视感和深度感。透视投影表现了物体在远近和大小上的变化,使画面具有更真实的呈现效果,并且可以更好地传递画家或设计者想表达的信息。在建筑设计、室内设计、工程制图和艺术绘画等领域中,透视投影被广泛应用。

把透视投影的棱台映射为长方体


通过三角形相似,很容易得到物品投影到投影面上的横纵坐标


第二个矩阵位正射投影的矩阵



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../lib/index.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
canvas{
margin: 50px auto 0;
display: block;
background: yellow;
}
</style>
</head>
<body>
<canvas id="canvas" width="400" height="400">
此浏览器不支持canvas
</canvas>
</body>
</html>
<script>
// 获取透视投影矩阵
function getPerspective(fov, aspect, far, near) {
fov = fov * Math.PI / 180;
return new Float32Array([
1/(aspect*Math.tan(fov / 2)), 0, 0, 0,
0, 1/(Math.tan(fov/2)),0,0,
0,0,-(far+near)/(far-near),-(2*far*near)/(far-near),
0,0,-1,0,
])
}
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
attribute vec4 aColor;
varying vec4 vColor;
uniform mat4 mat;
void main() {
gl_Position = mat * aPosition;
vColor = aColor;
}
`; // 顶点着色器
const FRAGMENT_SHADER_SOURCE = `
precision lowp float;
varying vec4 vColor;
void main() {
gl_FragColor = vColor;
}
`; // 片元着色器
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition');
const aColor = gl.getAttribLocation(program, 'aColor');
const mat = gl.getUniformLocation(program, 'mat');
const points = new Float32Array([
0.75,1.0,-0.6, 1.0,0.0,0.0,
0.25,-1.0,-0.6, 1.0,0.0,0.0,
1.0, -1.0,-0.6, 1.0,0.0,0.0,
0.75,1.0,-0.5, 0.0,1.0,0.0,
0.25,-1.0,-0.5, 0.0,1.0,0.0,
1.0, -1.0,-0.5, 0.0,1.0,0.0,
0.75,1.0,-0.4, 0.0,0.0,1.0,
0.25,-1.0,-0.4, 0.0,0.0,1.0,
1.0, -1.0,-0.4, 0.0,0.0,1.0,
-0.75,1.0,-0.6, 1.0,0.0,0.0,
-0.25,-1.0,-0.6, 1.0,0.0,0.0,
-1.0, -1.0,-0.6, 1.0,0.0,0.0,
-0.75,1.0,-0.5, 0.0,1.0,0.0,
-0.25,-1.0,-0.5, 0.0,1.0,0.0,
-1.0, -1.0,-0.5, 0.0,1.0,0.0,
-0.75,1.0,-0.4, 0.0,0.0,1.0,
-0.25,-1.0,-0.4, 0.0,0.0,1.0,
-1.0, -1.0,-0.4, 0.0,0.0,1.0,
])
const buffer = gl.createBuffer();
const BYTES = points.BYTES_PER_ELEMENT;
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, BYTES * 6, 0);
gl.enableVertexAttribArray(aPosition)
gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, BYTES * 6, BYTES * 3);
gl.enableVertexAttribArray(aColor)
gl.drawArrays(gl.TRIANGLES, 0, 3 * 6);
let eyex = 0.0;
let eyey = -0.1;
let eyez = 0.2;
function draw() {
const vm = getViewMatrix(eyex,eyey,eyez,0.0,0.0,0.0,0.0,0.6,0.0);
const perspective = getPerspective(150, ctx.width / ctx.height, 100, 1);
// const matrix = getTranslateMatrix(x, x);
// gl.vertexAttrib1f(aTranslate, x);
gl.enable(gl.DEPTH_TEST);
gl.uniformMatrix4fv(mat, false, mixMatrix(vm, perspective));
gl.drawArrays(gl.TRIANGLES, 0, 3 * 6);
}
draw()
document.onkeydown = function(e) {
switch(e.keyCode) {
case 37: eyex += 0.01; break;
case 38: eyex -= 0.01; break;
case 39: eyey += 0.01; break;
case 40: eyey -= 0.01; break;
}
draw();
}
</script>