博客地址:blog.liujunliang.com.cn
本文使用C# Winform开发工具运用3D数学基础实现三维渲染
主要有三个步骤:顶点的变换、矩阵的变换、模拟光照三维渲染
本文源码地址:下载链接
顶点的变换
首先实现在一个窗口绘制一个三角形,让其各个顶点自动旋转
让其自动旋转需要使用到旋转矩阵
矩阵公式:
矩阵与顶点的变换代码如下
// 单个顶点的矩阵转换
public Vertex4 Mul(Vertex4 vertex)
{
Vertex4 vertex4 = new Vertex4();
if (this.mColumn == vertex.Width())
{
vertex4.mVertexX = this[0, 0] * vertex.mVertexX + this[1, 0] * vertex.mVertexY + this[2, 0] * vertex.mVertexZ + this[3, 0] * vertex.mVertexW;
vertex4.mVertexY = this[0, 1] * vertex.mVertexX + this[1, 1] * vertex.mVertexY + this[2, 1] * vertex.mVertexZ + this[3, 1] * vertex.mVertexW;
vertex4.mVertexZ = this[0, 2] * vertex.mVertexX + this[1, 2] * vertex.mVertexY + this[2, 2] * vertex.mVertexZ + this[3, 2] * vertex.mVertexW;
vertex4.mVertexW = this[0, 3] * vertex.mVertexX + this[1, 3] * vertex.mVertexY + this[2, 3] * vertex.mVertexZ + this[3, 3] * vertex.mVertexW;
return vertex4;
}
else
{
Console.WriteLine("顶点转化失败!");
return null;
}
}
使用Winform工具绘制出来
//画出形状(根据点描出线条)
public override void Draw(Graphics graphics)
{
graphics.DrawLines(new Pen(Color.Black, 2f), this.GetAllPointF().ToArray());
}
其中GetAllPointF函数是获取顶点的X、Y坐标作为在屏幕的显示坐标
//获取各个点屏幕点
public List<PointF> GetAllPointF()
{
List<PointF> pointFList = new List<PointF>();
pointFList.Add(GetPointF(this.mCurrentVertexA));
pointFList.Add(GetPointF(this.mCurrentVertexB));
pointFList.Add(GetPointF(this.mCurrentVertexC));
pointFList.Add(pointFList[0]);
return pointFList;
}
最终的效果图如下所示
矩阵的变换
以上效果图显示发现,三角形的显示只是在平面上效果,并没有在3D图像上的透视效果
这时我们将三角形进行空间坐标系->世界坐标系->观察坐标系->投影坐标系中的转变
使用的矩阵是mvp矩阵,也就是说将矩阵转换下
Matrix4X4 m = rotateMatrix.Mul(scaleMatrix);
Matrix4X4 mv = m.Mul(viewMatrix);
Matrix4X4 mvp = mv.Mul(projectionMatrix);
mShape.Transform(mvp);
两个矩阵的转换公式代码如下
// 矩阵的转换
public Matrix4X4 Mul(Matrix4X4 matrix)
{
Matrix4X4 matrix4x4 = new Matrix4X4();
if (this.mColumn == matrix.mRow)
{
for (int x = 0; x < this.mRow; x++)
{
for (int y = 0; y < matrix.mColumn; y++)
{
for (int z = 0; z < this.mColumn; z++)
{
matrix4x4[x, y] += this[x,z] * matrix[z,y];
}
}
}
return matrix4x4;
}
else
{
Console.WriteLine("矩阵转化失败!");
return null;
}
}
透视效果图如下
模拟光照三维渲染
在计算光照渲染需要知道3D数学知识
博主归纳了两个
向量:u=(u1,u2,u3) v=(v1,v2,v3)
叉积公式:u x v = (u2v3-v2u3 ,u3v1-v3u1 ,u1v2-u2v1 )
点积公式:u · v = u1v1+u2v2+u3v33=lul*lvl*COS(U,V)
获取光照角度代码如下
//得到三角形的法线
public override Vertex.Vertex4 GetNormal()
{
//左手法则
Vertex.Vertex4 U = this.mCurrentVertexB - this.mCurrentVertexA;
Vertex.Vertex4 V = this.mCurrentVertexC - this.mCurrentVertexA;
this.mNormal = U.Cross(V);
return this.mNormal;
}
//得到灯光角度
public override float GetLightDot(Vertex.Vertex4 lightingDir)
{
float dot = GetNormal().Normalized.Dot(lightingDir.Normalized);
return Math.Max(0,dot);
}
将三角形填充并且计算光照后的颜色
//画出形状(根据点描出线条)
public override void Draw(Graphics graphics)
{
graphics.DrawLines(new Pen(Color.Black, 2f), this.GetAllPointF().ToArray());
System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddLines(this.GetAllPointF().ToArray());
int dot = (int)(255 * GetLightDot(new Vertex.Vertex4(0, 0, 250, 1)));
Color color = Color.FromArgb(dot,dot,dot);
Brush redBrush = new SolidBrush(color);
graphics.FillPath(redBrush, path);
}
效果显示如下图