本文使用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;
}
}
//画出形状(根据点描出线条)
public override void Draw(Graphics graphics)
{
graphics.DrawLines(new Pen(Color.Black, 2f), this.GetAllPointF().ToArray());
}
//获取各个点屏幕点
public List GetAllPointF()
{
List pointFList = new List();
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数学知识
博主归纳了两个
//得到三角形的法线
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);
}