游戏内核基础 二
内容纲要

矩阵
数学上,一个 m × n的矩阵是一个由 m行(row) n列(column)元素排列成的矩形阵列。矩阵里的元素可以是数字、符号或数学式。
大小相同(行数列数都相同)的矩阵之间可以相互加减,具体是对每个位置上的元素做加减法。矩阵的乘法则较为复杂。两个矩阵可以相乘,当且仅当第一个矩阵的列数等于第二个矩阵的行数。矩阵的乘法满足结合律和分配律,但不满足交换律。

以上来自维基百科对矩阵的解释(图例仅供欣赏),比较简单。矩阵也是游戏中最常用的功能,接下来封装一个4 x 4的矩阵:
export default class Matrix4x4{
private _data: number[] = [];
public constructor(){
this._data = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];
}
public get data(): number[]{
return this._data;
}
public static identity(): Matrix4x4{
return new Matrix4x4();
}
public static orthographic(left: number, right: number, bottom: number, top:number, nearClip: number, farClip: number){
let m = new Matrix4x4();
let lr: number = 1.0 / (left - right);
let bt: number = 1.0 / (bottom - top);
let nf: number = 1.0 / (nearClip - farClip);
m._data[0] = -2.0 * lr;
m._data[5] = -2.0 * bt;
m._data[10] = -2.0 * nf;
m._data[12] = (left + right) * lr;
m._data[13] = (top + bottom) * bt;
m._data[14] = (farClip + nearClip) * nf;
return m;
}
public static translation(position: Vector3): Matrix4x4{
let m = new Matrix4x4();
m._data[12] = position.x;
m._data[13] = position.y;
m._data[14] = position.z;
return m;
}
}

位置
矩阵需要位置,然后封装一个Vector3,x,y,z:
export default class Vector3{
private _x!: number;
private _y!: number;
private _z!: number;
public constructor(x: number = 0, y: number = 0, z: number = 0){
this._x = x;
this._y = y;
this._z = z;
}
public get x(): number{
return this._x;
}
public set x(value: number){
this._x = value;
}
public get y(): number{
return this._y;
}
public set y(value: number){
this._y = value;
}
public get z(): number{
return this._z;
}
public set z(value: number){
this._z = value;
}
public toArray(): number[]{
return [this._x, this._y, this._z];
}
public toFloat32Array(): Float32Array{
return new Float32Array(this.toArray());
}
}
使用getter和setter来获取x,y,z的位置。
测试
修改Sprite的宽高:
public position: Vector3 = new Vector3();
public constructor(name?: string, width: number = 100, height: number = 100){
//...
}

最后测试可用性:
//...
export default class Core{
//...
public start(): void {
//...
this._projection = Matrix4x4.orthographic(0, this._canvas.width, 0, this._canvas.height, -1.0, 100.0);
this._sprite = new Sprite("testName");
this._sprite.load();
this._sprite.position.x = 200;
//...
}
public resize():void {
if(this._canvas){
this._canvas.width = window.innerWidth;
this._canvas.height = window.innerHeight;
gl.viewport(-1, 1, -1, 1);//修改位置
}
}
public loadShaders(): void{
let vertexShaderSource = `
attribute vec3 a_position;
uniform mat4 u_projection;
uniform mat4 u_model;
void main(){
gl_Position = u_projection * u_model * vec4(a_position, 1.0);
}
`;
//...
}
private loop():void {
//...
let projectionPosition = this._shader.getUniformLocation("u_projection");
gl.uniformMatrix4fv(projectionPosition, false, new Float32Array(this._projection.data));
let modelLocation = this._shader.getUniformLocation("u_model");
gl.uniformMatrix4fv(modelLocation, false, new Float32Array(Matrix4x4.identity().data));
//...
}
}
就能看到下面的场景:

code enjoy! 🧐🧐🧐
作者:indeex
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。