在unity中,有时候不想使用内置的天空球去渲染,那么,我们就会使用一个球体去渲染天空球。为了保证游戏场景模型都放置在天空球内。球体就会放大的很大,那么问题就来了,这样会导致球体超出了相机的可视范围,导致天空球无法渲染,调整相机的裁减远面,会影响性能,还影响渲染效果。
这里有个解决方案,就是我们可以在材质里面去修改球体的顶点着色器输出的裁减坐标,将它的值限制在-w到w的范围内,来解决无法被渲染的问题。
UNITY_REVERSED_Z 这个属性则是为了判断是否翻转z 深度,像D3D平台,Metal平台,远裁剪面都是接近于0,他们都设置了UNITY_REVERSED_Z 值为1
而Opengl平台则 远裁剪面的值为w,但是没有设置UNITY_REVERSED_Z 的值。
所以,我们可以通过宏进行一下判断,如果UNITY_REVERSED_Z 有值positionCS.w * 0.0001f,
如果UNITY_REVERSED_Z 没有值,我们设置一下positionCS.w * 0.9999f,让模型裁剪空间位置无限接近于远裁剪面,就实现了当前的这个功能。
这是一个基于unlit修改的防止被裁剪的天空球shader
Shader "Unlit/SkyBox"
{
Properties
{
_MainTex ("Texture", 2D) = "white" { }
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//将输出位置的z坐标限制在-1到1的范围内,这样可以防止自定义的天空球被裁剪掉
#if UNITY_REVERSED_Z //这个宏是用来判断平台的,有个平台最远裁剪值是w,有的是-w
o.vertex.z = o.vertex.w * 0.000001f;
#else
o.vertex.z = o.vertex.w * 0.999999f;
#endif
return o;
}
half4 frag(v2f i) : SV_Target
{
// sample the texture
half4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
个人发现,在urp管线里面,精度没有那么高,需要这样写:
Shader "Unlit/SkyBox"
{
Properties
{
_BaseMap ("Texture", 2D) = "white" { }
_BaseColor ("Color", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags { "RenderType" = "Background" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline" "ShaderModel" = "4.5" }
LOD 100
ZWrite On
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
float4 _BaseMap_HDR;
half4 _BaseColor;
CBUFFER_END
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 positionCS : SV_POSITION;
};
v2f vert(appdata v)
{
v2f o;
o.positionCS = TransformObjectToHClip(v.vertex.xyz);
o.uv = TRANSFORM_TEX(v.uv, _BaseMap);
#if UNITY_REVERSED_Z //这个宏是用来判断平台的,有个平台最远裁剪值是1,有的是-1
o.positionCS.z = o.positionCS.w * 0.0001f;
#else
o.positionCS.z = o.positionCS.w * 0.9999f;
#endif
return o;
}
half4 frag(v2f i) : SV_Target
{
half4 col = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv);
col.rgb = DecodeHDREnvironment(col, _BaseMap_HDR) * _BaseColor.rgb;
return col;
}
ENDHLSL
}
}
}
降低一下精度