基本概念
图形变换
平移
所有顶点移动
javascript
<script id="vertexShader" type="x-shader/x-vertex">
atrribute vec4 a_Position;
uniform vec4 u_Translation;
void main() {
gl_Position = a_Position + u_Translation;
}
</script>
a_Position 是原始点,属于 attribute 变量
u_Translation 是用来作为改变原始点的为一的变量
为什么 u_Translation 不是使用 attribute 来定义?
原因是 attribute 定义的变量是跟顶点强相关的,也就是只有原始顶点才用它,其他的变换位置的变量(u_Translation)都是使用 uniform 来定义。
实现三角形沿着 y 轴进行平移

html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图形变换-平移</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
// 一个属性值,将会从缓冲区中获取数据
attribute vec4 a_Position;
attribute float a_PointSize;
uniform vec4 u_Translation;
// 所有着色器都有一个 main 方法
void main() {
// gl_Position 是一个顶点着色器主要设置的变量
gl_Position = a_Position + u_Translation;
gl_PointSize = a_PointSize;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_FragColor;
void main() {
gl_FragColor = u_FragColor;
}
</script>
<script type="module">
import { getPosByMouse, getInnerText, initShaderProgram } from "../utils/index.js"
const canvas = document.querySelector('#canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const gl = canvas.getContext('webgl');
gl.clearColor(0, 0, 0, 1);
const vertexStr = getInnerText("vertexShader");
const fragmentStr = getInnerText("fragmentShader");
const program = initShaderProgram(gl, vertexStr, fragmentStr )
let a_Position = gl.getAttribLocation(program, 'a_Position');
let a_PointSize = gl.getAttribLocation(program, 'a_PointSize');
let u_FragColor = gl.getUniformLocation(program, 'u_FragColor');
let u_Translation = gl.getUniformLocation(program, 'u_Translation');
gl.useProgram(program);
let vertices = [0.0, 0.5, 1, 0.5, 0, 1]
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.vertexAttrib1f(a_PointSize, 5);
gl.uniform4fv(u_FragColor, new Float32Array([1, 0, 1, 1]));
// 渲染
function render() {
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
let y = 0.01;
!(function ani(){
if(y >= 1) {
y = -1;
}
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform4fv(u_Translation, new Float32Array([0, y, 0, 1]));
y += 0.01;
render();
requestAnimationFrame(ani);
})();
</script>
</body>
</html>
旋转
三维物体的旋转需要知道以下条件:
旋转轴
旋转方向
旋转角度
在着色器中旋转:
javascript
<script id="vertexShader" type="x-shader/x-vertex">
// 一个属性值,将会从缓冲区中获取数据
attribute vec4 a_Position;
float angle = radians(80.0);
float sinB = sin(angle);
float cosB = cos(angle);
// 所有着色器都有一个 main 方法
void main() {
gl_Position.x = a_Position.x * cosB - a_Position.y * sinB;
gl_Position.y = a_Position.y * cosB - a_Position.x * sinB;
gl_Position.z = a_Position.z;
gl_Position.w = 1.0;
}
</script>
radians(float degree) 将角度转弧度
sin(float angle) 正弦
cos(float angle) 余弦
实现图形旋转,利用 js 进行传值旋转

html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图形变换-旋转</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
// 一个属性值,将会从缓冲区中获取数据
attribute vec4 a_Position;
// radians是着色器中的函数, 将角度转弧度
// float angle = radians(30.0);
// float sinB = sin(angle);
// float cosB = cos(angle);
uniform float u_CosB;
uniform float u_SinB;
void main() {
gl_Position.x = a_Position.x * u_CosB - a_Position.y * u_SinB;
gl_Position.y = a_Position.y * u_CosB - a_Position.x * u_SinB;
gl_Position.z = a_Position.z;
gl_Position.w = 1.0;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_FragColor;
void main() {
gl_FragColor = u_FragColor;
}
</script>
<script type="module">
import { getPosByMouse, getInnerText, initShaderProgram } from "../utils/index.js"
const canvas = document.querySelector('#canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const gl = canvas.getContext('webgl');
const vertexStr = getInnerText("vertexShader");
const fragmentStr = getInnerText("fragmentShader");
const program = initShaderProgram(gl, vertexStr, fragmentStr )
let a_Position = gl.getAttribLocation(program, 'a_Position');
let u_FragColor = gl.getUniformLocation(program, 'u_FragColor');
let u_CosB = gl.getUniformLocation(program, 'u_CosB');
let u_SinB = gl.getUniformLocation(program, 'u_SinB');
gl.useProgram(program);
let vertices = [0.0, 0.5, 1, 0.5, 0, 1]
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform4fv(u_FragColor, new Float32Array([1, 0, 1, 1]));
gl.clearColor(0, 0, 0, 1);
// 渲染
function render() {
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
let angle = 3.0;
!(function ani(){
angle += 0.02
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform1f(u_CosB, Math.cos(angle));
gl.uniform1f(u_SinB, Math.sin(angle));
render();
requestAnimationFrame(ani);
})()
</script>
</body>
</html>
缩放
可以理解为对向量长度的改变,或者对向量坐标分量的同步缩放
在着色器中缩放
1、对 gl_Position 的 x、y、z依次缩放
javascript
<script id="vertexShader" type="x-shader/x-vertex">
// 一个属性值,将会从缓冲区中获取数据
attribute vec4 a_Position;
float scale = 1.2;
void main() {
gl_Position.x = a_Position.x * scale;
gl_Position.y = a_Position.y * scale;
gl_Position.z = a_Position.z * scale;
gl_Position.w = 1.0;
}
</script>
2、对 a_Position 中 抽离出由 x、y、z组成的三维向量,对其一次性缩放
javascript
<script id="vertexShader" type="x-shader/x-vertex">
// 一个属性值,将会从缓冲区中获取数据
attribute vec4 a_Position;
float scale = 1.2;
void main() {
gl_Position = vec4(vec3(a_Position) * scale, 1.0);
}
</script>
实现图形缩放,直接传参缩放值

html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图形变换-缩放</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
// 一个属性值,将会从缓冲区中获取数据
attribute vec4 a_Position;
uniform float U_Scale;
void main() {
gl_Position.x = a_Position.x * U_Scale;
gl_Position.y = a_Position.y * U_Scale;
gl_Position.z = a_Position.z * U_Scale;
gl_Position.w = 1.0;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_FragColor;
void main() {
gl_FragColor = u_FragColor;
}
</script>
<script type="module">
import { getPosByMouse, getInnerText, initShaderProgram } from "../utils/index.js"
const canvas = document.querySelector('#canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const gl = canvas.getContext('webgl');
const vertexStr = getInnerText("vertexShader");
const fragmentStr = getInnerText("fragmentShader");
const program = initShaderProgram(gl, vertexStr, fragmentStr )
let a_Position = gl.getAttribLocation(program, 'a_Position');
let u_FragColor = gl.getUniformLocation(program, 'u_FragColor');
let U_Scale = gl.getUniformLocation(program, 'U_Scale');
gl.useProgram(program);
let vertices = [0.0, 0.5, 1, 0.5, 0, 1]
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform4fv(u_FragColor, new Float32Array([1, 0, 1, 1]));
gl.clearColor(0, 0, 0, 1);
// 渲染
function render() {
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
let scale = 20.0;
!(function ani(){
if(scale <= 0.01 ) {
scale = 20.0
}
scale -= 0.01
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform1f(U_Scale, scale);
render();
requestAnimationFrame(ani);
})()
</script>
</body>
</html>
实现图形缩放,利用三角函数中的正弦进行缩放
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图形变换-缩放</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
// 一个属性值,将会从缓冲区中获取数据
attribute vec4 a_Position;
uniform float U_Scale;
void main() {
gl_Position.x = a_Position.x * U_Scale;
gl_Position.y = a_Position.y * U_Scale;
gl_Position.z = a_Position.z * U_Scale;
gl_Position.w = 1.0;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_FragColor;
void main() {
gl_FragColor = u_FragColor;
}
</script>
<script type="module">
import { getPosByMouse, getInnerText, initShaderProgram } from "../utils/index.js"
const canvas = document.querySelector('#canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const gl = canvas.getContext('webgl');
const vertexStr = getInnerText("vertexShader");
const fragmentStr = getInnerText("fragmentShader");
const program = initShaderProgram(gl, vertexStr, fragmentStr )
let a_Position = gl.getAttribLocation(program, 'a_Position');
let u_FragColor = gl.getUniformLocation(program, 'u_FragColor');
let U_Scale = gl.getUniformLocation(program, 'U_Scale');
gl.useProgram(program);
let vertices = [0.0, 0.5, 1, 0.5, 0.5, 0]
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform4fv(u_FragColor, new Float32Array([1, 0, 1, 1]));
gl.clearColor(0, 0, 0, 1);
// 渲染
function render() {
gl.drawArrays(gl.TRIANGLES, 0, 3);
}
let angle = 0;
!(function ani(){
angle += 0.05;
const scale = Math.sin(angle) + 1;
gl.uniform1f(U_Scale, scale);
gl.clear(gl.COLOR_BUFFER_BIT);
render();
requestAnimationFrame(ani);
})()
</script>
</body>
</html>