【Unity Shaders】Reflecting Your World —— Unity3D中简单的Cubemap反射

在Project中可以创建我们自己的Cubemaps,现在,我们可以来看一下如何使用这种新的贴图类型来在Shaders中模拟反射效果。使用Cubemaps进行反射的原理实际上非常简单,但是这将给你的Shader效果带来翻天覆地的变化。它的原理主要是通过模型表面的每个顶点的法向量,去查找Cubemap贴图上的某一个位置。这种查找将会返回一个颜色值,来模拟这个Cubemap反射到你的对象上的这种效果。

这篇教程将会教给你用Cubemaps来进行反射的第一步!Unity实际上给我们提供了自动得到反射向量的方法,所以我们不需要自己去计算它了。这是在Input结构体中的内置的worldRefl向量中实现的。这会帮助我们去查找对应的Cubemap贴图中的位置。因此,第一步的内容将非常简单!


准备工作


在我们开始写Shader代码之前,我们需要搭建一个简单的场景。
  1. 创建一个新的scene,Material,和Shader,可以取名为SimpleReflection。
  2. 附着新的Shader到新的Material上,然后创建一个物体,并把Material赋值给它。
  3. 最后,创建或者找到一个Cubemap,之后将用于我们的Shader。

下面的截图显示了我们这节中将要使用的Cubemap




实现


下面,让我们来实现真正的Shader代码吧!

  1. 首先在Properties块中创建新的properties。我们需要一个位置来得到我们的Cubemap贴图对象以及来控制反射的程度:
    Properties {  
    1.     _MainTex ("Base (RGB)", 2D) = "white" {}  
    2.       
    3.     _MainTint ("Diffuse Tint", Color) = (1,1,1,1)  
    4.     _Cubemap ("CubeMap", CUBE) = ""{}  
    5.     _ReflAmount ("Reflection Amount", Range(0.01, 1)) = 0.5  
    6. }  
    	Properties {
    		_MainTex ("Base (RGB)", 2D) = "white" {}
    		
    		_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
    		_Cubemap ("CubeMap", CUBE) = ""{}
    		_ReflAmount ("Reflection Amount", Range(0.01, 1)) = 0.5
    	}
  2. 同样,我们还需要在SubShader块中创建和properties中各变量的联系。这将允许我们从Properties块中访问这些数据。
    CGPROGRAM  
    1. #pragma surface surf Lambert  
    2.   
    3. sampler2D _MainTex;  
    4. samplerCUBE _Cubemap;  
    5. float4 _MainTint;  
    6. float _ReflAmount  
    		CGPROGRAM
    		#pragma surface surf Lambert
    
    		sampler2D _MainTex;
    		samplerCUBE _Cubemap;
    		float4 _MainTint;
    		float _ReflAmount

  3. 为了让我们能够模拟正确的反射角度,我们需要得到一个向量来提供给我们合适的世界反射方向。因此,我们可以使用上面提到的Unity的Surface Shaders内置的变量。在Input结构体中,下面的代码将提供给我们一个世界反射向量,来用于接下来的Shader中:
    1. struct Input {  
    2.     float2 uv_MainTex;  
    3.     float3 worldRefl  
    4. };  
    		struct Input {
    			float2 uv_MainTex;
    			float3 worldRefl
    		};

  4. 最后,我们仅仅需要从Cubemap中得到贴图信息,即使用texCUBE函数和Input提供给我们的新的世界反射向量。添加下面的代码到你的surf函数中:
    void surf (Input IN, inout SurfaceOutput o) {  
    1.     half4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;  
    2.     o.Emission = texCUBE(_Cubemap, IN.worldRefl).rgb * _ReflAmount;;  
    3.     o.Albedo = c.rgb;  
    4.     o.Alpha = c.a;  
    		void surf (Input IN, inout SurfaceOutput o) {
    			half4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
    			o.Emission = texCUBE(_Cubemap, IN.worldRefl).rgb * _ReflAmount;;
    			o.Albedo = c.rgb;
    			o.Alpha = c.a;
    		

整体代码如下:
Shader "Custom/SimpleReflection" {  
  1.     Properties {  
  2.         _MainTint ("Diffuse Tint", Color) = (1,1,1,1)  
  3.         _MainTex ("Base (RGB)", 2D) = "white" {}  
  4.         _Cubemap ("CubeMap", CUBE) = ""{}  
  5.         _ReflAmount ("Reflection Amount", Range(0.01, 1)) = 0.5  
  6.     }  
  7.       
  8.     SubShader {  
  9.         Tags { "RenderType"="Opaque" }  
  10.         LOD 200  
  11.           
  12.         CGPROGRAM  
  13.         #pragma surface surf Lambert  
  14.   
  15.         sampler2D _MainTex;  
  16.         samplerCUBE _Cubemap;  
  17.         float4 _MainTint;  
  18.         float _ReflAmount;  
  19.   
  20.         struct Input {  
  21.             float2 uv_MainTex;  
  22.             float3 worldRefl;  
  23.         };  
  24.   
  25.         void surf (Input IN, inout SurfaceOutput o) {  
  26.             half4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;  
  27.             o.Emission = texCUBE(_Cubemap, IN.worldRefl).rgb * _ReflAmount;;  
  28.             o.Albedo = c.rgb;  
  29.             o.Alpha = c.a;  
  30.         }  
  31.         ENDCG  
  32.     }   
  33.     FallBack "Diffuse"  
  34. }  
最后,当我们和上一篇中创建的Cubemap结合起来后,就可以得到下面的效果。可以看到其中的球有反射的效果。



解释


上面代码能够成功的主要原因就是Unity3D提供的Surface Shader的Input结构的内置属性。worldRefl变量给我们需要的反射向量来正确的采样我们的Cubemap。我们仅需要在函数中使用worldRefl属性,就可以很方便地得到正确的反射视角。

下面的截图展示了一个什么是传递给Shader的反射数据的例子。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值