游戏内核基础 二

内容纲要

游戏内核基础

矩阵

数学上,一个 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

链接:https://indeex.cc

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


发表评论

您的电子邮箱地址不会被公开。