Boat Attack使用了Universal RP的许多新图形功能,可以用于探索 Universal RP 的使用方式和技巧。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

401 行
18 KiB

using System;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using IDataProvider = UnityEngine.Rendering.LookDev.IDataProvider;
namespace UnityEditor.Rendering.LookDev
{
enum ShadowCompositionPass
{
WithSun,
WithoutSun,
ShadowMask
}
enum CompositionFinal
{
First,
Second
}
class RenderTextureCache : IDisposable
{
//RenderTextures are packed this way:
//0: ViewIndex.First, ShadowCompositionPass.WithSun
//1: ViewIndex.First, ShadowCompositionPass.WithoutSun
//2: ViewIndex.First, ShadowCompositionPass.ShadowMask
//3: CompositionFinal.First
//4: ViewIndex.Second, ShadowCompositionPass.WithSun
//5: ViewIndex.Second, ShadowCompositionPass.WithoutSun
//6: ViewIndex.Second, ShadowCompositionPass.ShadowMask
//7: CompositionFinal.Second
RenderTexture[] m_RTs = new RenderTexture[8];
public RenderTexture this[ViewIndex index, ShadowCompositionPass passIndex]
{
get => m_RTs[computeIndex(index, passIndex)];
set => m_RTs[computeIndex(index, passIndex)] = value;
}
public RenderTexture this[CompositionFinal index]
{
get => m_RTs[computeIndex(index)];
set => m_RTs[computeIndex(index)] = value;
}
int computeIndex(ViewIndex index, ShadowCompositionPass passIndex)
=> (int)index * 4 + (int)(passIndex);
int computeIndex(CompositionFinal index)
=> 3 + (int)(index) * 4;
void UpdateSize(int index, Rect rect, bool pixelPerfect, Camera renderingCamera, string renderDocName = "LookDevRT")
{
bool nullRect = rect.IsNullOrInverted();
GraphicsFormat format = SystemInfo.IsFormatSupported(GraphicsFormat.R16G16B16A16_SFloat, FormatUsage.Render)
? GraphicsFormat.R16G16B16A16_SFloat
: SystemInfo.GetGraphicsFormat(DefaultFormat.LDR);
if (m_RTs[index] != null && (nullRect || m_RTs[index].graphicsFormat != format))
{
m_RTs[index].Release();
UnityEngine.Object.DestroyImmediate(m_RTs[index]);
m_RTs[index] = null;
}
if (nullRect)
return;
int width = (int)rect.width;
int height = (int)rect.height;
if (m_RTs[index] == null)
{
m_RTs[index] = new RenderTexture(0, 0, 24, format);
m_RTs[index].name = renderDocName;
m_RTs[index].antiAliasing = 1;
m_RTs[index].hideFlags = HideFlags.HideAndDontSave;
}
if (m_RTs[index].width != width || m_RTs[index].height != height)
{
m_RTs[index].Release();
m_RTs[index].width = width;
m_RTs[index].height = height;
m_RTs[index].Create();
}
if (renderingCamera != null)
renderingCamera.targetTexture = m_RTs[index];
}
public void UpdateSize(Rect rect, ViewIndex index, bool pixelPerfect, Camera renderingCamera)
{
UpdateSize(computeIndex(index, ShadowCompositionPass.WithSun), rect, pixelPerfect, renderingCamera, $"LookDevRT-{index}-WithSun");
UpdateSize(computeIndex(index, ShadowCompositionPass.WithoutSun), rect, pixelPerfect, renderingCamera, $"LookDevRT-{index}-WithoutSun");
UpdateSize(computeIndex(index, ShadowCompositionPass.ShadowMask), rect, pixelPerfect, renderingCamera, $"LookDevRT-{index}-ShadowMask");
}
public void UpdateSize(Rect rect, CompositionFinal index, bool pixelPerfect, Camera renderingCamera)
=> UpdateSize(computeIndex(index), rect, pixelPerfect, renderingCamera, $"LookDevRT-Final-{index}");
bool m_Disposed = false;
public void Dispose()
{
if (m_Disposed)
return;
m_Disposed = true;
for (int index = 0; index < 8; ++index)
{
if (m_RTs[index] == null || m_RTs[index].Equals(null))
continue;
UnityEngine.Object.DestroyImmediate(m_RTs[index]);
m_RTs[index] = null;
}
}
}
class Compositer : IDisposable
{
public static readonly Color firstViewGizmoColor = new Color32(0, 154, 154, 255);
public static readonly Color secondViewGizmoColor = new Color32(255, 37, 4, 255);
static Material s_Material;
static Material material
{
get
{
if (s_Material == null || s_Material.Equals(null))
s_Material = new Material(Shader.Find("Hidden/LookDev/Compositor"));
return s_Material;
}
}
IDataProvider m_DataProvider;
IViewDisplayer m_Displayer;
Context m_Contexts;
RenderTextureCache m_RenderTextures = new RenderTextureCache();
Renderer m_Renderer = new Renderer();
RenderingData[] m_RenderDataCache;
bool m_pixelPerfect;
bool m_Disposed;
public bool pixelPerfect
{
get => m_pixelPerfect;
set => m_Renderer.pixelPerfect = m_pixelPerfect = value;
}
Color m_AmbientColor = new Color(0.0f, 0.0f, 0.0f, 0.0f);
bool m_RenderDocAcquisitionRequested;
public Compositer(
IViewDisplayer displayer,
Context contexts,
IDataProvider dataProvider,
StageCache stages)
{
m_DataProvider = dataProvider;
m_Displayer = displayer;
m_Contexts = contexts;
m_RenderDataCache = new RenderingData[2]
{
new RenderingData() { stage = stages[ViewIndex.First], updater = contexts.GetViewContent(ViewIndex.First).camera },
new RenderingData() { stage = stages[ViewIndex.Second], updater = contexts.GetViewContent(ViewIndex.Second).camera }
};
m_Displayer.OnRenderDocAcquisitionTriggered += RenderDocAcquisitionRequested;
m_Displayer.OnUpdateRequested += Render;
}
void RenderDocAcquisitionRequested()
=> m_RenderDocAcquisitionRequested = true;
void CleanUp()
{
for (int index = 0; index < 2; ++index)
{
m_RenderDataCache[index]?.Dispose();
m_RenderDataCache[index] = null;
}
m_RenderTextures.Dispose();
m_Displayer.OnRenderDocAcquisitionTriggered -= RenderDocAcquisitionRequested;
m_Displayer.OnUpdateRequested -= Render;
}
public void Dispose()
{
if (m_Disposed)
return;
m_Disposed = true;
CleanUp();
GC.SuppressFinalize(this);
}
~Compositer() => CleanUp();
public void Render()
{
//TODO: make integration EditorWindow agnostic!
if (UnityEditorInternal.RenderDoc.IsLoaded() && UnityEditorInternal.RenderDoc.IsSupported() && m_RenderDocAcquisitionRequested)
UnityEditorInternal.RenderDoc.BeginCaptureRenderDoc(m_Displayer as EditorWindow);
using (new UnityEngine.Rendering.VolumeIsolationScope(true))
{
switch (m_Contexts.layout.viewLayout)
{
case Layout.FullFirstView:
RenderSingleAndOutput(ViewIndex.First);
break;
case Layout.FullSecondView:
RenderSingleAndOutput(ViewIndex.Second);
break;
case Layout.HorizontalSplit:
case Layout.VerticalSplit:
RenderSingleAndOutput(ViewIndex.First);
RenderSingleAndOutput(ViewIndex.Second);
break;
case Layout.CustomSplit:
RenderCompositeAndOutput();
break;
}
}
//TODO: make integration EditorWindow agnostic!
if (UnityEditorInternal.RenderDoc.IsLoaded() && UnityEditorInternal.RenderDoc.IsSupported() && m_RenderDocAcquisitionRequested)
UnityEditorInternal.RenderDoc.EndCaptureRenderDoc(m_Displayer as EditorWindow);
//stating that RenderDoc do not need to acquire anymore should
//allows to gather both view and composition in render doc at once
m_RenderDocAcquisitionRequested = false;
}
void AcquireDataForView(ViewIndex index, Rect viewport)
{
var renderingData = m_RenderDataCache[(int)index];
renderingData.viewPort = viewport;
Environment env = m_Contexts.GetViewContent(index).environment;
m_RenderTextures.UpdateSize(renderingData.viewPort, index, m_Renderer.pixelPerfect, renderingData.stage.camera);
renderingData.output = m_RenderTextures[index, ShadowCompositionPass.WithSun];
m_Renderer.Acquire(renderingData, RenderingPass.First);
//get shadowmask betwen first and last pass to still be isolated
RenderTexture tmp = m_RenderTextures[index, ShadowCompositionPass.ShadowMask];
env?.UpdateSunPosition(renderingData.stage.sunLight);
renderingData.stage.sunLight.intensity = 1f;
m_DataProvider.GetShadowMask(ref tmp, renderingData.stage.runtimeInterface);
renderingData.stage.sunLight.intensity = 0f;
m_RenderTextures[index, ShadowCompositionPass.ShadowMask] = tmp;
if (env != null)
m_DataProvider.UpdateSky(renderingData.stage.camera, env.shadowSky, renderingData.stage.runtimeInterface);
renderingData.output = m_RenderTextures[index, ShadowCompositionPass.WithoutSun];
m_Renderer.Acquire(renderingData, RenderingPass.Last);
if (env != null)
m_DataProvider.UpdateSky(renderingData.stage.camera, env.sky, renderingData.stage.runtimeInterface);
}
void RenderSingleAndOutput(ViewIndex index)
{
Rect viewport = m_Displayer.GetRect((ViewCompositionIndex)index);
AcquireDataForView(index, viewport);
Compositing(viewport, (int)index, (CompositionFinal)index);
m_Displayer.SetTexture((ViewCompositionIndex)index, m_RenderTextures[(CompositionFinal)index]);
}
void RenderCompositeAndOutput()
{
Rect viewport = m_Displayer.GetRect(ViewCompositionIndex.Composite);
AcquireDataForView(ViewIndex.First, viewport);
AcquireDataForView(ViewIndex.Second, viewport);
Compositing(viewport, 2 /*split*/, CompositionFinal.First);
m_Displayer.SetTexture(ViewCompositionIndex.Composite, m_RenderTextures[CompositionFinal.First]);
}
void Compositing(Rect rect, int pass, CompositionFinal finalBufferIndex)
{
if (rect.IsNullOrInverted()
|| (m_Contexts.layout.viewLayout != Layout.FullSecondView
&& (m_RenderTextures[ViewIndex.First, ShadowCompositionPass.WithSun] == null
|| m_RenderTextures[ViewIndex.First, ShadowCompositionPass.WithoutSun] == null
|| m_RenderTextures[ViewIndex.First, ShadowCompositionPass.ShadowMask] == null))
|| (m_Contexts.layout.viewLayout != Layout.FullFirstView
&& (m_RenderTextures[ViewIndex.Second, ShadowCompositionPass.WithSun] == null
|| m_RenderTextures[ViewIndex.Second, ShadowCompositionPass.WithoutSun] == null
|| m_RenderTextures[ViewIndex.Second, ShadowCompositionPass.ShadowMask] == null)))
{
m_RenderTextures[finalBufferIndex] = null;
return;
}
m_RenderTextures.UpdateSize(rect, finalBufferIndex, m_pixelPerfect, null);
ComparisonGizmoState gizmo = m_Contexts.layout.gizmoState;
Vector4 gizmoPosition = new Vector4(gizmo.center.x, gizmo.center.y, 0.0f, 0.0f);
Vector4 gizmoZoneCenter = new Vector4(gizmo.point2.x, gizmo.point2.y, 0.0f, 0.0f);
Vector4 gizmoThickness = new Vector4(ComparisonGizmoState.thickness, ComparisonGizmoState.thicknessSelected, 0.0f, 0.0f);
Vector4 gizmoCircleRadius = new Vector4(ComparisonGizmoState.circleRadius, ComparisonGizmoState.circleRadiusSelected, 0.0f, 0.0f);
Environment env0 = m_Contexts.GetViewContent(ViewIndex.First).environment;
Environment env1 = m_Contexts.GetViewContent(ViewIndex.Second).environment;
float exposureValue0 = env0?.sky.exposure ?? 0f;
float exposureValue1 = env1?.sky.exposure ?? 0f;
float dualViewBlendFactor = gizmo.blendFactor;
float isCurrentlyLeftEditting = m_Contexts.layout.lastFocusedView == ViewIndex.First ? 1f : -1f;
float dragAndDropContext = 0f; //1f left, -1f right, 0f neither
float toneMapEnabled = -1f; //1f true, -1f false
float shadowMultiplier0 = env0?.shadowIntensity ?? 0f;
float shadowMultiplier1 = env1?.shadowIntensity ?? 0f;
Color shadowColor0 = env0?.shadow.color ?? Color.white;
Color shadowColor1 = env1?.shadow.color ?? Color.white;
//TODO: handle shadow not at compositing step but in rendering
Texture texWithSun0 = m_RenderTextures[ViewIndex.First, ShadowCompositionPass.WithSun];
Texture texWithoutSun0 = m_RenderTextures[ViewIndex.First, ShadowCompositionPass.WithoutSun];
Texture texShadowsMask0 = m_RenderTextures[ViewIndex.First, ShadowCompositionPass.ShadowMask];
Texture texWithSun1 = m_RenderTextures[ViewIndex.Second, ShadowCompositionPass.WithSun];
Texture texWithoutSun1 = m_RenderTextures[ViewIndex.Second, ShadowCompositionPass.WithoutSun];
Texture texShadowsMask1 = m_RenderTextures[ViewIndex.Second, ShadowCompositionPass.ShadowMask];
Vector4 compositingParams = new Vector4(dualViewBlendFactor, exposureValue0, exposureValue1, isCurrentlyLeftEditting);
Vector4 compositingParams2 = new Vector4(dragAndDropContext, toneMapEnabled, shadowMultiplier0, shadowMultiplier1);
// Those could be tweakable for the neutral tonemapper, but in the case of the LookDev we don't need that
const float k_BlackIn = 0.02f;
const float k_WhiteIn = 10.0f;
const float k_BlackOut = 0.0f;
const float k_WhiteOut = 10.0f;
const float k_WhiteLevel = 5.3f;
const float k_WhiteClip = 10.0f;
const float k_DialUnits = 20.0f;
const float k_HalfDialUnits = k_DialUnits * 0.5f;
const float k_GizmoRenderMode = 4f; //display all
// converting from artist dial units to easy shader-lerps (0-1)
//TODO: to compute one time only
Vector4 tonemapCoeff1 = new Vector4((k_BlackIn * k_DialUnits) + 1.0f, (k_BlackOut * k_HalfDialUnits) + 1.0f, (k_WhiteIn / k_DialUnits), (1.0f - (k_WhiteOut / k_DialUnits)));
Vector4 tonemapCoeff2 = new Vector4(0.0f, 0.0f, k_WhiteLevel, k_WhiteClip / k_HalfDialUnits);
const float k_ReferenceScale = 1080.0f;
Vector4 screenRatio = new Vector4(rect.width / k_ReferenceScale, rect.height / k_ReferenceScale, rect.width, rect.height);
RenderTexture oldActive = RenderTexture.active;
RenderTexture.active = m_RenderTextures[finalBufferIndex];
material.SetTexture("_Tex0WithSun", texWithSun0);
material.SetTexture("_Tex0WithoutSun", texWithoutSun0);
material.SetTexture("_Tex0Shadows", texShadowsMask0);
material.SetColor("_ShadowColor0", shadowColor0);
material.SetTexture("_Tex1WithSun", texWithSun1);
material.SetTexture("_Tex1WithoutSun", texWithoutSun1);
material.SetTexture("_Tex1Shadows", texShadowsMask1);
material.SetColor("_ShadowColor1", shadowColor1);
material.SetVector("_CompositingParams", compositingParams);
material.SetVector("_CompositingParams2", compositingParams2);
material.SetColor("_FirstViewColor", firstViewGizmoColor);
material.SetColor("_SecondViewColor", secondViewGizmoColor);
material.SetVector("_GizmoPosition", gizmoPosition);
material.SetVector("_GizmoZoneCenter", gizmoZoneCenter);
material.SetVector("_GizmoSplitPlane", gizmo.plane);
material.SetVector("_GizmoSplitPlaneOrtho", gizmo.planeOrtho);
material.SetFloat("_GizmoLength", gizmo.length);
material.SetVector("_GizmoThickness", gizmoThickness);
material.SetVector("_GizmoCircleRadius", gizmoCircleRadius);
material.SetFloat("_BlendFactorCircleRadius", ComparisonGizmoState.blendFactorCircleRadius);
material.SetFloat("_GetBlendFactorMaxGizmoDistance", gizmo.blendFactorMaxGizmoDistance);
material.SetFloat("_GizmoRenderMode", k_GizmoRenderMode);
material.SetVector("_ScreenRatio", screenRatio);
material.SetVector("_ToneMapCoeffs1", tonemapCoeff1);
material.SetVector("_ToneMapCoeffs2", tonemapCoeff2);
material.SetPass(pass);
Renderer.DrawFullScreenQuad(new Rect(0, 0, rect.width, rect.height));
RenderTexture.active = oldActive;
}
public ViewIndex GetViewFromComposition(Vector2 localCoordinate)
{
Rect compositionRect = m_Displayer.GetRect(ViewCompositionIndex.Composite);
Vector2 normalizedLocalCoordinate = ComparisonGizmoController.GetNormalizedCoordinates(localCoordinate, compositionRect);
switch (m_Contexts.layout.viewLayout)
{
case Layout.CustomSplit:
return Vector3.Dot(new Vector3(normalizedLocalCoordinate.x, normalizedLocalCoordinate.y, 1), m_Contexts.layout.gizmoState.plane) >= 0
? ViewIndex.First
: ViewIndex.Second;
default:
throw new Exception("GetViewFromComposition call when not inside a Composition");
}
}
}
}