上次学习cg语言和shader是去年8月份的事了
后来发现学了也没有太多用的地方,就慢慢放下了
最近学ios开发,感觉既然是游戏开发者,还是需要学openglES
线性代数算是没有什么进步空间了(学一次忘一次....好几回了)
从图形学和图形方面入手试试算了
03.24日笔记
以下是一个MatCap 的shader
关于这个有个很奇妙的故事
就是我去年夏天第一次接触这个技术,感觉很神奇,但是没看懂原理
后来就睡着了,然后在梦里就(ˇˍˇ) 想明白这个的原理了.....醒来赶紧记下来
手写了整个shader,发现自己比去年厉害了不少,至少报错没那么多次了,而且基本知道错误的原因和位置
最关键的是我最近在论坛里学了好几个UnityCG.cginc的里面的函数,确实很方便,可以省略好多代码量
最后是这个shader的原理:我们可以设想一下,一个面对你的物体,它的所有法线到你的视平面的投射,其范围是x最大只能是1,最小-1,y也同理,因为这个是几乎平行于你的视屏面的向量投射在你的视屏面的投影向量,所以matcap的贴图会是一个球,带有光照信息的球,该物体的所有法线的投影的范围在x(-1,1),y(-1,1),构成了一个圆形
这就是原理
应用上的缺点,网上也写的很明白了,对于正方体类似的物体支持不太好,因为正方体的法线就3根(同时可见的),所有在采样图像的时候,会一闪一闪亮晶晶.......倒是有解决办法,就是flat着色改为smooth着色,这个是三维软件里的叫法,转到unity中,就是在import的选项里,重新计算导入模型的向量即可
Shader "Advanced/MatcapShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_MatCapTex("Matcap",2D) = "white"{}
_LightIntensity("PowerOfMat",Range(0,2)) = 0.5
_Blend("BlendTwoTex",Range(0,1)) = 0.5
}
SubShader {
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _MatCapTex;
float4 _MatCapTex_ST;
half _Blend;
half _LightIntensity;
struct VertexInput
{
float4 vertex:POSITION;
float4 normal:NORMAL;
half4 texcoord:TEXCOORD0;
};
struct VertexOutput {
float4 POS:SV_POSITION;
half4 NORMAL_WorldCoor:TEXCOORD0;
float2 uv_MainTex:TEXCOORD1;
float2 uv_Matcap:TEXCOORD2;
};
VertexOutput vert(VertexInput Input)
{
VertexOutput o;
o.POS = mul(UNITY_MATRIX_MVP,Input.vertex);
o.NORMAL_WorldCoor = mul(_Object2World,Input.normal);
o.uv_MainTex = TRANSFORM_TEX(Input.texcoord,_MainTex);
o.uv_Matcap.x = dot(UNITY_MATRIX_IT_MV[0].xyz,Input.normal);
o.uv_Matcap.y = dot(UNITY_MATRIX_IT_MV[1].xyz,Input.normal);
o.uv_Matcap = o.uv_Matcap*0.5 + 0.5;
return o;
}
inline float4 UnpackTex(sampler2D tex,float2 uv)
{
float4 result = tex2D(tex,uv);
return result;
}
float4 frag(VertexOutput o):COLOR
{
float4 _mainColor = UnpackTex(_MainTex,o.uv_MainTex)*_Blend;
float4 _matCapColor = UnpackTex(_MatCapTex,o.uv_Matcap)*_LightIntensity;
float4 TexColor = (_mainColor + _matCapColor );
return fixed4(TexColor.xyz,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
3月25日
今天写了一个
Cook-Torrance 的shader,肯定有地方有问题.......效果碉堡了
这个图可能看不清...颜色衰减和颗粒细度超级平滑融合
跟默认的diffuce一比较就能看出来了!!!~~~~
当然....这个计算量略大,多次平方,指数运算,好多除法.......应该是不适合移动手机
Shader "Advance/Cook" {
Properties {
_Color("Color",Color) = (1.0,1.0,1.0,1.0)
_SpecColor("SpecColor",Color) = (1.0,1.0,1.0,1.0)
_Shininess("Shininess",float) = 10.0
_m("mValue",float ) = 5
_fesnel ("Fesnel",float) = 3
}
SubShader {
Pass{
Tags { "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
uniform float4 _Color;
uniform float4 _SpecColor;
uniform float _Shininess;
//translate the variable from unity to our CGRPOGRAM
uniform float4 _LightColor0;
uniform float _m;
uniform float _fesnel;
struct vertexInput
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct vertexOutput
{
float4 pos:SV_POSITION;
float3 posWorld:TEXCOORD0;
float3 normalDir:TEXCOORD1;
};
vertexOutput vert(vertexInput i)
{
vertexOutput o;
o.normalDir = normalize(mul( float4(i.normal,0.0),_Object2World).xyz);
o.pos = mul(UNITY_MATRIX_MVP,i.vertex);
o.posWorld = mul(_Object2World,i.vertex).xyz;
return o;
}
float4 frag(vertexOutput o):COLOR
{
float3 P = o.posWorld.xyz;
float3 N = o.normalDir.xyz;
float3 L = normalize(_WorldSpaceLightPos0.xyz - P);
float nDotl = saturate(dot(L,N));
float3 V = normalize(_WorldSpaceCameraPos.xyz - P);
float3 H = normalize(L + V);
float3 specular = float3(0.0,0.0,0.0);
float nv = dot(N,V);
if(nv > 0 && nDotl > 0)
{
float nh = dot(N,H);
float temp = (nh*nh -1)/(_m*_m*nh*nh);
//rougth
float roughness = (exp(temp))/(pow(_m,2)*pow(nh,4.0));
float vh = dot(V,H);
float a = (2*nh*nv)/vh;
float b = (2*nh*nDotl)/vh;
float geometric = min(a,b);
geometric = min(1,geometric);
float fresnelCoe = _fesnel + (1 - _fesnel)*pow(1-vh,5.0);
float rs = (fresnelCoe * geometric *roughness)/(nv*nDotl);
specular = rs*_LightColor0*nDotl*_Shininess;
}
float3 colorDiffuce = _Color * nDotl;
float3 final = colorDiffuce + specular;
return float4(final,1);
}
ENDCG
}
}
}