2024-11-01 16:55:46 +08:00

167 lines
5.2 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.Universal.Internal;
using UnityEngine.XR;
[ExecuteAlways]
public class _3DSkybox : MonoBehaviour
{
private _3DSkyboxPass pass;
private DrawObjectsPass drawPass;
public LayerMask mask;
private FilteringSettings filterOpaqueSettings = FilteringSettings.defaultValue;
private FilteringSettings filterTransparentSettings = FilteringSettings.defaultValue;
private RenderStateBlock renderStateBlock;
public int stencilRef;
private StencilState stencilState;
public Material depthClearMat;
public float scale = 64;
private void OnEnable()
{
pass ??= new _3DSkyboxPass();
// injection point
pass.renderPassEvent = RenderPassEvent.AfterRenderingSkybox;
// setup 3D skybox stuff
filterOpaqueSettings = new FilteringSettings(RenderQueueRange.opaque, mask.value);
filterTransparentSettings = new FilteringSettings(RenderQueueRange.transparent, mask.value);
renderStateBlock = new RenderStateBlock(RenderStateMask.Stencil);
stencilState = StencilState.defaultValue;
stencilState.enabled = true;
stencilState.SetCompareFunction(CompareFunction.Equal);
renderStateBlock.stencilReference = stencilRef;
renderStateBlock.stencilState = stencilState;
// setup callback
RenderPipelineManager.beginCameraRendering += OnBeginCamera;
RenderPipelineManager.endCameraRendering += EndCamera;
}
private void OnDisable()
{
RenderPipelineManager.beginCameraRendering -= OnBeginCamera;
RenderPipelineManager.endCameraRendering -= EndCamera;
}
private void OnBeginCamera(ScriptableRenderContext context, Camera cam)
{
//Avoid rendering while in terminal
if (SceneTransitionManager.IsAvailable() && SceneTransitionManager.IsInTerminal() && cam.CompareTag("MainCamera"))
{
return;
}
if (pass == null) return;
if (cam.cameraType != CameraType.Game && cam.cameraType != CameraType.SceneView) return;
pass.filterOpaqueSettings = filterOpaqueSettings;
pass.filterTransparentSettings = filterTransparentSettings;
pass.renderStateBlock = renderStateBlock;
pass.depthClearMat = depthClearMat;
// Do transform
TransformSkybox(cam);
// inject pass
cam.GetUniversalAdditionalCameraData().scriptableRenderer.EnqueuePass(pass);
}
private void EndCamera(ScriptableRenderContext arg1, Camera arg2)
{
transform.position = Vector3.zero;
transform.localScale = Vector3.one;
}
private void TransformSkybox(Camera cam)
{
if (cam.cameraType == CameraType.SceneView) return;
var offset = cam.transform.position * (1 - (1/scale));
transform.position = offset;
transform.localScale = Vector3.one * (1/scale);
}
private class _3DSkyboxPass : ScriptableRenderPass
{
public FilteringSettings filterOpaqueSettings;
public FilteringSettings filterTransparentSettings;
public RenderStateBlock renderStateBlock;
public Material depthClearMat;
List<ShaderTagId> shaderTags = new List<ShaderTagId>
{
new("SRPDefaultUnlit"), new("UniversalForward"), new("UniversalForwardOnly")
};
public _3DSkyboxPass()
{
profilingSampler = new ProfilingSampler(nameof(_3DSkyboxPass));
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
DrawSkyboxObjects(ref renderingData, context);
// Clear the depth values
var cmd = CommandBufferPool.Get("3D Skybox");
if (depthClearMat != null)
{
CoreUtils.DrawFullScreen(cmd, depthClearMat);
}
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
}
private void DrawSkyboxObjects(ref RenderingData renderingData, ScriptableRenderContext context)
{
var drawSettings =
RenderingUtils.CreateDrawingSettings(shaderTags, ref renderingData, SortingCriteria.CommonOpaque);
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterOpaqueSettings,
ref renderStateBlock);
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterTransparentSettings,
ref renderStateBlock);
}
}
private Camera cam;
private void OnDrawGizmosSelected()
{
if (cam == null) cam = Camera.main;
if (cam == null) return;
Gizmos.matrix = cam.transform.localToWorldMatrix;
var c = Color.red;
c.a = 0.2f;
Gizmos.color = c;
Gizmos.DrawFrustum(Vector3.zero, cam.fieldOfView, cam.farClipPlane * (1f/scale), cam.nearClipPlane * (1f/scale), cam.aspect);
}
}