为什么要学习图形学?
图形学:
1,知其然亦知其所以然。
比如:纹理寻址。
2,游戏开发中经常需要平衡CPU 和 GPU 性能消耗。
比如:loading .
伴随着请求资源(网络和本地资源)
Loading 做法:
1,cpu 做若干张图交替 (播放若干张图片) 2,gpu 旋转一张图。
3,编写炫酷特效。
4,20K 以上高薪必备技能。
Opengl 渲染流程:
Cpu: FBX -Meshrender
Fbxobj : 模型文件里面包含了 uv 顶点位置,法线切线等渲染所需要的信息。
**MeshRender : 将这些信息传递到GPU 。
skin mesh render 带蒙皮的骨骼。
mesh render : mesh render主要是将顶点等信息传递到gpu .
mesh filter : 表示将哪个模型信息传递给gpu .
skin mesh render :
GPU:
渲染管线:
顶点着色器 - 光栅化 - 片段着色器 – alpha 测试 -模板测试 ---- 深度测试 — Blend — Gbuffer — frontBuffer — frame buffer — 显示器
顶点着色器作用:
1, 计算顶点的颜色。
2,将物体坐标系转换到相机坐标系。
光栅化作用:
将顶点转换成像素。(差值)
100*100
(0,0,0,0)
(1,1,1,1)
此图会变成由白到黑
片段着色器:
1, 已经是像素点。
像素:RGBA 4 通道组成。
RGBA 8888 8bit .
屏幕: 720*1280
横有 720个像素竖排 1280个像素。
Float[720 *1280]
顶点: 4个到了片段着色器 100*100. 10000次
结论:
(并行计算)点着色器会运行 4次片段着色器会运行 100X00.
顶点着色器 和 片段着色器运算次数不是一个量级。
所以能把运算放在顶点着色器就放这里。
片段着色器:
1, 纹理采样。从纹理像素赋给像素(从材质数据种读取像素显示到屏幕上)
2,像素跟灯光计算。
三大测试
Alpha 测试: 挑选合格的alpha 像素显示。
模板测试: 像素还可以携带模板信息。达到条件的模板值。
深度测试: (相机的距离) 符合条件的像素就通过不然就丢弃。
Blend : 将当前要渲染的像素和已经渲染出来的像素混合运算。
缓存区
GBuffer : RGBA 模板值深度值等。
Float[ 72012804 ]
Front Buffer : float[7201280]
framebuffer : float[7201280] (显示器)
front Buffer/frame buffer 交换一帧帧的在动
Shader 介绍 :
1, shader 语言
opengl : SGI公司 跨平台。
GLSL语言 : opengl shader lauguage
dx : 微软开发。非跨平台性能非常好。
HLSL : high level shader lauguage .
CG : 微软和英伟达公司。 跨平台基于 C语言。
shader lab : Unity 自己的语言
unity shader分类:
fiexed shader : shader1.0 主要是开关式
顶点 片段着色器: shader 2.0 功能里面的公式我们可以自己定义
Surface shader: 前两种的封装
4, shader 结构:
着色器组成:
//shader 的名字会显示在 Unity 的 Inspector 中选择 shader 的菜单里面
**Shader 属性定义的通用格式:**
Properties { Property [Property ...] }
name : 变量的名字。以下划线开头。
display name: 供外界 参考说明 。
int : 表示 变量类型 。
= number:表示默认值。
为什么三维的世界要用四维去表示?
_MainTex ("Texture", 2D) = "white" {}:
White:表示默认值。
• For 2D Textures, the default value is either an empty string, or one of the built-in default Textures: “white” (RGBA: 1,1,1,1), “black” (RGBA: 0,0,0,0), “gray” (RGBA: 0.5,0.5,0.5,0.5), “bump” (RGBA: 0.5,0.5,1,0.5) or “red” (RGBA: 1,0,0,0).
什么是材质球?
人的衣服。
什么是 shader ?
决定材质跟灯光的作用。
```csharp
Shader "shader 的名字" {
// 属性 C#定义参数
// Properties { Property [Property ...] }
// 定义一个 int : name ("display name", Int) = number
// display name : 外界的参考说明
// int 类型
// name : 参数
// 类型关键字: 2D Int Float Range() Color Vector Cube 3D
// CubeMap : 有六个面的 纹理 。
// 3D 纹理 : 1, 只能用 script 创建 。
// 2, opengl 3.0 及以上 才支持 。
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_MainTex("Texture",2D)="white"{}
_TestCube("cubeMap",Cube)=""{}
_XX("display name",3D)="defaulttesture"{}
}
// 自动筛选硬件代码 显卡用的哪个subshader
// 可能存在多个 subshader。
// Unity 会在所有 subshader 列表中选择当前环境中可用的第一个 subshader
Subshader {
// subshader 的标签
[Tags] Tags { "RenderType"="Opaque" }
LOD 200
// 给多个 pass 公用的设置
[Common State]
// 可能存在多个 pass, 每个 pass 都会引起一次渲染过程
Pass {
// pass 的标签
[Pass Tags]
// 渲染设置, 如颜色混合
[Render Setup]
// 纹理设置,只有在 fixed function shader 中才可用
[Texture Setup]
}
// 可以有多个 pass
[其他的 Pass]
}
// 可以有多个 subshader
[其他的 Subshader]
// 当所有 subshader 失败的时候, 使用 Fallback 指定的 shader
[Fallback]
// 当有自定义 shader 的设置 UI 时候用
[CustomEditor]
}
Shader1.0 光照计算
顶点着色器 -光栅化 -片段着色器 -- alpha 测试 -模板测试
----深度测试 — Blend - Gbuffer -- frontBuffer - frame buffer -显示器
Shader 1.0 :
顶点着色器:
1, 计算顶点的颜色。
2, 顶点变换。
3, 灯光的作用。
片段着色器:
三大测试:
调节顶点的颜色:
_TestColor (“TestColor”, Color) = (1,0,0,1)
Color (0,1,0,1)
Color[_TestColor]
Shader 1.0 灯光计算公式:
Ambient * (Lighting Window’s Ambient Intensity setting )
- (Light Color * Diffuse + Light Color * Specular)
- Emission
光的分类;
Ambient : 环境光
Diffuse : 漫反射
Specular : 镜面反射
Emission:自发光
Lighting On : 灯光的总开关。
SeparateSpecular On : 高光开关。
Shader "Custom/Shader1.0"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
//_MainTex ("Albedo (RGB)", 2D) = "white" {}
//_Glossiness ("Smoothness", Range(0,1)) = 0.5
//_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader
{
Pass
{
//Color 的两种使用方法
//Color(0,1,0,1)
//Color[_Color]
Material
{
// Diffuse 的两种方式
// Diffuse(0,1,0,1)
//Diffuse[_Color]
//shader 1.0 灯光计算公式
/* Ambient* (Lighting Window’s Ambient Intensity setting)
+ (Light Color * Diffuse + Light Color * Specular)
+ Emission*/
Ambient[_Color] //环境光
Specular[_Color] //高光
// Emission[_Color] //自发光
}
Lighting On
SeparateSpecular On //高光开关
}
}
}
Shader1.0 纹理寻址
Shader1.0 顶点着色器 --光栅化 ----片段着色器
顶点着色器 :
1,计算顶点的颜色
2,计算灯光设置
片段着色器
1,纹理采样。
顶点着色器 4: 片段着色器100*100:
贴纹理:
Q:大小跟我这个显示区域不匹配怎么办?
1,纹理跟显示区域相等。
显示区域100100纹理大小: 100100
2,纹理大于显示区域:
显示区域 100100 纹理大小: 1024512
1, 采用等比例映射。
UV: 笛卡尔坐标系 寻址方式
2, Point : 就近采样。
Bilinear : 就近周围四个像素的平均:
(1,1,1,1)
(上+ 中 +下+左+右)/5
Trilinear : 就近周围 8个像素的平均。
3, 纹理像素小于显示区域:
显示区域 100100 纹理大小:5050
锯齿:马赛克 模糊 (使用Bilinear、Trilinear)
Shader1.0 纹理寻址设置
格式:
SetTexture [TextureName] {Texture Block}
TextureName:表示纹理变量。
Previous : 表示前面一个SetTexture出来以后的像素。
Primary : 表示顶点计算出来的颜色。
Texture : 等于SetTexture当前的纹理变量
Constant :表示一个固定的颜色。(1,1,1,1)
combine Texture
combine Previous * Texture 越乘 越暗
表示 两个 像素的 乘法: (1,0,0,1) ( 0.5,0,0,1)
combine Previous + Texture 越加 越亮
Lerp公式:
让 src1 和 src3 进行混合 .
混合的方式取决于src2的 alpha 值:
(1-t)A + tB --差值公式
combine src1 lerp (src2) src3:
设置constantColor 两种方式:
1,constantColor(0,1,0,1)
SetTexture[_MainTex]
{
// constantColor(0,1,0,1)
combine Texture *Constant
}
2, Property 设置:
_ConsColor(“Color”,Color)=(1,0,0,1)
SetTexture[_MainTex]
{
constantColor[_ConsColor]
combine Texture *Constant
}
Shader 1.0 适应所有的显卡。
Shader "Custom/Shader1.0-SetTrexture"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Main2Tex("Albedo2 (RGB)", 2D) = "white" {}
_ConsColor("Color",Color) = (1,0,0,1)
}
//**格式:**
// SetTexture[TextureName]{ Texture Block }
// TextureName:表示纹理变量。
// Previous : 表示前面一个SetTexture出来以后的像素。
// Primary : 表示顶点计算出来的颜色。
// Texture : 等于SetTexture当前的纹理变量
// Constant : 表示一个固定的颜色。(1,1,1,1)
SubShader
{
Pass
{
//Color[_Color]
SetTexture[_MainTex]
{
combine Texture
//combine Primary* Texture
//combine Primary+Texture
}
SetTexture[_Main2Tex]
{
//Previous
//combine Texture
//combine Primary* Texture
//combine Primary + Texture
//combine Previous+Texture
//combine Texture lerp(Texture) Previous
//combine Previous lerp(Texture) Texture
// constantColor(0,1,0,1)
constantColor[_ConsColor]
combine Texture* Constant
}
}
}
//FallBack "Diffuse"
}
Shader 2.0
Shader 1.0 和 2.0区别:
代码路径: X:\xxx\Unity\Editor\Data\CGIncludes\UnityCG.cginc
不同点: 2.0 可以实现编程。
相同点: 渲染管线一样。
#pragma vertex vert 定义一个顶点着色器的 入口函数 。
#pragma fragment frag 定义一个片段着色器的 入口函数
Appdata从 meshrender 里面来的。
v2f vert (appdata v)
v2f:顶点着色器的输出值/片段着色器的输入值。
语义 :
POSITION: 获取模型顶点的信息。
NORMAL : 获取法线信息。
TEXCOORD (n): 高精度的 从顶点传递信息 到 片段着色器
float2, float3 or float4.
COLOR : 表示低精度从顶点传递信息 到 片段着色器
float4
TANGENT : 获取切线信息。
SV_POSITION: 表示经过 mvp矩阵 已经转化到 屏幕坐标的位置。
SV_Target: 输出到哪个 render target .
//顶点着色器从fbx 获取信息:
struct appdata_base {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct appdata_tan {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct appdata_full {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
fixed4 color : COLOR;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
Shader 2.0 顶点着色器:
1, 计算顶点的位置变换。
2,计算顶点的颜色。
Unity3d 里面矩阵是左乘:
1, 将物体坐标系变换到世界坐标系
P(世界) = M(物体到世界的)*P(物体)
规律: 3D 变换首先将物体坐标系变换到世界。
2, 将世界坐标变换到相机坐标系
P(相机)= M(世界到相机) *p(世界)
M : 物体坐标系变换到世界坐标系
V :世界坐标变换到相机坐标系
P: 将 3D 坐标系转换成2维屏幕坐标系。
Vector3 Pos = transform.parent.localToWorldMatrix.MultiplyPoint(transform.localPosition);
//左乘矩阵,设置物体坐标