zoukankan      html  css  js  c++  java
  • Unity3D ShaderLab 静态贴图光照模型

     Unity3D ShaderLab 静态贴图光照模型

    其实在unity的光照模型中,我们可以把光照讯息烘培进入一个2D贴图,来实现着色器的光照效果。

    下面是在unity中关闭灯光和打开灯光的对比效果。所以这类着色器的缺点就是不会随着光源变化效果。

     

     

     

    接下来,我们开始创建,首先通过软件MaCrea来制作我们的2D光照贴图,MaCrea软件

     

    通过该软件可以快速制作一个完整的发光球体平面图。

    软件地址:http://pan.baidu.com/s/1bnD7wkv

    软件视频教学地址:http://pan.baidu.com/s/1c0rQDva

    完成静态光照贴图的制作后。在unity中创建ShaderMaterial

    直接打开Shader脚本编辑:

    1>Properties: 

    1 Properties {
    2 
    3 _MainTint("Diffuse Color",Color) = (1,1,1,1)
    4 
    5 _MainTex ("Base (RGB)", 2D) = "white" {}
    6 
    7 _NormalMap("Normal Map",2D) = ""{}
    8 
    9 }

    2>SubShader:

     1 CGPROGRAM
     2 
     3 #pragma surface surf Unlit vertex:vert
     4 
     5  
     6 
     7 float4 _MainTint;
     8 
     9 sampler2D _MainTex;
    10 
    11 sampler2D _NormalMap;
    12 
    13 struct Input {
    14 
    15 float2 uv_MainTex;
    16 
    17 float2 uv_NormalMap;
    18 
    19 float3 tan1;
    20 
    21 float3 tan2;
    22 
    23 };

    //因为我们要使用单独的球体贴图来实现光照,所以我们无需使用Lambert光照函数,只需要申明自定义无光亮的光照函数;

    3>光照函数

     1 inline fixed4 LightingUnlit(SurfaceOutput s, fixed3 lightDir, fixed3 atten){
     2 
     3 fixed4 c= fixed4(1,1,1,1);
     4 
     5 c.rgb = c*s.Albedo;
     6 
     7 c.a = s.Alpha;
     8 
     9 return c;
    10 
    11 }

    //我们只希望通过外部物体来产生阴影,因为该着色器不受光源的;

    4>计算球面贴图

     1 void vert(inout appdata_full v, out Input o){
     2 
     3 UNITY_INITIALIZE_OUTPUT(Input, o);
     4 
     5  
     6 
     7 TANGENT_SPACE_ROTATION ;
     8 
     9 o.tan1 = mul(rotation,UNITY_MATRIX_IT_MV[0].xyz);
    10 
    11 o.tan2 = mul(rotation,UNITY_MATRIX_IT_MV[1].xyz);
    12 
    13 }

    //为了正确的检索到球面贴图,我们需要把正切旋转矩阵乘以当前模型的逆转模型视图;

    5>完善surf

     1 void surf (Input IN, inout SurfaceOutput o) {
     2 
     3 float3 normals = UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
     4 
     5 o.Normal = normals;
     6 
     7  
     8 
     9 float2 litSphereUV;
    10 
    11 litSphereUV.x = dot(IN.tan1,o.Normal);
    12 
    13 litSphereUV.y = dot(IN.tan2,o.Normal);
    14 
    15  
    16 
    17 half4 c = tex2D (_MainTex, litSphereUV*0.5+0.5);
    18 
    19 o.Albedo = c.rgb*_MainTint;
    20 
    21 o.Alpha = c.a;
    22 
    23 }

     

    通过以上的步骤,我们完成这个静态的光照模型。返回unity中简单设置后,就可以看出效果了。

     

    在上面的过程中,最主要的是vert函数,因为在这个函数里,我们把旋转切向量和逆转模型视图矩阵相乘,在赋值给o.tan1o.tan2

    这个计算就是把向量弯曲到何时的位置来检索球面的贴图。而逆转模型视图则是我们利用unity内置的值。

    通过上面的检索传递后,我们简单的将IN.tan1IN.tan2的值作为球面贴图纹理检索的uv值,

    我们可以直接使用input结构体中的值,因为我们也在vert函数中将这些值传递进去了。

     

     1 Shader "91YGame/LightStatic" {
     2     Properties {
     3         _MainTint("Diffuse Color",Color) = (1,1,1,1)
     4         _MainTex ("Base (RGB)", 2D) = "white" {}
     5         _NormalMap("Normal Map",2D) = ""{}
     6     }
     7     SubShader {
     8         Tags { "RenderType"="Opaque" }
     9         LOD 200
    10         
    11         CGPROGRAM
    12         #pragma surface surf Unlit vertex:vert
    13 
    14         float4 _MainTint;
    15         sampler2D _MainTex;
    16         sampler2D _NormalMap;
    17 
    18         struct Input {
    19             float2 uv_MainTex;
    20             float2 uv_NormalMap;
    21             float3 tan1;
    22             float3 tan2;
    23         };
    24 
    25 
    26 
    27         inline fixed4 LightingUnlit(SurfaceOutput s, fixed3 lightDir, fixed3 atten){
    28             fixed4 c= fixed4(1,1,1,1);
    29             c.rgb = c*s.Albedo;
    30             c.a = s.Alpha;
    31             return c;
    32         }
    33 
    34         void vert(inout appdata_full v, out Input o){
    35             UNITY_INITIALIZE_OUTPUT(Input, o);
    36 
    37             TANGENT_SPACE_ROTATION;
    38             o.tan1 = mul(rotation,UNITY_MATRIX_IT_MV[0].xyz);
    39             o.tan2 = mul(rotation,UNITY_MATRIX_IT_MV[1].xyz);
    40         }
    41 
    42         void surf (Input IN, inout SurfaceOutput o) {
    43             float3 normals = UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
    44             o.Normal = normals;
    45 
    46             float2 litSphereUV;
    47             litSphereUV.x = dot(IN.tan1,o.Normal);
    48             litSphereUV.y = dot(IN.tan2,o.Normal);
    49 
    50             half4 c = tex2D (_MainTex, litSphereUV*0.5+0.5);
    51             o.Albedo = c.rgb*_MainTint;
    52             o.Alpha = c.a;
    53         }
    54         ENDCG
    55     } 
    56     FallBack "Diffuse"
    57 }

     

     

     

  • 相关阅读:
    Java中会存在内存泄漏吗,请简单描述。
    什么是类加载器
    通俗易懂 索引、单列索引、复合索引、主键、唯一索引、聚簇索引、非聚簇索引、唯一聚簇索引 的区别与联系
    Redis真的那么好用吗
    java中public,private,protected和default的区别
    聚集和非聚集索引
    我以为我对Mysql索引很了解,直到我遇到了阿里的面试官(转)
    Java中存储金额用什么数据类型
    InnoDB在MySQL默认隔离级别下解决幻读
    android应用程序第一次启动时显示引导界面
  • 原文地址:https://www.cnblogs.com/2Yous/p/4246208.html
Copyright © 2011-2022 走看看