Unity引擎制作假室内效果
大家好,我是阿赵。
这次来介绍一种使用CubeMap做假室内效果的方式。这种技术名叫InteriorCubeMap,是UE引擎自带的节点效果。我这里是在Unity引擎里面的实现。
一、效果展示
这个假室内效果,要动态看才能看出效果,各位可以看看上面的视频
简单来说,从不同的角度看这个面片,看到的里面的内容会随着视角的变化而变化,感觉好像从窗外观看室内的效果。
二、原理分析
实际上,并没有什么室内效果,那些都是一个一个的面片来的。
面片所显示的内容,其实是CubeMap贴图。
CubeMap贴图的用法之前在写天空盒变化的文章里面介绍过,各位可以去看看:
https://blog.csdn.net/liweizhao/article/details/129603219
当时的CubeMap采样时通过计算世界空间的ViewDir和世界空间的法线方向来做的
float3 worldViewDir = UnityWorldSpaceViewDir(i.worldPos);
worldViewDir = normalize(worldViewDir);
float3 worldReflect = reflect(worldViewDir,i.worldNormal);
float4 col = texCUBE(_SkyTex1, worldReflect);
所以如果使用在一个面片上面,也能做到里面的内容跟随这视角变化而变化,但由于面片的法线方向都是朝着同一个方向的,所以显示在上面的CubeMap是一个平面的效果。
但这个InteriorCubeMap的计算采样CubeMap的UV的方式比较特别,它会模拟成一个方形来采样CubeMap。
我把这个InteriorCubeMap节点的代码模拟成一个方法,求出一个采样的UV:
float3 InteriorCubeMap(float3 worldPosition, float3 worldTangent,float3 worldNormal,float3 worldBitangent,float2 uv)
{
float3 tanToWorld0 = float3(worldTangent.x, worldBitangent.x, worldNormal.x);
float3 tanToWorld1 = float3(worldTangent.y, worldBitangent.y, worldNormal.y);
float3 tanToWorld2 = float3(worldTangent.z, worldBitangent.z, worldNormal.z);
float3 worldViewDir = UnityWorldSpaceViewDir(worldPosition);
worldViewDir = normalize(worldViewDir);
float3 tanViewDir = tanToWorld0 * worldViewDir.x + tanToWorld1 * worldViewDir.y + tanToWorld2 * worldViewDir.z;
tanViewDir = Unity_SafeNormalize(tanViewDir);
float3 step1Val = (float3(-1, -1, 1) * tanViewDir);
float3 step2Val = (1.0 / step1Val);
float3 step3Val = (float3(((frac(((uv * float2(1, -1)) * (_Tilling).xx)) * float2(2, -2)) - float2(1, -1)), -1.0*_Depth));
float3 step4Val = (abs(step2Val) - (step2Val * step3Val));
float3 step5Val = ((min(min(step4Val.x, step4Val.y), step4Val.z) * step1Val) + step3Val);
return (float3(step5Val.z, step5Val.x, step5Val.y));
}
通过调节Depth参数,可以模拟不同深度的室内效果。
通过调节Tilling平铺次数,可以模拟多个相同的房间放在一起的效果。
三、代码
Shader "azhao/InteriorCubeMapTest"
{
Properties
{
_Tilling("Tilling", Vector) = (1,1,1,1)
_CubeTex("Texture Sample 0", CUBE) = "white" {}
_Depth("Depth",Range(0,5)) = 1
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityStandardBRDF.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 color : COLOR;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float3 worldTangent : TEXCOORD2;
float3 worldNormal : TEXCOORD3;
float3 worldBitangent : TEXCOORD4;
};
samplerCUBE _CubeTex;
float2 _Tilling;
float _Depth;
float3 InteriorCubeMap(float3 worldPosition, float3 worldTangent,float3 worldNormal,float3 worldBitangent,float2 uv)
{
float3 tanToWorld0 = float3(worldTangent.x, worldBitangent.x, worldNormal.x);
float3 tanToWorld1 = float3(worldTangent.y, worldBitangent.y, worldNormal.y);
float3 tanToWorld2 = float3(worldTangent.z, worldBitangent.z, worldNormal.z);
float3 worldViewDir = UnityWorldSpaceViewDir(worldPosition);
worldViewDir = normalize(worldViewDir);
float3 tanViewDir = tanToWorld0 * worldViewDir.x + tanToWorld1 * worldViewDir.y + tanToWorld2 * worldViewDir.z;
tanViewDir = Unity_SafeNormalize(tanViewDir);
float3 step1Val = (float3(-1, -1, 1) * tanViewDir);
float3 step2Val = (1.0 / step1Val);
float3 step3Val = (float3(((frac(((uv * float2(1, -1)) * (_Tilling).xy)) * float2(2, -2)) - float2(1, -1)), -1.0*_Depth));
float3 step4Val = (abs(step2Val) - (step2Val * step3Val));
float3 step5Val = ((min(min(step4Val.x, step4Val.y), step4Val.z) * step1Val) + step3Val);
return (float3(step5Val.z, step5Val.x, step5Val.y));
}
v2f vert(appdata v)
{
v2f o;
o.worldTangent = UnityObjectToWorldDir(v.tangent);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
float vertexTangentSign = v.tangent.w * unity_WorldTransformParams.w;
float3 worldBitangent = cross(o.worldNormal, o.worldTangent) * vertexTangentSign;
o.worldBitangent.xyz = worldBitangent;
o.uv = v.uv;
o.vertex = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
half4 frag(v2f i) : SV_Target {
float3 cubeUV = InteriorCubeMap(i.worldPos,i.worldTangent, i.worldNormal, i.worldBitangent, i.uv);
half4 finalColor = texCUBE(_CubeTex, cubeUV);
return finalColor;
}
ENDCG
}
}
}