/// <summary> /// Computes the rule used for toggling renderer shadow casting. /// </summary> /// <param name="profile">Profile used for size and distance thresholds needed for the rule.</param> /// <param name="viewportSize">Diagonal viewport size of the renderer.</param> /// <param name="distanceToCamera">Distance from renderer to camera.</param> /// <param name="shadowMapTexelSize">Shadow map bounding box size in texels.</param> /// <returns>True if renderer should have shadow, false otherwise.</returns> internal static bool TestRendererShadowRule(CullingControllerProfile profile, float viewportSize, float distanceToCamera, float shadowMapTexelSize) { bool shouldHaveShadow = distanceToCamera < profile.shadowDistanceThreshold; shouldHaveShadow |= viewportSize > profile.shadowRendererSizeThreshold; shouldHaveShadow &= shadowMapTexelSize > profile.shadowMapProjectionSizeThreshold; return(shouldHaveShadow); }
public float shadowMapProjectionSizeThreshold; // /// <summary> /// Performs a linear interpolation between the values of two CullingControllerProfiles. /// Used for controlling the settings panel slider. /// </summary> /// <param name="p1">Starting profile</param> /// <param name="p2">Ending profile</param> /// <param name="t">Time value for the linear interpolation.</param> /// <returns>A new CullingControllerProfile with the interpolated values.</returns> public static CullingControllerProfile Lerp(CullingControllerProfile p1, CullingControllerProfile p2, float t) { return(new CullingControllerProfile { visibleDistanceThreshold = Mathf.Lerp(p1.visibleDistanceThreshold, p2.visibleDistanceThreshold, t), shadowDistanceThreshold = Mathf.Lerp(p1.shadowDistanceThreshold, p2.shadowDistanceThreshold, t), emissiveSizeThreshold = Mathf.Lerp(p1.emissiveSizeThreshold, p2.emissiveSizeThreshold, t), opaqueSizeThreshold = Mathf.Lerp(p1.opaqueSizeThreshold, p2.opaqueSizeThreshold, t), shadowRendererSizeThreshold = Mathf.Lerp(p1.shadowRendererSizeThreshold, p2.shadowRendererSizeThreshold, t), shadowMapProjectionSizeThreshold = Mathf.Lerp(p1.shadowMapProjectionSizeThreshold, p2.shadowMapProjectionSizeThreshold, t) }); }
/// <summary> /// Computes the rule used for toggling renderers visibility. /// </summary> /// <param name="profile">Profile used for size and distance thresholds needed for the rule.</param> /// <param name="viewportSize">Diagonal viewport size of the renderer.</param> /// <param name="distanceToCamera">Distance to camera of the renderer.</param> /// <param name="boundsContainsCamera">Renderer bounds contains camera?</param> /// <param name="isOpaque">Renderer is opaque?</param> /// <param name="isEmissive">Renderer is emissive?</param> /// <returns>True if renderer should be visible, false if otherwise.</returns> internal static bool TestRendererVisibleRule(CullingControllerProfile profile, float viewportSize, float distanceToCamera, bool boundsContainsCamera, bool isOpaque, bool isEmissive) { bool shouldBeVisible = distanceToCamera < profile.visibleDistanceThreshold || boundsContainsCamera; if (isEmissive) { shouldBeVisible |= viewportSize > profile.emissiveSizeThreshold; } if (isOpaque) { shouldBeVisible |= viewportSize > profile.opaqueSizeThreshold; } return(shouldBeVisible); }
/// <summary> /// Process all sceneObject renderers with the parameters set by the given profile. /// </summary> /// <param name="profile">any CullingControllerProfile</param> /// <returns>IEnumerator to be yielded.</returns> internal IEnumerator ProcessProfile(CullingControllerProfile profile) { Renderer[] renderers; // If profile matches the skinned renderer profile in settings, // the skinned renderers are going to be used. if (profile == settings.rendererProfile) { renderers = objectsTracker.GetRenderers(); } else { renderers = objectsTracker.GetSkinnedRenderers(); } for (var i = 0; i < renderers.Length; i++) { if (timeBudgetCount > settings.maxTimeBudget) { timeBudgetCount = 0; yield return(null); } Renderer r = renderers[i]; if (r == null) { continue; } bool rendererIsInIgnoreLayer = ((1 << r.gameObject.layer) & settings.ignoredLayersMask) != 0; if (rendererIsInIgnoreLayer) { SetCullingForRenderer(r, true, true); continue; } float startTime = Time.realtimeSinceStartup; //NOTE(Brian): Need to retrieve positions every frame to take into account // world repositioning. Vector3 playerPosition = CommonScriptableObjects.playerUnityPosition; Bounds bounds = r.GetSafeBounds(); Vector3 boundingPoint = bounds.ClosestPoint(playerPosition); float distance = Vector3.Distance(playerPosition, boundingPoint); bool boundsContainsPlayer = bounds.Contains(playerPosition); float boundsSize = bounds.size.magnitude; float viewportSize = (boundsSize / distance) * Mathf.Rad2Deg; bool isEmissive = IsEmissive(r); bool isOpaque = IsOpaque(r); float shadowTexelSize = ComputeShadowMapTexelSize(boundsSize, urpAsset.shadowDistance, urpAsset.mainLightShadowmapResolution); bool shouldBeVisible = TestRendererVisibleRule(profile, viewportSize, distance, boundsContainsPlayer, isOpaque, isEmissive); bool shouldHaveShadow = TestRendererShadowRule(profile, viewportSize, distance, shadowTexelSize); if (r is SkinnedMeshRenderer skr) { Material mat = skr.sharedMaterial; bool isAvatarRenderer = false; if (mat != null && mat.shader != null) { isAvatarRenderer = mat.shader.name == "DCL/Toon Shader"; } if (isAvatarRenderer) { shouldHaveShadow &= TestAvatarShadowRule(profile, distance); } skr.updateWhenOffscreen = TestSkinnedRendererOffscreenRule(settings, distance); } if (OnDataReport != null) { if (!shouldBeVisible && !hiddenRenderers.Contains(r)) { hiddenRenderers.Add(r); } if (shouldBeVisible && !shouldHaveShadow && !shadowlessRenderers.Contains(r)) { shadowlessRenderers.Add(r); } } SetCullingForRenderer(r, shouldBeVisible, shouldHaveShadow); #if UNITY_EDITOR DrawDebugGizmos(shouldBeVisible, bounds, boundingPoint); #endif timeBudgetCount += Time.realtimeSinceStartup - startTime; } }
internal static bool TestAvatarShadowRule(CullingControllerProfile profile, float avatarDistance) { return(avatarDistance < profile.maxShadowDistanceForAvatars); }