3D引擎是将现实中的物质抽象为多边形或者各种曲线等表现形式,在计算机中进行相关计算并输出最终图像的算法实现的集合。 3D引擎就像是在计算机内建立一个“真实的世界”
多边形在透视摄像机下的变换过程(注意scene是开启了2d按钮,Game是模型渲染)
Matrix4x4 Move(){平移矩阵}
Matrix4x4 Scale(){缩放矩阵}
Matrix4x4 Rotation(){旋转矩阵}
Matrix4x4 View(){试图矩阵,摄像机}
Matrix4x4 Projection(){投影矩阵}
----------------------------------------------------
Vector4 a = new Vector4(0, 1f, 0, 1); //3角面片的点
Vector4 b = new Vector4(-1f, 0, 0, 1);
Vector4 c = new Vector4(1, 0, 0, 1);
Vector4 d = new Vector4(0, 0, 0.2f, 1);
----------------------------------------------------
Matrix4x4 newMat = Rotation() * Move() * Scale() * View() * Projection();//各种矩阵相乘
Vector4 aNewPoint1 = newMat * a; //点个矩阵相乘
Vector4 bNewPoint1 = newMat * b;
Vector4 cNewPoint1 = newMat * c;
Vector4 dNewPoint1 = newMat * d;
Gizmos.color = Color.red;
Gizmos.DrawLine(aNewPoint1, bNewPoint1);
Gizmos.DrawLine(aNewPoint1, cNewPoint1);
Gizmos.DrawLine(cNewPoint1, bNewPoint1);
Gizmos.DrawLine(aNewPoint1, dNewPoint1);
Gizmos.DrawLine(bNewPoint1, dNewPoint1);
Gizmos.DrawLine(cNewPoint1, dNewPoint1);
----------------------------------------------------
public Matrix4x4 Mul(Matrix4x4 m, Matrix4x4 matrix4x4)
{ //4444矩阵乘法
Matrix4x4 new_Matrix4x4 = new Matrix4x4();
for (int i = 0; i < 4; i++){
for (int j = 0; j < 4; j++){
for (int k = 0; k < 4; k++){
new_Matrix4x4[i, j] = m[i, k] * matrix4x4[k, j];}}}
return new_Matrix4x4;}
----------------------------------------------------
public Vector4 Mul(Matrix4x4 m, Vector4 v)
{//4441矩阵乘法
Vector4 new_Vector4 = new Vector4();
new_Vector4.x = v.x * m[0, 0] + v.y * m[1, 0] + v.z * m[2, 0] + v.w * m[3, 0];
new_Vector4.y = v.y * m[0, 1] + v.y * m[1, 1] + v.z * m[2, 1] + v.w * m[3, 1];
new_Vector4.z = v.z * m[0, 2] + v.y * m[1, 2] + v.z * m[2, 2] + v.w * m[3, 2];
new_Vector4.w = v.w * m[0, 3] + v.y * m[1, 3] + v.z * m[2, 3] + v.w * m[3, 3];
return new_Vector4;}
多边形在模型空间下的变换过程
Matrix4x4 newMat = Rotation() * Move() * Scale();
----------------------------------------------------
Matrix4x4 Move() // 平移矩阵
{
Matrix4x4 Move = new Matrix4x4();
Move[0, 0] = 1;
Move[1, 1] = 1; 1 0 0 0
Move[2, 2] = 1; 0 1 0 0
Move[0, 3] = _Move_X; 0 0 0 0
Move[1, 3] = _Move_Y; x y z 1
Move[2, 3] = 1;
Move[3, 3] = 1;
return Move;
}
----------------------------------------------------
Matrix4x4 Scale()
{
Matrix4x4 Scale = new Matrix4x4();
Scale[0, 0] = _Scale;
Scale[1, 1] = _Scale;
Scale[2, 2] = _Scale;
Scale[3, 3] = 1;
return Scale;
}
----------------------------------------------------
Matrix4x4 Rotation()
{
Matrix4x4 Rotation = new Matrix4x4();
Rotation = new Matrix4x4();
Rotation[0, 0] = (float)Math.Cos(_Rotation * Mathf.Deg2Rad); //角度转弧度 y轴旋转
Rotation[0, 2] = (float)Math.Sin(_Rotation * Mathf.Deg2Rad);
Rotation[1, 1] = 1;
Rotation[2, 0] = (float)-Math.Sin(_Rotation * Mathf.Deg2Rad);
Rotation[2, 2] = (float)Math.Cos(_Rotation * Mathf.Deg2Rad);
Rotation[3, 3] = 1;
return Rotation;
}
多边形在视图空间下的变换过程
Matrix4x4 newMat = Rotation() * Move() * Scale() * View();
----------------------------------------------------
Matrix4x4 View()
{
Matrix4x4 View = new Matrix4x4();
View[0, 0] = 1;
View[1, 1] = 1;
View[2, 2] = 1;
View[3, 2] = _View_D;
View[3, 3] = 1;
View[0, 3] = _View_Width; //视图矩阵大小
View[1, 3] = _View_Height;
View[2, 3] = _View_Z;
return View;
}
多边形在投影下的变换过程
Matrix4x4 newMat = Rotation() * Move() * Scale() * View() * Projection();
----------------------------------------------------
Matrix4x4 Projection()
{
Matrix4x4 Projection = new Matrix4x4();
Projection[0, 0] = _Projection_Width;
Projection[1, 1] = _Projection_Height;
Projection[2, 2] = 1;
Projection[2, 3] = 1f / _View_D;
return Projection;
}
多边形在投影下转变成2d空间(深度值另外存储),opengl在转换过程中规范化为-1到1的空间坐标值
矩阵的逆
当在编辑器里面,设置一个物体的子节点物体,成另一个物体的子节点时候,实际位置没发生改变,这个过程就是从一个模型空间到世界空间在到另一个模型空间的转换,
模型到世界 又可以世界到模型的就是可逆矩阵
着色器不同矩阵下的区别 和 光栅化
Shader "test/1111" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct VertexInput {
float4 vertex : POSITION;
};
struct VertexOutput {
float4 pos : POSITION;
float4 color : TEXCOORD0;
};
VertexOutput vert (VertexInput v) { //顶点着色器
VertexOutput o = (VertexOutput)0;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//if(o.pos.x>0)//投影空间计算(-1到1) 0就是中心
if(v.vertex.x>0)//模型空间计算0就是模型中心点
{
o.color = fixed4(1,1,1,1);
}
else
{
o.color = fixed4(0,0,0,1);
}
return o;
}
fixed4 frag(VertexOutput i) : COLOR { //片段着色器
return i.color; //返回顶点色
}
ENDCG
}
}
FallBack "Diffuse"
}
代码一样,同一顶点,但在2个空间的计算结果,已当前空间的坐标系为计算标准
上面代码是已0位中心点,判定分明,但显示结果是黑白渐变过程,这就是显卡光栅化过程
顶点着色器和片段着色器区别
Shader "test/1111" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct VertexInput {
float4 vertex : POSITION;
};
struct VertexOutput {
float4 pos : POSITION;
float4 color : TEXCOORD0;
};
VertexOutput vert (VertexInput v) { //顶点着色器
VertexOutput o = (VertexOutput)0;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
return o;
}
fixed4 frag(VertexOutput i) : COLOR { //片段着色器
//if(i.pos.x>0)
if(i.pos.x>500)
{
return fixed4(1,1,1,1);
}
else
{
return fixed4(0,0,0,1);
}
}
ENDCG
}
}
FallBack "Diffuse"
}
相同代码从顶点着色器移到片段着色器,发现原来>0的判断不是想象的效果,但改成>500就出现了想要的效果,而且黑白分明2个函数区别在与
顶点:每帧按顶点的数量,每个执行一遍
片段:每帧按像素的数量,计算每个像素值
光照计算(C#计算方法)
Shader "test/1111" {
SubShader {
Pass {
CGPROGRAM
struct VertexInput {
float4 vertex : POSITION;
float4 color : COLOR;};
struct VertexOutput {
float4 pos : POSITION;
float4 color : COLOR;};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.color = v.color;
return o; }
fixed4 frag(VertexOutput i) : COLOR {
return i.color;
}
ENDCG
}}
FallBack "Diffuse"
}
----------------------------------------------------
public class diffuse : MonoBehaviour {
public GameObject light;
Mesh mesh;
Vector3[] normals;
Color[] colors;
void Start(){
mesh = gameObject.GetComponent<MeshFilter>().mesh;
normals = mesh.normals;
Run();}
void Run(){
colors = new Color[mesh.normals.Length];
for(int i=0;normasls.Length)
{
Matrix4x4 max44 = transform.localToWorldMatrix;
Vector3 worldNormal = (max44 * normals[i]).normalized;//规范化01
Vector3 worldLight = light.transform.position.normalized;
float val = Vector3.Dot(worldNormal, worldLight); //获取点积
if (val < 0) val = 0f; else if (val > 1) val = 1;
colors[i] = (Color)(new Vector4(val, val, val, 1));
}
mesh.colors = colors;
}
void Update () { Run(); } }
unity中主要的3个网格渲染器 MeshRenderer SkinnedMeshRenderer ParticleRenderer
MeshRenderer包含元素
第一纬度# 第二纬度# 第三纬度
Mesh# 顶点数据和组成三角面数据 #法线切线和顶点色数据 #uv2或者uv3数据
图片# rgb数据 #a透明通道数据 .
Shader# 如变色,遮罩,高光,流光等 #如漫反射,光照 #多pass运用,如实时阴影,镜面投影
NGUI的渲染和层级管理
NGUI使用的是MeshRenderer网格渲染
Mesh:根据编辑数据生成verts,norms,uvs,cols组成模型面片
贴图:Atlas里面的图片
Shader:使用半透物体的渲染(RenderQueue 3000开始),并且关闭深度写入(ZWrite Off)
创建一个新的DC:Atlas_Achievement_add RenderQueue:3000 Material:Atlas_Achievement_add Shader:Unlit/Transparent Colored Texture:Atlas_Achievement_add
渲染Sprite节点:0 在已经有的DC[Atlas_Achievement_add]中加入mesh数据 verts: 4
渲染Sprite节点:1 在已经有的DC[Atlas_Achievement_add]中加入mesh数据 verts: 8
渲染Sprite节点:4 在已经有的DC[Atlas_Achievement_add]中加入mesh数据 verts: 12
更新mesh: Atlas_Achievement_add verts:12 包含渲染Sprite数量:3
创建一个新的DC:Atlas_ActivitySkinBox01_add RenderQueue:3002 Material:Atlas_ActivitySkinBox01_add Shader:Unlit/Transparent Colored Texture:Atlas_ActivitySkinBox01_add
渲染Sprite节点:5 在已经有的DC[Atlas_ActivitySkinBox01_add]中加入mesh数据 verts: 4
更新mesh: Atlas_ActivitySkinBox01_add verts:4 包含渲染Sprite数量:1
创建一个新的DC:Atlas_Achievement_add RenderQueue:3004 Material:Atlas_Achievement_add Shader:Unlit/Transparent Colored Texture:Atlas_Achievement_add
渲染Sprite节点:6 在已经有的DC[Atlas_Achievement_add]中加入mesh数据 verts: 4
渲染Sprite节点:7 在已经有的DC[Atlas_Achievement_add]中加入mesh数据 verts: 8
更新mesh: Atlas_Achievement_add verts:8 包含渲染Sprite数量:2
创建一个新的DC:Atlas_ActivitySkinBox01_add RenderQueue:3006 Material:Atlas_ActivitySkinBox01_add Shader:Unlit/Transparent Colored Texture:Atlas_ActivitySkinBox01_add
渲染Sprite节点:8 在已经有的DC[Atlas_ActivitySkinBox01_add]中加入mesh数据 verts: 4
更新mesh: Atlas_ActivitySkinBox01_add verts:4 包含渲染Sprite数量:1
**<b>NGUI层级</b>**
1:根据当前UIPanel下的所有Sprite设置的Depth进行从小到大排序(使用自定义渲染队列遵循从后往前画)
2:循环Sprite列表,下一条对比上一条mat,shader,Tex,有一个不一样的就创建新的MeshRenderer
3:创建出来的MeshRenderer数据就是DC的数量
4:每个MeshRenderer的RenderQueue为 3000+UIPanel.depth+MeshRenderer列表的下标值*2(使用自定义渲染队列遵循从后往前画)
5:NGUI和3d模型的层级管理
模型使用材质ZWrite Off挂载脚本ChangeRenderQueue设置属性Sprite,3d模型显示层级完全遵照Sprite的Depth层级显示
模型使用材质ZWrite On 挂载脚本ChangeRenderQueue设置属性Sprite,还需调整模型Z坐标