游戏开发的数学基础

坐标系

2D:

1272179-20190508081524287-925321873.png

数学:笛卡尔坐标系
计算机(屏幕坐标系):以屏幕左上角(标准坐标系)或者屏幕左下角(Cocos2d)为原点

3D

1272179-20190508081907709-739234954.jpg
左手系 unity
右手系

1272179-20190508082357320-1962818517.jpg
Y UP 3dmax
1272179-20190508082615641-2056910860.jpg
Z UP maya

向量

具有大小和方向,一般常用于表示势能、位移和速度。有时我们也用向量来表示一个单个方向,比如玩家在3D游戏中观察的方向、多边形面对的方向、光线的传播方向以及从一个物体表面折回的反射光方向。

A(x1,y1,z1) B(x2,y2,z2)
AB=(x2-x1,y2-y1,z2-z1)

向量的数乘
n*(x,y,z) = (nx,ny,nz)

Unity下在cube下挂载下列程序,模拟x,y,z向移动

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class axis : MonoBehaviour {

    public float speed = 0f;
    public Vector3 dir = new Vector3(0, 0, 0);

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        Vector3 pre = this.gameObject.transform.position;
        Vector3 now = dir * speed + pre;

        this.gameObject.transform.position = now;
    }
}

自定义加减法和normalize,与Unity原身进行比较
新建Vector3d.cs,添加到component

using System.Collections;
using System;
using System.Collections.Generic;

public class Vector3d  {
    public float x, y, z;

    public Vector3d(float x=0f,float y=0f,float z = 0f)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    } 

    public Vector3d(Vector3d vec)
    {
        this.x = vec.x;
        this.y = vec.y;
        this.z = vec.z;
    }

    public Vector3d add(Vector3d vec)
    {
        Vector3d ret = new Vector3d(x, y, z);
        ret.x += vec.x;
        ret.y += vec.y;
        ret.z += vec.z;
        return ret;
    }

    public Vector3d sub(Vector3d vec)
    {
        Vector3d ret = new Vector3d(x, y, z);
        ret.x -= vec.x;
        ret.y -= vec.y;
        ret.z -= vec.z;
        return ret;
    }

    public void normalize()
    {
        float length = (float)Math.Sqrt(x * x + y * y + z * z);
        x /= length;
        y /= length;
        z /= length;
    }

    public override string ToString()
    {
        return string.Format("("+x+","+y+","+z+")");
    }

    public static Vector3d operator +(Vector3d lv,Vector3d rv)
    {
        return lv.add(rv);
    }

    public static Vector3d operator -(Vector3d lv,Vector3d rv)
    {
        return lv.sub(rv);
    }
}

比较程序如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class axis : MonoBehaviour {

    public bool isEqual(Vector3d ov,Vector3 uv)
    {
        if (ov.x == uv.x && ov.y == uv.y && ov.z == uv.z)
        {
            return true;
        }
        return false;
    }

    void Start () {
        Vector3d ov1 = new Vector3d(1.1f, 1.2f, 1.3f) + new Vector3d(1, 2, 3);
        Vector3 uv1 = new Vector3(1.1f, 1.2f,1.3f) + new Vector3(1, 2, 3);
        if (isEqual(ov1, uv1))
        {
            Debug.Log("add equal ...");
        }
        Vector3d ov2 = new Vector3d(1.1f, 1.2f, 1.3f) - new Vector3d(1, 2, 3);
        Vector3 uv2 = new Vector3(1.1f, 1.2f, 1.3f) - new Vector3(1, 2, 3);
        if (isEqual(ov2, uv2))
        {
            Debug.Log("sub equal ...");
        }
        ov2.normalize();
        uv2.Normalize();
        if (isEqual(ov2, uv2))
        {
            Debug.Log("nrm equal ...");
        }

    }
}
叉积(cross product,满足左手法则,叉积不符合交换律,计算平面法线).定义:通过对u和v两个3d向量计算叉积,结果第三个向量w同时垂直于u和v
u = (x1,y1,z1),v = (x2,y2,z2)
u x v = (y1*z2-z1*y2,z1*x2-x1*z2,x1*y2-y1*x2)

代码如下:

public Vector3d cross(Vector3d vec)
{
    Vector3d ret = new Vector3d();
    ret.x = y * vec.z - z * vec.y;
    ret.y = z * vec.x - x * vec.z;
    ret.z = x * vec.y - y * vec.x;
    return ret;
}

比较结果:

Vector3d ov3 = new Vector3d(1, 2, 3).cross(new Vector3d(-5, 7, 10));
Vector3 uv3 = Vector3.Cross(new Vector3(1, 2, 3), new Vector3(-5, 7, 10));
if (isEqual(ov3, uv3))
{
    Debug.Log("cross equal ...");
}
点积(dot product).定义:标量
u = (x1,y1,z1),v = (x2,y2,z2)
u · v = x1*x2+y1*y2+z1*z2
余弦定理:
u · v = |u||v|cos(a)

a为u与v的夹角
u · v = 0,u与v相互垂直
u · v > 0,u与v夹角小于90
u · v < 0,u与v夹角大于90

模拟光照颜色

假如:u和v都是一个单位向量,
u · v = cos(a) => -1<=cos(a)<=1
用一个向量表示光照颜色。最后的平面的光照颜色=光照颜色*cos(a)
1272179-20190508121904070-1906306433.png

在Unity中新建一个小球,然后添加meterial,新建一个Shader,代码如下,模拟光照效果:

Shader "Custom/Color" {
    Properties {
        _Color ("Light Color", Color) = (1,1,1,1)   // 白色
        _Dir ("Light Dir", Vector) = (0,0,1,0)
        _Intensity("Intensity",float) = 1.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 100
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct v2f {
                float4 vertex: POSITION;
                float3 normal: NORMAL;
            };

            fixed4 _Color;
            fixed4 _Dir;
            float _Intensity;

            v2f vert(appdata_base v) {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.normal = v.normal;
                return o;
            }

            // 光照算法
            fixed4 frag(v2f i) : COLOR{
                fixed3 dir = fixed3(-_Dir.x, -_Dir.y, -_Dir.z);
                dir = normalize(dir);
                fixed3 nrm = normalize(i.normal);
                float bis = dot(dir, nrm);
                if (bis <= 0) {
                    bis = 0;
                }
                fixed4 col = _Color * bis * _Intensity; //光照颜色
                return col;
            }

            ENDCG
        }
    }
}

光照算法核心代码:

// 光照算法
fixed4 frag(v2f i) : COLOR{
    fixed3 dir = fixed3(-_Dir.x, -_Dir.y, -_Dir.z);
    dir = normalize(dir);
    fixed3 nrm = normalize(i.normal);
    float bis = dot(dir, nrm);
    if (bis <= 0) {
        bis = 0;
    }
    fixed4 col = _Color * bis * _Intensity; //光照颜色
    return col;
}

效果如下:
1272179-20190508122448592-1655080771.png

矩阵

定义:一个m x n的矩阵M是一个m行n列的矩形实数数组。行和列指定了矩阵的维数。矩阵中数值称为元素。

我们使用行和列的双下标Mij来标识一个矩阵。i指定了元素所在行,j指定了元素所在的列。
矩阵相等:当且仅当两个矩阵的对应元素相等时,这两个矩阵相等;这两个矩阵必须具有相同的行数和列数,才能进行比较。

矩阵的加、减法
矩阵的数乘

矩阵的乘法:满足分配律和结合律

A(B+C)=AB+AC
(AB)C=A(BC)

a * b = (b的转置矩阵 * a的转置矩阵)的转置矩阵

代码检验:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class axis : MonoBehaviour {

    // Use this for initialization
    void Start () {
        Matrix4x4 a = new Matrix4x4();
        for(int i = 0; i < 16; i++)
        {
            a[i] = Random.Range(1, 100.0f);
        }
        Matrix4x4 b = new Matrix4x4();
        for (int i = 0; i < 16; i++)
        {
            b[i] = Random.Range(1, 100.0f);
        }
        Debug.Log(a * b);

        // a * b = (b的转置矩阵 * a的转置矩阵)的转置矩阵
        Matrix4x4 c = a.transpose;//转置矩阵
        Matrix4x4 d = b.transpose;
        Debug.Log((d * c).transpose);
    }
    
    // Update is called once per frame
    void Update () {
       
    }
}

矩阵变换

位移

Debug.Log(this.transform.localToWorldMatrix);

(x,y,z,0)用于描述向量
(x,y,z,1)用于描述点
原始单位大小,位于原点:
1.00000 0.00000 0.00000 0.00000
0.00000 1.00000 0.00000 0.00000
0.00000 0.00000 1.00000 0.00000
0.00000 0.00000 0.00000 1.00000
1272179-20190509084044550-1050433552.png

在x轴-1单位,y轴2单位,z轴6单位:
1.00000 0.00000 0.00000 -1.00000
0.00000 1.00000 0.00000 2.00000
0.00000 0.00000 1.00000 6.00000
0.00000 0.00000 0.00000 1.00000
1272179-20190509084236535-1686238749.png

Debug.Log(this.transform.localToWorldMatrix.transpose);    // 转置后对应坐标原点

1.00000 0.00000 0.00000 0.00000
0.00000 1.00000 0.00000 0.00000
0.00000 0.00000 1.00000 0.00000
-1.00000 2.00000 6.00000 1.00000

矩阵缩放(Unity3d使用的时OpenGL,所以进行了转置操作)

假设我们通过一个最小点(-4,-4,0)和一个最大点(4,4,0)定义一个正方形,我们希望将正方形沿着x轴缩小0.5倍,y轴放大2.0倍,z抽不变。那么对应的缩放矩阵为:
0.5 0 0 0
0 2 0 0
0 0 1 0
0 0 0 1

1272179-20190509090105702-1900656286.png
显示结果:
0.50000 0.00000 0.00000 0.00000
0.00000 2.00000 0.00000 0.00000
0.00000 0.00000 1.00000 0.00000
-1.00000 2.00000 6.00000 1.00000

旋转

x(1,0,0)旋转角度a,对应矩阵

1 0 0 0
0 cos(a) sin(a) 0
0 -sin(a) cos(a) 0
0 0 0 1

在x轴旋转30度:
1272179-20190509090951425-1576185807.png

1.00000 0.00000 0.00000 0.00000
0.00000 0.86603 0.50000 0.00000
0.00000 -0.50000 0.86603 0.00000
0.00000 0.00000 0.00000 1.00000

射线与平面相交

现在给定射线 p(t)= p0 + t*u
平面:n·(p-p1)=0
那么射线与平面的关系为:
t=(n·p1 - n·p0)/n·u

若t>=0,则射线与平面相交,且交点为p0+t*u
若t<0,则不相交

转载于:https://www.cnblogs.com/carious/p/10676437.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值