Sweep over 48 files (Editor/ excluded): remove comments that restate the code, condense class summaries, fix three stale doc statements (HsvColorPicker alpha bar, PaintHud layoutPrefab, MasterVolume FallbackDefault). Inline two single-use wrappers (IsPointerOverUi, BuildModes), drop an unused using, replace a magic literal with the existing ParallaxBase constant, and convert ~10 UnityEngine.Object null checks to the implicit-bool convention. No serialized fields, signatures, RPC/NetworkVariable names, defaults, or #if blocks touched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
161 lines
5.6 KiB
C#
161 lines
5.6 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
|
|
/// <summary>
|
|
/// Builds the environment reflection from the current Skybox in memory (renders the sky into a cubemap
|
|
/// assigned as the Custom reflection), so smooth/metallic materials reflect the sky WITHOUT a baked
|
|
/// LightingData.asset. Runs in Edit and Play mode ([ExecuteAlways]); drop it on one object per scene —
|
|
/// also works for runtime-loaded / procedural scenes.
|
|
///
|
|
/// Why a rendered cubemap and not <see cref="DynamicGI.UpdateEnvironment"/>: in this project
|
|
/// UpdateEnvironment does NOT produce a valid skybox reflection probe (a mirror stays black), so
|
|
/// <see cref="RenderSettings.reflectionIntensity"/> had nothing to scale. Rendering the sky into a
|
|
/// Custom reflection cubemap gives a real reflection that intensity can actually drive.
|
|
///
|
|
/// The skybox AMBIENT probe still comes from UpdateEnvironment — but it only convolves a non-zero probe
|
|
/// once the sky has actually been rendered this session. Straight after a domain reload / scene load /
|
|
/// play-start the sky hasn't rendered yet, so the probe is ZERO and the Environment intensity multiplier
|
|
/// has nothing to scale ("doesn't take effect" until a manual re-enable). Fix: one synchronous
|
|
/// full-screen sky render "warms" the sky right before UpdateEnvironment — deterministic, no waiting on
|
|
/// renders. (RenderToCubemap does NOT warm the ambient path; a normal Camera.Render does.)
|
|
/// </summary>
|
|
[ExecuteAlways]
|
|
[DisallowMultipleComponent]
|
|
public class SkyboxEnvironmentUpdater : MonoBehaviour
|
|
{
|
|
[Range(0f, 4f)]
|
|
public float environmentLightingIntensity = 1;
|
|
|
|
[Header("Reflections")]
|
|
|
|
[Tooltip("Resolution of the generated sky reflection cubemap (power of two).")]
|
|
public int reflectionResolution = 128;
|
|
|
|
[Tooltip("How strongly the sky reflection tints reflective/metallic surfaces. 1 = neutral; the Lighting window slider caps at 1, but higher values (via this field) over-drive the reflection for a glossier metal look. Only applied while Force Skybox Reflections is on.")]
|
|
[Range(0f, 4f)]
|
|
public float reflectionIntensity = 1f;
|
|
|
|
[Tooltip("Optional: render THIS sky material into the reflection cubemap instead of the scene's global Skybox. Leave empty to use RenderSettings.skybox. Only affects the reflection — the visible scene skybox is unchanged.")]
|
|
public Material reflectionSkyOverride;
|
|
|
|
[System.NonSerialized] Cubemap _reflectionCube;
|
|
|
|
void OnDisable()
|
|
{
|
|
#if UNITY_EDITOR
|
|
UnityEditor.EditorApplication.delayCall -= Apply;
|
|
#endif
|
|
if (!_reflectionCube)
|
|
return;
|
|
|
|
if (RenderSettings.customReflectionTexture == _reflectionCube)
|
|
RenderSettings.customReflectionTexture = null;
|
|
|
|
DestroyImmediate(_reflectionCube);
|
|
|
|
_reflectionCube = null;
|
|
}
|
|
|
|
void OnValidate()
|
|
{
|
|
if (this && isActiveAndEnabled)
|
|
OnEnable();
|
|
else
|
|
OnDisable();
|
|
}
|
|
|
|
void OnEnable()
|
|
{
|
|
if (!RenderSettings.skybox && !reflectionSkyOverride)
|
|
return;
|
|
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
UnityEditor.EditorApplication.delayCall -= Apply;
|
|
UnityEditor.EditorApplication.delayCall += Apply;
|
|
return;
|
|
}
|
|
#endif
|
|
StartCoroutine(ApplyNextFrame());
|
|
}
|
|
|
|
IEnumerator ApplyNextFrame()
|
|
{
|
|
yield return null;
|
|
Apply();
|
|
}
|
|
|
|
void Apply()
|
|
{
|
|
if (!this || !isActiveAndEnabled)
|
|
return;
|
|
|
|
if (!RenderSettings.skybox && !reflectionSkyOverride)
|
|
return;
|
|
|
|
RenderSettings.ambientIntensity = environmentLightingIntensity;
|
|
|
|
var camGo = new GameObject("__SkyboxEnvCam") { hideFlags = HideFlags.HideAndDontSave };
|
|
try
|
|
{
|
|
var cam = camGo.AddComponent<Camera>();
|
|
cam.enabled = false;
|
|
cam.cullingMask = 0;
|
|
cam.clearFlags = CameraClearFlags.Skybox;
|
|
cam.cameraType = CameraType.Reflection;
|
|
|
|
var camData = camGo.AddComponent<UniversalAdditionalCameraData>();
|
|
camData.renderPostProcessing = false;
|
|
camData.requiresDepthTexture = false;
|
|
camData.requiresColorTexture = false;
|
|
camData.renderShadows = false;
|
|
|
|
if (reflectionSkyOverride)
|
|
camGo.AddComponent<Skybox>().material = reflectionSkyOverride;
|
|
|
|
camGo.transform.position = transform.position;
|
|
|
|
var rt = RenderTexture.GetTemporary(64, 64, 16);
|
|
cam.targetTexture = rt;
|
|
cam.Render();
|
|
cam.targetTexture = null;
|
|
RenderTexture.ReleaseTemporary(rt);
|
|
|
|
EnsureReflectionCubemap();
|
|
cam.RenderToCubemap(_reflectionCube);
|
|
}
|
|
finally
|
|
{
|
|
DestroyImmediate(camGo);
|
|
}
|
|
|
|
RenderSettings.defaultReflectionMode = DefaultReflectionMode.Custom;
|
|
RenderSettings.customReflectionTexture = _reflectionCube;
|
|
RenderSettings.reflectionIntensity = reflectionIntensity;
|
|
|
|
RenderSettings.ambientMode = AmbientMode.Skybox;
|
|
DynamicGI.UpdateEnvironment();
|
|
}
|
|
|
|
void EnsureReflectionCubemap()
|
|
{
|
|
int size = Mathf.Max(16, reflectionResolution);
|
|
|
|
if (!_reflectionCube || _reflectionCube.width != size)
|
|
{
|
|
if (_reflectionCube)
|
|
{
|
|
DestroyImmediate(_reflectionCube);
|
|
}
|
|
|
|
_reflectionCube = new Cubemap(size, TextureFormat.RGBA32, true)
|
|
{
|
|
name = "SkyboxReflection (generated)"
|
|
};
|
|
}
|
|
}
|
|
}
|