查看: 1759|回复: 0
打印 上一主题 下一主题

[经验分享] Unity3D中简单的Cubemap反射

[复制链接]

100

主题

3

听众

7683

积分

高级设计师

Rank: 6Rank: 6

纳金币
2378
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2015-2-13 00:46:58 |只看该作者 |倒序浏览

本系列主要参考《Unity Shaders and Effects Cookbook》一书(感谢原书作者),同时会加上一点个人理解或拓展。


这里是本书所有的插图。这里是本书所需的代码和资源(当然你也可以从官网下载)。

========================================== 分割线 ==========================================



写在前面


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



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





准备工作


在我们开始写Shader代码之前,我们需要搭建一个简单的场景。


创建一个新的scene,Material,和Shader,可以取名为SimpleReflection。

附着新的Shader到新的Material上,然后创建一个物体,并把Material赋值给它。

最后,创建或者找到一个Cubemap,之后将用于我们的Shader。



下面的截图显示了我们这节中将要使用的Cubemap(这是通过在上一篇的基础上,在场景中球体所在的位置创建的自己的Cubemap)。你的可能和它不一样,没有关系,我们仅仅是想展示一下使用的Cubemap的样子,以便在最后的效果中不会产生任何难理解的地方。使用自己的也是完全可以的。
















实现


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




首先在Properties块中创建新的properties。我们需要一个位置来得到我们的Cubemap贴图对象以及来控制反射的程度:

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

}

同样,我们还需要在SubShader块中创建和properties中各变量的联系。这将允许我们从Properties块中访问这些数据。

CGPROGRAM

#pragma surface surf Lambert


sampler2D _MainTex;

samplerCUBE _Cubemap;

float4 _MainTint;

float _ReflAmount


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

struct Input {

float2 uv_MainTex;

float3 worldRefl

};


最后,我们仅仅需要从Cubemap中得到贴图信息,即使用texCUBE函数和Input提供给我们的新的世界反射向量。添加下面的代码到你的surf函数中:         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” {

Properties {

_MainTint (“Diffuse Tint”, Color) = (1,1,1,1)

_MainTex (“Base (RGB)”, 2D) = “white” {}

_Cubemap (“CubeMap”, CUBE) = “”{}

_ReflAmount (“Reflection Amount”, Range(0.01, 1)) = 0.5

}


SubShader {

Tags { “RenderType”=”Opaque” }

LOD 200


CGPROGRAM

#pragma surface surf Lambert


sampler2D _MainTex;

samplerCUBE _Cubemap;

float4 _MainTint;

float _ReflAmount;


struct Input {

float2 uv_MainTex;

float3 worldRefl;

};


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;

}

ENDCG

}

FallBack “Diffuse”

}





最后,当我们和上一篇中创建的Cubemap结合起来后,就可以得到下面的效果。可以看到其中的球有反射的效果。













解释


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



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




转自:http://www.yxkfw.com/?p=45054
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-12-1 05:06 , Processed in 0.095293 second(s), 28 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部