什么是立方体纹理
天空盒子 用于模拟背景的一种方式。
添加天空盒子:
新建材质,shader选择自带的Skybox/6 sided.
将图片附上,图片的wrap mode设置为clamp,
在window-rendering-lighting中的scene中将skybox设置为之前的材质
该设置会覆盖所有摄像机,如果希望使用不同的,需要给摄像机添加skybox组件。
创建环境映射的立方体纹理
特殊布局的纹理创建
需要类似立方体展开图或者全景布局图,将texture type设置为cubemap
手动创建Cubemap
上面的方法
脚本生成
通过unity提供的Camera.RenderToCubemap函数实现,该函数可以把任意位置的场景图像储存到6张图像中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 using UnityEngine;using UnityEditor;using System.Collections;public class RenderCubemapWizard : ScriptableWizard { public Transform renderFromPosition; public Cubemap cubemap; void OnWizardUpdate () { helpString = "Select transform to render from and cubemap to render into" ; isValid = (renderFromPosition != null ) && (cubemap != null ); } void OnWizardCreate () { GameObject go = new GameObject( "CubemapCamera" ); go.AddComponent<Camera>(); go.transform.position = renderFromPosition.position; go.GetComponent<Camera>().RenderToCubemap(cubemap); DestroyImmediate( go ); } [MenuItem("GameObject/Render into Cubemap" ) ] static void RenderCubemap () { ScriptableWizard.DisplayWizard<RenderCubemapWizard>( "Render cubemap" , "Render!" ); } }
通过调用该脚本就可以把一个位置的环境渲染到一个Cubemap当中。
反射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 Shader "Unity Shaders Book/Chapter 10/Reflection" { Properties { _Color ("Color Tint" , Color) = (1 , 1 , 1 , 1 ) _ReflectColor ("Reflection Color" , Color) = (1 , 1 , 1 , 1 ) _ReflectAmount ("Reflect Amount" , Range(0 , 1 )) = 1 _Cubemap ("Reflection Cubemap" , Cube) = "_Skybox" {} } SubShader { Tags { "RenderType" ="Opaque" "Queue" ="Geometry" } Pass { Tags { "LightMode" ="ForwardBase" } CGPROGRAM #pragma multi_compile_fwdbase #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" fixed4 _Color; fixed4 _ReflectColor; fixed _ReflectAmount; samplerCUBE _Cubemap; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD0; fixed3 worldNormal : TEXCOORD1; fixed3 worldViewDir : TEXCOORD2; fixed3 worldRefl : TEXCOORD3; SHADOW_COORDS(4 ) }; v2f vert (a2v v ) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos); o.worldRefl = reflect(-o.worldViewDir, o.worldNormal); TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i ) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 worldViewDir = normalize(i.worldViewDir); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0 , dot(worldNormal, worldLightDir)); fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb * _ReflectColor.rgb; UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); fixed3 color = ambient + lerp(diffuse, reflection, _ReflectAmount) * atten; return fixed4(color, 1.0 ); } ENDCG } } FallBack "Reflective/VertexLit" }
折射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 Shader "Unity Shaders Book/Chapter 10/Refraction" { Properties { _Color ("Color Tint" , Color) = (1 , 1 , 1 , 1 ) _RefractColor ("Refraction Color" , Color) = (1 , 1 , 1 , 1 ) _RefractAmount ("Refraction Amount" , Range(0 , 1 )) = 1 _RefractRatio ("Refraction Ratio" , Range(0.1 , 1 )) = 0.5 _Cubemap ("Refraction Cubemap" , Cube) = "_Skybox" {} } SubShader { Tags { "RenderType" ="Opaque" "Queue" ="Geometry" } Pass { Tags { "LightMode" ="ForwardBase" } CGPROGRAM #pragma multi_compile_fwdbase #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" fixed4 _Color; fixed4 _RefractColor; float _RefractAmount; fixed _RefractRatio; samplerCUBE _Cubemap; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD0; fixed3 worldNormal : TEXCOORD1; fixed3 worldViewDir : TEXCOORD2; fixed3 worldRefr : TEXCOORD3; SHADOW_COORDS(4 ) }; v2f vert (a2v v ) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos); o.worldRefr = refract(-normalize(o.worldViewDir), normalize(o.worldNormal), _RefractRatio); TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i ) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 worldViewDir = normalize(i.worldViewDir); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0 , dot(worldNormal, worldLightDir)); fixed3 refraction = texCUBE(_Cubemap, i.worldRefr).rgb * _RefractColor.rgb; UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); fixed3 color = ambient + lerp(diffuse, refraction, _RefractAmount) * atten; return fixed4(color, 1.0 ); } ENDCG } } FallBack "Reflective/VertexLit" }
菲涅尔反射 原理:当光线照射到物体表面时,一部分反射,一部分发生折射和散射,被反射的光和入射光存在一定的比率关系。
菲涅尔等式:
近似公式:Schlick 菲涅尔近似等式: $$ F_{Schlick}(v,n)=F_0+(1-F_0)(1-v·n)^5 $$ F0是反射系数,控制反射强度,v是视角方向,n是法线
应用广泛的等式是Empricial菲涅尔近似等式: $$ F_{Empricial}(v,n)=max(0,min(1,bias+scale\times(1-v·n)^{power})) $$ 三个英文是控制项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 Shader "Unity Shaders Book/Chapter 10/Fresnel" { Properties { _Color ("Color Tint" , Color) = (1 , 1 , 1 , 1 ) _FresnelScale ("Fresnel Scale" , Range(0 , 1 )) = 0.5 _Cubemap ("Reflection Cubemap" , Cube) = "_Skybox" {} } SubShader { Tags { "RenderType" ="Opaque" "Queue" ="Geometry" } Pass { Tags { "LightMode" ="ForwardBase" } CGPROGRAM #pragma multi_compile_fwdbase #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" #include "AutoLight.cginc" fixed4 _Color; fixed _FresnelScale; samplerCUBE _Cubemap; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD0; fixed3 worldNormal : TEXCOORD1; fixed3 worldViewDir : TEXCOORD2; fixed3 worldRefl : TEXCOORD3; SHADOW_COORDS(4 ) }; v2f vert (a2v v ) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos); o.worldRefl = reflect(-o.worldViewDir, o.worldNormal); TRANSFER_SHADOW(o); return o; } fixed4 frag (v2f i ) : SV_Target { fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 worldViewDir = normalize(i.worldViewDir); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos); fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb; fixed fresnel = _FresnelScale + (1 - _FresnelScale) * pow(1 - dot(worldViewDir, worldNormal), 5 ); fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0 , dot(worldNormal, worldLightDir)); fixed3 color = ambient + lerp(diffuse, reflection, saturate(fresnel)) * atten; return fixed4(color, 1.0 ); } ENDCG } } FallBack "Reflective/VertexLit" }