Fix : 쉐도우 버그 수정
This commit is contained in:
parent
c70b24fe8c
commit
2a1775ff34
@ -1109,10 +1109,20 @@ namespace NiloToon.NiloToonURP
|
||||
|
||||
if (regenerateSmoothedNormalInUV8)
|
||||
{
|
||||
NiloBakeSmoothNormalTSToMeshUv8.GenGOSmoothedNormalToUV8(gameObject);
|
||||
NiloBakeSmoothNormalTSToMeshUv8.GenGOSmoothedNormalToUV8(gameObject);
|
||||
}
|
||||
|
||||
|
||||
AutoFillInMissingProperties();
|
||||
|
||||
// Streamingle: 이미 등록된 renderer에도 updateWhenOffscreen 적용 (씬에 미리 있던 캐릭터 대응).
|
||||
// RefillAllRenderers는 새 등록 때만 호출되므로 OnEnable에서 한 번 더 강제.
|
||||
for (int i = 0; i < allRenderers.Count; i++)
|
||||
{
|
||||
if (allRenderers[i] is SkinnedMeshRenderer existingSmr && !existingSmr.updateWhenOffscreen)
|
||||
{
|
||||
existingSmr.updateWhenOffscreen = true;
|
||||
}
|
||||
}
|
||||
|
||||
// To support VRMBlendShapeProxy, NiloToon now generates material instances on OnEnable(), which is before VRMBlendShapeProxy's Start()
|
||||
// Note:
|
||||
@ -1537,7 +1547,15 @@ namespace NiloToon.NiloToonURP
|
||||
|
||||
// we don't want to add particle/vfx/trail....renderers
|
||||
if(!(renderer is MeshRenderer or SkinnedMeshRenderer)) continue;
|
||||
|
||||
|
||||
// Streamingle: Pass.cs의 manual DrawRenderer로 cullResults 우회 시,
|
||||
// SkinnedMeshRenderer가 화면 밖이면 Unity가 본 매트릭스 갱신을 skip하여 stale pose가 그려질 수 있음.
|
||||
// updateWhenOffscreen=true 강제. (localBounds는 GetCharacterBoundCenter에 영향 주므로 건드리지 않음)
|
||||
if (renderer is SkinnedMeshRenderer smr && !smr.updateWhenOffscreen)
|
||||
{
|
||||
smr.updateWhenOffscreen = true;
|
||||
}
|
||||
|
||||
var NiloToonPerCharacterRenderControllerFound = renderer.transform.GetComponentInParent<NiloToonPerCharacterRenderController>();
|
||||
if(NiloToonPerCharacterRenderControllerFound)
|
||||
{
|
||||
|
||||
@ -174,6 +174,31 @@ namespace NiloToon.NiloToonURP
|
||||
List<NiloToonPerCharacterRenderController> validCharList = new List<NiloToonPerCharacterRenderController>();
|
||||
List<NiloToonPerCharacterRenderController> finalValidCharList = new List<NiloToonPerCharacterRenderController>();
|
||||
|
||||
// Streamingle: shader → "NiloToonSelfShadowCaster" pass index 캐시.
|
||||
// Unity 6 RG path는 main camera cullResults 만 쓰므로 카메라가 캐릭터 안 보면 shadow map 비어 그림자 사라짐.
|
||||
// ExecutePass에서 manual DrawRenderer로 cullResults 우회. shader 별 pass index 조회는 비싸 캐시 필요.
|
||||
static readonly Dictionary<Shader, int> s_shadowCasterPassIndexCache = new Dictionary<Shader, int>();
|
||||
static readonly ShaderTagId s_lightModeTagId = new ShaderTagId("LightMode");
|
||||
static readonly ShaderTagId s_shadowCasterTagId = new ShaderTagId("NiloToonSelfShadowCaster");
|
||||
|
||||
static int GetShadowCasterPassIndex(Shader shader)
|
||||
{
|
||||
if (shader == null) return -1;
|
||||
if (s_shadowCasterPassIndexCache.TryGetValue(shader, out int cached)) return cached;
|
||||
int found = -1;
|
||||
int passCount = shader.passCount;
|
||||
for (int i = 0; i < passCount; i++)
|
||||
{
|
||||
if (shader.FindPassTagValue(i, s_lightModeTagId) == s_shadowCasterTagId)
|
||||
{
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
s_shadowCasterPassIndexCache[shader] = found;
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
// Constructor(will not call on every frame)
|
||||
public NiloToonCharSelfShadowMapRTPass(NiloToonRendererFeatureSettings allSettings)
|
||||
@ -448,27 +473,15 @@ namespace NiloToon.NiloToonURP
|
||||
// https://docs.microsoft.com/en-us/windows/win32/dxtecharts/common-techniques-to-improve-shadow-depth-maps
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeometryUtility.CalculateFrustumPlanes(camera, cameraPlanes);
|
||||
|
||||
validCharList.Clear();
|
||||
|
||||
// [1] filter list
|
||||
// [1] Streamingle: 메인 카메라 frustum cull 제거. (controller bound 기반 필터)
|
||||
// 캐릭터가 메인 카메라 frustum 밖이어도 ortho box / keyword 가 정상 동작해야 함.
|
||||
// 실제 cullResults 우회는 ExecutePass의 manual DrawRenderer 가 담당.
|
||||
foreach (var targetChar in NiloToonAllInOneRendererFeature.characterList)
|
||||
{
|
||||
// if target is not valid, skip it
|
||||
if (targetChar == null) continue;
|
||||
if (!targetChar.isActiveAndEnabled) continue; // character GameObject not enabled(not rendering) but in list
|
||||
|
||||
// if character bounding sphere is completely not visible in game camera frustum, skip it
|
||||
var boundRadius = targetChar.GetCharacterBoundRadius();
|
||||
var centerPosWS = targetChar.GetCharacterBoundCenter();
|
||||
// TODO: this section is not correct, which may incorrectly cull effective shadow caster that is OUTSIDE of main camera frustum
|
||||
if (!GeometryUtility.TestPlanesAABB(cameraPlanes, new Bounds(centerPosWS, Vector3.one * boundRadius)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// it is a valid visible char, add to list
|
||||
if (!targetChar.isActiveAndEnabled) continue;
|
||||
validCharList.Add(targetChar);
|
||||
}
|
||||
|
||||
@ -602,43 +615,7 @@ namespace NiloToon.NiloToonURP
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set culling for shadow camera -> do culling
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
camera.TryGetCullingParameters(out var cullingParameters);
|
||||
|
||||
// update culling matrix
|
||||
cullingParameters.cullingMatrix = shadowCamProjectionMatrix * shadowCamViewMatrix;
|
||||
|
||||
// update culling planes
|
||||
GeometryUtility.CalculateFrustumPlanes(cullingParameters.cullingMatrix, cameraPlanes);
|
||||
for (int i = 0; i < cameraPlanes.Length; i++)
|
||||
{
|
||||
cullingParameters.SetCullingPlane(i, cameraPlanes[i]);
|
||||
}
|
||||
|
||||
CullingResults cullResults;
|
||||
|
||||
bool terrainExist = false;
|
||||
if (settings.terrainCrashSafeGuard)
|
||||
{
|
||||
terrainExist = Terrain.activeTerrains.Length != 0;
|
||||
}
|
||||
if (settings.perfectCullingForShadowCasters && !terrainExist)
|
||||
{
|
||||
// use the above new cullResults in DrawRenderers() below,
|
||||
// so even a renderer is not visible in the perspective of main camera,
|
||||
// it can still render correctly in shadow camera's perspective due to this new culling
|
||||
|
||||
// (2021-07-14) unity will crash if code running this line and terrain exist in scene
|
||||
// (2024-03-21) enable this will make VLB's SRP batcher mode flicker randomly, not sure why, should we do something to revert this culling line?
|
||||
cullResults = context.Cull(ref cullingParameters); // original working code, but will crash if terrain exist
|
||||
}
|
||||
else
|
||||
{
|
||||
// (2021-07-14) a special temp fix to avoid terrain crashing unity, but will make shadow culling not always correctly if shadow caster is not existing on screen
|
||||
cullResults = renderingData.cullResults;
|
||||
}
|
||||
// Streamingle: cullResults / custom culling 코드 제거. manual DrawRenderer가 cullResults에 의존하지 않으므로 불필요.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Set uniform (before context.DrawRenderers)
|
||||
@ -708,12 +685,12 @@ namespace NiloToon.NiloToonURP
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// draw all char renderer using SRP batching (must set all uniforms and executed before draw!)
|
||||
// Streamingle: cullResults 의존성 완전 제거. context.DrawRenderers + custom culling 모두 제거.
|
||||
// characterList의 모든 NiloToon 캐릭터를 manual draw로 그려 카메라 frustum 무관하게 shadow map 채움.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ShaderTagId shaderTagId = new ShaderTagId("NiloToonSelfShadowCaster");
|
||||
var drawSetting = CreateDrawingSettings(shaderTagId, ref renderingData, SortingCriteria.CommonOpaque);
|
||||
var filterSetting = new FilteringSettings(RenderQueueRange.opaque);
|
||||
context.DrawRenderers(cullResults, ref drawSetting, ref filterSetting); // using custom cullResults from shadow camera's perspective, instead of main camera's cull result
|
||||
DrawNiloToonCharsManuallyLegacy(cmd);
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
cmd.Clear();
|
||||
|
||||
// Note: Since we are providing our own _NiloToonSelfShadowWorldToClip to shader for VP transform,
|
||||
// this section is not needed anymore, it will trigger a bug in multi pass mode XR
|
||||
@ -812,8 +789,7 @@ namespace NiloToon.NiloToonURP
|
||||
// copy and edit of https://docs.unity3d.com/6000.0/Documentation/Manual/urp/render-graph-draw-objects-in-a-pass.html
|
||||
private class PassData
|
||||
{
|
||||
// Create a field to store the list of objects to draw
|
||||
public RendererListHandle rendererListHandle;
|
||||
// Streamingle: RendererListHandle 제거. manual DrawRenderer로 대체됨.
|
||||
public bool shouldRender;
|
||||
public Matrix4x4 _NiloToonSelfShadowWorldToClip;
|
||||
public Vector4 _NiloToonSelfShadowParam;
|
||||
@ -840,21 +816,10 @@ namespace NiloToon.NiloToonURP
|
||||
UniversalCameraData cameraData = frameContext.Get<UniversalCameraData>();
|
||||
UniversalRenderingData renderingData = frameContext.Get<UniversalRenderingData>();
|
||||
UniversalLightData lightData = frameContext.Get<UniversalLightData>();
|
||||
|
||||
SortingCriteria sortFlags = SortingCriteria.CommonOpaque; //cameraData.defaultOpaqueSortFlags;
|
||||
RenderQueueRange renderQueueRange = RenderQueueRange.opaque;
|
||||
FilteringSettings filterSettings = new FilteringSettings(renderQueueRange, ~0);
|
||||
|
||||
// Redraw only objects that have their LightMode tag set to "NiloToonSelfShadowCaster"
|
||||
ShaderTagId shadersToOverride = new ShaderTagId("NiloToonSelfShadowCaster");
|
||||
|
||||
// Create drawing settings
|
||||
DrawingSettings drawSettings = RenderingUtils.CreateDrawingSettings(shadersToOverride, renderingData, cameraData, lightData, sortFlags);
|
||||
|
||||
// Create the list of objects to draw
|
||||
var rendererListParameters = new RendererListParams(renderingData.cullResults, drawSettings, filterSettings);
|
||||
|
||||
|
||||
// Streamingle: RendererList 기반 그리기 제거. ExecutePass의 manual DrawRenderer가
|
||||
// characterList를 직접 그리므로 cullResults에 의존하는 RendererList는 불필요 + double-draw 방지.
|
||||
// RendererList CPU 컬링 비용도 절약.
|
||||
|
||||
// create RT (temp)
|
||||
// Create texture properties that match the screen size
|
||||
@ -871,21 +836,17 @@ namespace NiloToon.NiloToonURP
|
||||
{
|
||||
shouldRender = true;
|
||||
}
|
||||
|
||||
// Convert the list to a list handle that the render graph system can use
|
||||
passData.rendererListHandle = renderGraph.CreateRendererList(rendererListParameters);
|
||||
|
||||
passData.shouldRender = shouldRender;
|
||||
|
||||
|
||||
RenderTextureDescriptor renderTextureDescriptor = new RenderTextureDescriptor(shadowMapSize, shadowMapSize, RenderTextureFormat.Shadowmap, 16);
|
||||
|
||||
// Create a temporary texture
|
||||
TextureHandle shadowMapRT = UniversalRenderer.CreateRenderGraphTexture(renderGraph, renderTextureDescriptor, "_NiloToonCharSelfShadowMapRT", true);
|
||||
|
||||
|
||||
// Set the render target as the color and depth textures of the active camera texture
|
||||
UniversalResourceData resourceData = frameContext.Get<UniversalResourceData>();
|
||||
|
||||
builder.UseRendererList(passData.rendererListHandle);
|
||||
|
||||
|
||||
//builder.SetRenderAttachment(resourceData.activeColorTexture, 0);
|
||||
builder.SetRenderAttachmentDepth(shadowMapRT, AccessFlags.Write);
|
||||
|
||||
@ -1036,29 +997,15 @@ namespace NiloToon.NiloToonURP
|
||||
// https://docs.microsoft.com/en-us/windows/win32/dxtecharts/common-techniques-to-improve-shadow-depth-maps
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeometryUtility.CalculateFrustumPlanes(camera, cameraPlanes);
|
||||
|
||||
validCharList.Clear();
|
||||
|
||||
// [1] filter list
|
||||
// [1] Streamingle: 메인 카메라 frustum cull 제거. (controller bound 기반 필터)
|
||||
// 캐릭터가 메인 카메라 frustum 밖이어도 ortho box / keyword 가 정상 동작해야 함.
|
||||
// 실제 cullResults 우회는 ExecutePass의 manual DrawRenderer 가 담당.
|
||||
foreach (var targetChar in NiloToonAllInOneRendererFeature.characterList)
|
||||
{
|
||||
// if target is not valid, skip it
|
||||
if (targetChar == null) continue;
|
||||
if (!targetChar.isActiveAndEnabled)
|
||||
continue; // character GameObject not enabled(not rendering) but in list
|
||||
|
||||
// if character bounding sphere is completely not visible in game camera frustum, skip it
|
||||
var boundRadius = targetChar.GetCharacterBoundRadius();
|
||||
var centerPosWS = targetChar.GetCharacterBoundCenter();
|
||||
// TODO: this section is not correct, which may incorrectly cull effective shadow caster that is OUTSIDE of main camera frustum
|
||||
if (!GeometryUtility.TestPlanesAABB(cameraPlanes,
|
||||
new Bounds(centerPosWS, Vector3.one * boundRadius)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// it is a valid visible char, add to list
|
||||
if (!targetChar.isActiveAndEnabled) continue;
|
||||
validCharList.Add(targetChar);
|
||||
}
|
||||
|
||||
@ -1328,10 +1275,67 @@ namespace NiloToon.NiloToonURP
|
||||
cmd.SetGlobalVector("_NiloToonSelfShadowSoftShadowParam", data._NiloToonSelfShadowSoftShadowParam);
|
||||
|
||||
cmd.SetKeyword(GlobalKeyword.Create(_NILOTOON_RECEIVE_SELF_SHADOW_Keyword), true);
|
||||
|
||||
// Draw the objects in the list
|
||||
cmd.DrawRendererList(data.rendererListHandle);
|
||||
|
||||
// Streamingle: cullResults 의존성 완전 제거. manual draw만 사용.
|
||||
// characterList의 모든 NiloToon 캐릭터를 직접 그려 카메라 frustum 무관하게 shadow map 채움.
|
||||
DrawNiloToonCharsManually(cmd);
|
||||
}
|
||||
|
||||
static void DrawNiloToonCharsManually(RasterCommandBuffer cmd)
|
||||
{
|
||||
var charList = NiloToonAllInOneRendererFeature.characterList;
|
||||
if (charList == null) return;
|
||||
for (int c = 0; c < charList.Count; c++)
|
||||
{
|
||||
var character = charList[c];
|
||||
if (character == null || !character.isActiveAndEnabled) continue;
|
||||
var renderers = character.allRenderers;
|
||||
if (renderers == null) continue;
|
||||
for (int r = 0; r < renderers.Count; r++)
|
||||
{
|
||||
var renderer = renderers[r];
|
||||
if (renderer == null || !renderer.enabled || !renderer.gameObject.activeInHierarchy) continue;
|
||||
var sharedMats = renderer.sharedMaterials;
|
||||
if (sharedMats == null) continue;
|
||||
for (int subIdx = 0; subIdx < sharedMats.Length; subIdx++)
|
||||
{
|
||||
var mat = sharedMats[subIdx];
|
||||
if (mat == null) continue;
|
||||
int passIdx = GetShadowCasterPassIndex(mat.shader);
|
||||
if (passIdx < 0) continue;
|
||||
cmd.DrawRenderer(renderer, mat, subIdx, passIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void DrawNiloToonCharsManuallyLegacy(CommandBuffer cmd)
|
||||
{
|
||||
var charList = NiloToonAllInOneRendererFeature.characterList;
|
||||
if (charList == null) return;
|
||||
for (int c = 0; c < charList.Count; c++)
|
||||
{
|
||||
var character = charList[c];
|
||||
if (character == null || !character.isActiveAndEnabled) continue;
|
||||
var renderers = character.allRenderers;
|
||||
if (renderers == null) continue;
|
||||
for (int r = 0; r < renderers.Count; r++)
|
||||
{
|
||||
var renderer = renderers[r];
|
||||
if (renderer == null || !renderer.enabled || !renderer.gameObject.activeInHierarchy) continue;
|
||||
var sharedMats = renderer.sharedMaterials;
|
||||
if (sharedMats == null) continue;
|
||||
for (int subIdx = 0; subIdx < sharedMats.Length; subIdx++)
|
||||
{
|
||||
var mat = sharedMats[subIdx];
|
||||
if (mat == null) continue;
|
||||
int passIdx = GetShadowCasterPassIndex(mat.shader);
|
||||
if (passIdx < 0) continue;
|
||||
cmd.DrawRenderer(renderer, mat, subIdx, passIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user