Direct 3D绘制流水线(渲染管线)

来源:互联网 发布:朋友圈小视频软件 编辑:程序博客网 时间:2024/04/30 17:30

一个3D模型要在显示器屏幕显示,必须顺序经过【世界变换】、【观察变换】和【投影变换】,顺序完成三个变换并在显示器显示的过程被称作绘制流水线。


1、世界变换

搭建3D场景时,首先要使用一个坐标系统来定位所有的3D模型的摆放位置,称为世界坐标系统。

每次在世界空间(3D场景)中放入一个3D模型,都必须根据该模型在世界空间的位置为其指定世界变换矩阵。

可以用以下函数得到世界变换矩阵,将这些变换矩阵相乘可以得到复杂的变换关系,使3D模型完成复杂的运动:

public static Matrix RotationYawPitchRoll(float yaw, float pitch, float roll);public static Matrix Translation(float x, float y, float z);public static Matrix RotationY(float yaw);public static Matrix RotationX(float pitch);public static Matrix RotationZ(float roll);public static Matrix Scaling(float x, float y, float z);public static Matrix Scaling(Vector3 vertex);

2、观察变换

一个观察者在世界空间中进行观察,所看到的部分场景就是要投影到显示器屏幕上的场景。

观察者在世界空间的不同位置所看到的是世界空间不同部分的场景。

摄像坐标系统:

首先,观察者必须在这个坐标系同原点;

其次,z轴坐标表示观察者到被观察模型的距离;

最后,要求投影面(即显示器屏幕)平行坐标系统的xy平面。

观察变换就是把观察者在场景中所看到的3D模型顶点的世界坐标系统坐标变换为摄像坐标系统坐标,为投影做好准备。

生成变换矩阵的函数:

public static Matrix LookAtLH(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector);

参数cameraPosition为观察者在世界空间中的位置

参数cameraTarget为观察目标在世界空间中的位置

参数cameraUpVector为摄像坐标系统的y轴正方向

3、投影变换

将摄像空间中的3D模型转换为在显示器屏幕上显示的具有立体感的平面图形。

有两种类型的投影:透视投影,正交投影。(其中,正交投影忽略距离——z值的影响)

生成左手系统透视投影矩阵的函数:

public static Matrix PerspectiveFovLH(float fieldOfViewY, float aspectRatio, float znearPlane, float zfarPlane);

参数fieldOfViewY是y轴方向上的视场角(FoV),以弧度为单位

参数aspectRatio是纵横比

参数znearPlane是近裁剪面到坐标原点(摄像机位置)的距离

参数zfarPlane是远裁剪面到坐标原点(摄像机位置)的距离

具体可以想象一个四棱台,小的面是近裁剪面,大的面是远裁剪面,这两个平行的面是平行于xy平面的,棱台的高即zfarPlane减去znearPlane的差值。

4、简单的显示

CustomVertex.TransformedColored结构只能定义已根据透视原理进行了变换的顶点,模型是静止的,无法控制。

要定义未经变换的顶点,可使用CustomVertex.PositionColored结构。


【显示三角形】

增加变量:

private VertexBuffer vertexBuffer = null;

修改OnCreateDevice方法:

        public void OnCreateDevice(object sender, EventArgs e)        {            /*             * 其他Device初始化工作;             */            Device dev = (Device) sender;            this.vertexBuffer = new VertexBuffer(                typeof(CustomVertex.PositionColored),                3,                dev,                0,                CustomVertex.PositionColored.Format,                Pool.Default);            this.vertexBuffer.Created += this.OnCreateVertexBuffer;            this.OnCreateVertexBuffer(this.vertexBuffer, null);        }

增加OnCreateVertexBuffer方法:

        public void OnCreateVertexBuffer(object sender, EventArgs e)        {            CustomVertex.PositionColored[] verts =                (CustomVertex.PositionColored[])((VertexBuffer)sender).Lock(0, 0);            verts[0].Position = new Vector3(-1.0f, -1.0f, 0.0f);            verts[0].Color = Color.Red.ToArgb();            verts[1].Position = new Vector3(1.0f, -1.0f, 0.0f);            verts[1].Color = Color.Green.ToArgb();            verts[2].Position = new Vector3(0.0f, 1.0f, 0.0f);            verts[2].Color = Color.Blue.ToArgb();            this.vertexBuffer.Unlock();        }

增加绘制流水线的方法:

        private void SetupMatrices()        {            this.device.Transform.World = Matrix.RotationY(0);            this.device.Transform.View = Matrix.LookAtLH(                new Vector3(0.0f, 3.0f, -5.0f),                new Vector3(0.0f, 0.0f, 0.0f),                new Vector3(0.0f, 1.0f, 0.0f));            this.device.Transform.Projection = Matrix.PerspectiveFovLH(                (float) Math.PI / 4, 1.0f, 1.0f, 100.0f);        }

修改OnResetDevice方法:

        public void OnResetDevice(object sender, EventArgs e)        {            /*             * Device参数变化时调用;             */            Device dev = (Device) sender;            dev.RenderState.CullMode = Cull.None;            dev.RenderState.Lighting = false;            this.SetupMatrices();        }

修改渲染方法:

        public void Render()        {            if (this.device == null)                return;            if (this.pause) //当窗口最小化或者不是可视化时,停止渲染;                return;            this.device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.WhiteSmoke, 1.0f, 0);            this.device.BeginScene();            /*             * 渲染代码必须放在这里;             */            this.device.SetStreamSource(0, this.vertexBuffer, 0);            this.device.VertexFormat = CustomVertex.PositionColored.Format;            this.device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);            this.device.EndScene();            this.device.Present();        }

效果:



0 0
原创粉丝点击