【Unity Shaders】学习笔记——SurfaceShader(九)Cubemap

  1. 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以。

  2. 水平有限,难免有谬误之处,望指出。


上一节中讲述了制作Cubemap的方法。这一节讲讲怎么使用它。

Simple Cubemap

先来看一下最简单的Cubemap。

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"
}

其实就是用texCUBE()函数来对Cubemap采样。

第二个参数应该传入UV坐标,但实际传入的是世界反射向量。这是Unity替我们计算了UV坐标。
Cubemap是由六张贴图构成的,组成了一个类似天空盒的六面体,那这六张贴图是如何映射到小球上的呢,使小球看起来像倒映着周围的环境一样?
将Cubemap想象成一个立方体,包裹着小球,从小球的中心点发射一条射线,穿过小球表面和立方体表面,射线与小球和立方体会各有一个交点,小球上的这个点对应的就是立方体上的这个点的纹理。那要怎样计算各个点对应的UV坐标呢?从小球中心点发射的一条条射线其实就是法线,有个很明显的事实就是,法线朝向法线坐标分量最大的坐标轴指向的立方体的面。也就是坐标(1,1,3)的法线朝向的是Z轴指向的立方体的面。这样就由法线找到了点对应的面。那么UV坐标又该如何计算呢?法线另外两个较小的坐标值和UV坐标是有关系的。举个特殊点的例子,小球最顶点的法线的坐标应该是(0,0,1),对应的应该是立方体的顶面的中点,UV坐标应该是(0.5,0.5)。计算UV坐标的方法是(x/z×0.5+0.5,y/z×0.5+0.5),将特殊点代进去,答案是正确的。原理有点难说明,相当于把X、Y坐标投影到了对应的面上。乘0.5加0.5是为了让法线坐标的区间从[-1,1]变为[0,1]。
在Unity里,我们不必自己计算,可以直接使用内置变量worldRefl来检索Cubemap。

Normal Cubemap

Shader "Custom/NormalMappedReflection"
{
Properties
{
_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_NormalMap ("Normal Map", 2D) = "bump" {}
_Cubemap ("Cubemap", CUBE) = ""{}
_ReflAmount ("Reflection Amount", Range(0,1)) = 0.5
} SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200 CGPROGRAM
#pragma surface surf Lambert samplerCUBE _Cubemap;
sampler2D _MainTex;
sampler2D _NormalMap;
float4 _MainTint;
float _ReflAmount; struct Input
{
float2 uv_MainTex;
float2 uv_NormalMap;
float3 worldRefl;
INTERNAL_DATA
}; void surf (Input IN, inout SurfaceOutput o)
{
half4 c = tex2D (_MainTex, IN.uv_MainTex); float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;
o.Normal = normals; o.Emission = texCUBE (_Cubemap, WorldReflectionVector (IN, o.Normal)).rgb * _ReflAmount;
o.Albedo = c.rgb * _MainTint;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}

就只是增加了法线贴图而已。
因为法线信息的改变,所以要重新计算传入texCUBE()函数的世界反射向量。float3 worldRefl;INTERNAL_DATA变量用于原本的法线信息不使用时,比如使用了法线贴图,原来的法线信息就不使用了。要根据新的法线信息计算世界反射向量使用WorldReflectionVector()函数。

动态立方图系统

有时候游戏里的物体从一个环境走到另一个环境,需要更换Cubemap,这样显示的反射效果才真实。
有两种方法更换Cubemap,一种是实时更换Cubemap,这样的效果最真实,但是要牺牲性能;第二种是当物体走到另一个环境的时候更换Cubemap,这就是我要讲的方法。
方法很简单,就是在C#里用SetTexture的方法动态更换Cubemap。

[ExecuteInEditMode]
public class SwapCubemaps : MonoBehaviour
{
public Cubemap cubeA;
public Cubemap cubeB; public Transform posA;
public Transform posB; private Material curMat;
private Cubemap curCube; // Use this for initialization
void Start ()
{ } // Update is called once per frame
void Update ()
{
curMat = renderer.sharedMaterial;
if(curMat)
{
curCube = CheckProbeDistance();
curMat.SetTexture("_Cubemap", curCube); }
} private Cubemap CheckProbeDistance()
{
float distA = Vector3.Distance(transform.position, posA.position);
float distB = Vector3.Distance(transform.position, posB.position); if(distA < distB)
{
return cubeA;
}
else if(distB < distA)
{
return cubeB;
}
else
{
return cubeA;
} } void OnDrawGizmos()
{
Gizmos.color = Color.green; if(posA)
{
Gizmos.DrawWireSphere(posA.position, 0.5f);
} if(posB)
{
Gizmos.DrawWireSphere(posB.position, 0.5f);
}
}
}
  1. [ExecuteInEditMode]是为了让脚本在编辑器状态的时候也能执行,这样就不必点击Play调试,比较方便。

  2. OnDrawGizmos()是在Scene里画一些可视化的东西方便调试。

  3. CheckProbeDistance()里用Distance判断物体和A点、B点的距离,根据距离决定返回哪种Cubemap。

  4. 在Update()设置材质的Cubemap。

Cubemap效果

Cubemap

我有加个金属的纹理。效果是这样的。

NormalCubemap

这是加了法线贴图的。

【Unity Shaders】学习笔记——SurfaceShader(九)Cubemap的更多相关文章

  1. 【Unity Shaders】学习笔记——SurfaceShader(八)生成立方图

    [Unity Shaders]学习笔记——SurfaceShader(八)生成立方图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5630261.html ...

  2. 【Unity Shaders】学习笔记——SurfaceShader(十一)光照模型

    [Unity Shaders]学习笔记——SurfaceShader(十一)光照模型 转载请注明出处:http://www.cnblogs.com/-867259206/p/5664792.html ...

  3. 【Unity Shaders】学习笔记——SurfaceShader(十)镜面反射

    [Unity Shaders]学习笔记——SurfaceShader(十)镜面反射 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以. 水 ...

  4. 【Unity Shaders】学习笔记——SurfaceShader(七)法线贴图

    [Unity Shaders]学习笔记——SurfaceShader(七)法线贴图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5627565.html 写 ...

  5. 【Unity Shaders】学习笔记——SurfaceShader(六)混合纹理

    [Unity Shaders]学习笔记——SurfaceShader(六)混合纹理 转载请注明出处:http://www.cnblogs.com/-867259206/p/5619810.html 写 ...

  6. 【Unity Shaders】学习笔记——SurfaceShader(五)让纹理动起来

    [Unity Shaders]学习笔记——SurfaceShader(五)让纹理动起来 转载请注明出处:http://www.cnblogs.com/-867259206/p/5611222.html ...

  7. 【Unity Shaders】学习笔记——SurfaceShader(四)用纹理改善漫反射

    [Unity Shaders]学习笔记——SurfaceShader(四)用纹理改善漫反射 转载请注明出处:http://www.cnblogs.com/-867259206/p/5603368.ht ...

  8. 【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert

    [Unity Shaders]学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert 转载请注明出处:http://www.cnblogs.com/-867259 ...

  9. 【Unity Shaders】学习笔记——SurfaceShader(二)两个结构体和CG类型

    [Unity Shaders]学习笔记——SurfaceShader(二)两个结构体和CG类型 转载请注明出处:http://www.cnblogs.com/-867259206/p/5596698. ...

随机推荐

  1. js 如何生成二维数组

    想了几种方法都不能很好的,用js定义二维数组.这种定义,指的是:定义按需确认数组大小. 网上看了下,都是用for循环创建,大小必须提前设定.不是我想要的.(感觉不能和php一样,真是麻烦!) 先贴出代 ...

  2. angularjs webstorm 单元测试 Package.json

    Package.json小结 生成package.json 定位到想放置package.json的目录,运行npm init,根据提示就可以生成package.json文件,其中test comman ...

  3. Java-输入输出

    1. 流的分类 java.io 1.1 输入和输出流 File类不能访问文件内容本身,需要使用输入/输出流 输入输出流的方向是相对与内存读写的方向. 1.2 字节流和字符流 字节流 InputStea ...

  4. WINDOWS黑客基础(3):注入代码

    有使用过外挂的朋友应该知道,我们在玩游戏的时候,有很多辅助功能给你使用,比如吃药,使用物品等功能,这个时候我们就是使用注入代码的技术,简单的来将就是我们让另外一个进程去执行我们想让它执行的代码,这中间 ...

  5. .NET常用方法收藏

    1.过滤文本中的HTML标签 /// <summary> /// 清除文本中Html的标签 /// </summary> /// <param name="Co ...

  6. 【转】CSS浏览器兼容性与解析问题终极归纳

    1.怪异模式问题:漏写DTD声明,Firefox仍然会按照标准模式来解析网页,但在IE中会触发怪异模式.为避免怪异模式给我们带来不必要的麻烦,最好养成书写DTD声明的好习惯. 2.IE6双边距问题:在 ...

  7. windows server 2012将计算机、回收站、文档等图标添加到桌面

    rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0

  8. Well, let's start everything from the very beginning.

    帝都的霾仿佛亘古不变,不知觉2015年竟已快到尾声,而我在IBM也已呆了4个月.回顾过往多遇贵人,所获颇丰.最幸运的还是自己不忘初心,仍在不断成长.继续学习. 过去的几个月一直用WordPress,搭 ...

  9. c++ std::sort函数调用经常出现的invalidate operator<错误原因以及解决方法

    在c++编程中使用sort函数,自定义一个数据结构并进行排序时新手经常会碰到这种错误. 这是为什么呢?原因在于什么?如何解决? 看下面一个例子: int main(int, char*[]) { st ...

  10. angular.js form

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...