我的SharpDX学习笔记

从开始折腾到觉得自己可以小结一下了,一共三周。

开始是找库,OPENGL还是DirectX其实并不重要,甚至还考虑过Unity,不过最终发现像我这种非主流的需求,还是老老实实的从头学(搞)比较实际。

最终选了DirectX还是因为微软的文档。

SharpDX封装的很好,学习的过程中找到的有效资料基本都是C++的,用SharpDX实现既能对应上,又让我觉得方便了很多(和C++例子比)。

代码我是在一个项目上直接改的,我的目的不是教别人,所以堆在一起,未来看的时候能回忆一下当初的理解过程。

如果其他人看到了,抱歉,这文章是我自己纪录思路的,可能不太适合当作参考。

总的来说,DirectX入门需要一些数学知识储备,向量、矩阵的定义和运算,坐标变换的原理,齐次坐标变换,仿射矩阵,向量单位化(L2Norm),有一些立体的抽象思维能力,坐标系,光源,摄像机,而且绕不开的还有C++的知识,至少要能猜懂。

学习的顺序:

一、找本靠谱的参考书,例如Introduction to 3D Game Programming with Direct3D 11.0

二、测试开发环境,创建一个Device,我在网上找到几个靠谱的Tutorial代码却全在我Win7+VS2015 Community的环境下编译不能。所以测试环境很重要啊。

三、理解PipeLine,细节理解得越清楚越好,否则后面绝对会乱,尤其是C++。

四、针对PipeLine的每一部分,去用代码熟悉一下,总的来说,Directx每一步都有如下套路:描述一下这部分的属性,分配内存(当然分配前要定义结构和空间大小),绑定。C++原始API都是把创建的结果地址当作参数传入,返回结果是出错代码,对习惯了等号右赋左值的C#程序员很不习惯,所以SharpDX封装的好!而且还尽力省略了一些很不常用的参数。

五、别着急,这种底层的API由于灵活,所以每个人的玩法都不一样,没理解的情况下要把两个例子混一块玩会死得很惨,

SharpDX的Camera实现

<Introduction to 3D Game Programming with Direct3D 11.0>第15章Camera类的C#(SharpDX)实现。

using System;
using SharpDX;

namespace SharpDX_Study_001
{
    class Camera
    {
        public Camera()
        {
            mPosition = Vector3.Zero;
            mRight = Vector3.UnitX;
            mUp = Vector3.UnitY;
            mLook = Vector3.UnitZ;
            SetLens(0.2f * SharpDX.MathUtil.Pi, 1.0f, 1.0f, 1000.0f);
        }
        public Vector4 PositionXM
        {
            get
            {
                return new Vector4(mPosition, 0);
            }
        }
        public Vector3 Position
        {
            get
            {
                return mPosition;
            }
            set
            {
                mPosition = value;
            }
        }
        public Vector4 RightXM
        {
            get
            {
                return new Vector4(mRight, 0);
            }
        }
        public Vector4 UpXM
        {
            get
            {
                return new Vector4(mUp, 0);
            }
        }
        public Vector4 LookXM
        {
            get
            {
                return new Vector4(mLook, 0);
            }
        }
        public Vector3 Right
        {
            get
            {
                return mRight;
            }
        }
        public Vector3 Look
        {
            get
            {
                return mLook;
            }
        }
        public Vector3 Up
        {
            get
            {
                return mUp;
            }
        }
        public float NearZ
        {
            get
            {
                return mNearZ;
            }
        }
        public float FarZ
        {
            get
            {
                return mFarZ;
            }
        }
        public float Aspect
        {
            get
            {
                return mAspect;
            }
        }
        public float FovY
        {
            get
            {
                return mFovY;
            }
        }
        public float FovX
        {
            get
            {
                float halfWidth = 0.5f * NearWindowWidth;
                return 2.0f * Convert.ToSingle(Math.Atan(halfWidth / mNearZ));
            }
        }
        public float NearWindowWidth
        {
            get
            {
                return mAspect * mNearWindowHeight;
            }
        }
        public float NearWindowHeight
        {
            get
            {
                return mNearWindowHeight;
            }
        }
        public float FarWindowWidth
        {
            get
            {
                return mAspect * mFarWindowHeight;
            }
        }
        public float FarWindowHeight
        {
            get
            {
                return mFarWindowHeight;
            }
        }

        /// <summary>
        /// Set frustum.
        /// </summary>
        /// <param name="fovY"></param>
        /// <param name="aspect"></param>
        /// <param name="zn"></param>
        /// <param name="zf"></param>
        public void SetLens(float fovY, float aspect, float zn, float zf)
        {
            // cache properties
            mFovY = fovY;
            mAspect = aspect;
            mNearZ = zn;
            mFarZ = zf;

            mNearWindowHeight = 2.0f * mNearZ * Convert.ToSingle(Math.Tan(0.5f * mFovY));
            mFarWindowHeight = 2.0f * mFarZ * Convert.ToSingle(Math.Tan(0.5f * mFovY));

            mProj = Matrix.PerspectiveFovLH(mFovY, mAspect, mNearZ, mFarZ);
        }

        //       // Define camera space via LookAt parameters.
        public void LookAt(Vector4 pos, Vector4 target, Vector4 worldUp)
        {
            Vector3 L = new Vector3(pos.X, pos.Y, pos.Z);
            Vector3 T = new Vector3(target.X, target.Y, target.Z);
            Vector3 U = new Vector3(worldUp.X, worldUp.Y, worldUp.Z);
            LookAt(L, T, U);
        }
        public void LookAt(Vector3 pos, Vector3 target, Vector3 up)
        {
            mPosition = pos;
            mLook = Vector3.Normalize(target - pos);
            mRight = Vector3.Normalize(Vector3.Cross(up, mLook));
            mUp = Vector3.Cross(mLook, mRight);
        }
        public Matrix View
        {
            get
            {
                return mView;
            }
        }
        public Matrix Proj
        {
            get
            {
                return mProj;
            }
        }
        public Matrix ViewProj
        {
            get
            {
                return View * Proj;
            }
        }
        // Strafe/Walk the camera a distance d.
        public void Strafe(float d)
        {
            // mPosition += d*mRight
            Vector4 s = new Vector4(d);

            var nPos = (s * RightXM + PositionXM);
            mPosition = new Vector3(nPos.X, nPos.Y, nPos.Z);
        }
        public void Walk(float d)
        {
            // mPosition += d*mLook
            Vector4 s = new Vector4(d);
            var nPos = (s * LookXM + PositionXM);
            mPosition = new Vector3(nPos.X, nPos.Y, nPos.Z);
        }

        // Rotate the camera.
        public void Pitch(float angle)
        {
            // Rotate up and look vector about the right vector.

            Matrix R = Matrix.RotationAxis(mRight, angle);
            mUp = Vector3.TransformNormal(mUp, R);
            mLook = Vector3.TransformNormal(mLook, R);
        }
        public void RotateY(float angle)
        {
            // Rotate the basis vectors about the world y-axis.

            Matrix R = Matrix.RotationY(angle);
            mRight = Vector3.TransformNormal(mRight, R);
            mUp = Vector3.TransformNormal(mUp, R);
            mLook = Vector3.TransformNormal(mLook, R);
        }

        // After modifying camera position/orientation, call to rebuild the view matrix.
        public void UpdateViewMatrix()
        {
            var R = mRight;
            var U = mUp;
            var L = mLook;
            var P = mPosition;

            // Keep camera's axes orthogonal to each other and of unit length.
            L = Vector3.Normalize(L);
            U = Vector3.Normalize(Vector3.Cross(mLook, mRight));

            // U, L already ortho-normal, so no need to normalize cross product.
            R = Vector3.Cross(U, L);

            // Fill in the view matrix entries.
            float x = -Vector3.Dot(P, R);
            float y = -Vector3.Dot(P, U);
            float z = -Vector3.Dot(P, L);

            mRight = R;
            mUp = U;
            mLook = L;

            mView.Column1 = new Vector4(mRight, x);
            mView.Column2 = new Vector4(mUp, y);
            mView.Column3 = new Vector4(mLook, z);
            mView.Column4 = Vector4.UnitW;
        }


        private Vector3 mPosition;

        private Vector3 mRight;

        private Vector3 mUp;

        private Vector3 mLook;


        // Cache frustum properties.
        float mNearZ;
        float mFarZ;
        float mAspect;
        float mFovY;
        float mNearWindowHeight;
        float mFarWindowHeight;

        Matrix mView;
        Matrix mProj;

    }
}