纹理映射
不知道为什么照着书本敲的代码效果跟复制回来的代码相比总是暗了很多,找不同也找了好久没找到,直接在源码上做注释吧。。
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Unity Shaders Book/Chapter 7/Single Texture" {
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Tex", 2D) = "white" {}
_Specular ("Specular", Color) = (1, 1, 1, 1)
_Gloss ("Gloss", Range(8.0, 256)) = 20
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex : POSITION;
//顶点
float3 normal : NORMAL;
//物体坐标系下的法线
float4 texcoord : TEXCOORD0;
//纹理坐标
};
struct v2f {
float4 pos : SV_POSITION;
//顶点坐标输出
float3 worldNormal : TEXCOORD0;
//世界坐标系下的法线
float3 worldPos : TEXCOORD1;
//世界坐标系下的顶点
float2 uv : TEXCOORD2;
//uv坐标
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
//老规矩,顶点着色器中对顶点POSITION进行MVP变换
//在v2f结构体中作为SV_POSITION输出
o.worldNormal = UnityObjectToWorldNormal(v.normal);
//物体坐标系下的法线转换成世界坐标系下的向量
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
//float3 worldPos = mul(_Object2World, v.vertex).xyz;
//这是把顶点从模型空间(物体的本地坐标空间)转化到世界空间中,并取xyz分量
//其中,_Object2World是转化矩阵。
//UnityObjectToClipPos(v.vertex);
//这个是把顶点从模型空间直接转化到裁剪空间,也就是进行了M - V - P三次转化
//这个函数是unity重新封装过一次
//其实它最初是mul(UNITY_MATRIX_MVP, v.vertex);
//其中,UNITY_MATRIX_MVP是转化矩阵。
//既然可以直接转化为什么还要得到世界空间中的顶点位置?
//这是因为很多时候我们需要在片元着色器中进行一些特殊的运算
//这些运算需要世界空间中的顶点位置,例如,光照模拟,凹凸映射等。
o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
// Or just call the built-in function
//o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
//计算贴图缩放移动后的uv坐标
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
//归一化,方便计算,下面同理
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
// Use the texture to sample the diffuse color
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
//CG程序中用来在一张贴图中对一个点进行采样的方法
//float4 Tex2D(sampler2D tex, float2 s) :s - 需进行查找的纹理坐标(uv)
//把贴图颜色+属性中的颜色相乘作为反射率
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
//环境光渲染结果 = 自身贴图纹理颜色 * 环境光颜色值
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
//漫反射 = 灯光颜色 * 自身贴图纹理颜色
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
return fixed4(ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
FallBack "Specular"
}
顶点着色器要做的事:
MVP变换
法线转换成世界坐标
点转换成世界坐标
纹理坐标缩放,根据_ST进行缩放
片元着色器要做的事:
着色点看向光源的向量归一化
着色点看向观察点的方向向量归一化
反射率 = 获取到的纹理.rgb * _COLOR.rgb
漫反射 = 光源颜色 * 反射率 * max(0,dot(v,l))
halfDir = 法线 + 灯光方向(归一化)
高光 = 高光颜色 * 光源颜色 * pow(max(0,dot(h,v)))高光度)
环境光 = 反射率 * 环境光
具体内容看手册,这里只讲书里的几个。
Wrap Mode(选择纹理平铺时的行为方式):
纹理坐标超过【0,1】之后会如何平铺。
Repeat: 重复
Clamp:大于1截取至1,小于0截取至0。
Filter Mode(选择纹理在通过 3D 变换拉伸时如何进行过滤):
纹理放大变模糊,这个过程需要低通滤波过滤。
Point:像素风格,只采样一个像素
Bilinear:采样邻近四个像素,进行线性插值混合
Generate Mip Maps(多级渐远纹理技术):
就是MipMaps,Games101里面解释很详细了。
纹理管线(百人计划):