diff options
| author | yum <yum.food.vr@gmail.com> | 2026-01-18 11:48:35 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-01-18 11:48:35 -0800 |
| commit | fbe7ed126883b0c4a1d5115e5c953bc244bc0214 (patch) | |
| tree | 7bf3926507eb33c3b4278de375f4cd68740e378f | |
| parent | 29fcaf34e1e6932379714ec3f2adffbbd487810e (diff) | |
Impostors: baking script now auto-scales bounds
| -rwxr-xr-x | Scripts/Impostors.cs | 64 | ||||
| -rwxr-xr-x | impostor.cginc | 33 |
2 files changed, 60 insertions, 37 deletions
diff --git a/Scripts/Impostors.cs b/Scripts/Impostors.cs index 1214b8f..e77be4e 100755 --- a/Scripts/Impostors.cs +++ b/Scripts/Impostors.cs @@ -7,7 +7,7 @@ using System.IO; public class Impostors : MonoBehaviour { [Header("Bounding Sphere")] - public float sphere_radius_ = 1f; + public float radiusScale = 1f; [Header("Grid Settings")] [Range(2, 20)] public int gridResolution = 5; @@ -27,9 +27,23 @@ public class Impostors : MonoBehaviour private Material impostorMaterial; public bool HasImpostor => impostorObject != null; - private float Radius => sphere_radius_ * Mathf.Max(transform.lossyScale.x, transform.lossyScale.y, transform.lossyScale.z); private string OutputFolder => GetOutputFolder(); + Bounds GetCombinedBounds() + { + Renderer[] allRenderers = originalMesh.GetComponentsInChildren<Renderer>(true); + Renderer[] renderers = System.Array.FindAll(allRenderers, r => r.gameObject != impostorObject); + Bounds bounds = renderers[0].bounds; + for (int i = 1; i < renderers.Length; i++) + bounds.Encapsulate(renderers[i].bounds); + return bounds; + } + + float GetBoundingSphereRadius() + { + return GetCombinedBounds().extents.magnitude * radiusScale; + } + void OnEnable() => Camera.onPreRender += UpdateMainCameraPos; void OnDisable() => Camera.onPreRender -= UpdateMainCameraPos; @@ -41,8 +55,14 @@ public class Impostors : MonoBehaviour void OnDrawGizmos() { + if (originalMesh == null) return; + + Bounds bounds = GetCombinedBounds(); + Vector3 center = bounds.center; + float radius = GetBoundingSphereRadius(); + Gizmos.color = Color.cyan; - Gizmos.DrawWireSphere(transform.position, Radius); + Gizmos.DrawWireSphere(center, radius); if (Application.isEditor && gridResolution > 0) { @@ -51,9 +71,9 @@ public class Impostors : MonoBehaviour { for (int x = 0; x < gridResolution; x++) { - Vector3 worldPos = transform.position + PlaneToHemiOctahedron(x, y) * (Radius + nearClippingDistance); - Gizmos.DrawSphere(worldPos, Radius * 0.05f); - Gizmos.DrawLine(worldPos, transform.position); + Vector3 worldPos = center + PlaneToHemiOctahedron(x, y) * (radius + nearClippingDistance); + Gizmos.DrawSphere(worldPos, radius * 0.05f); + Gizmos.DrawLine(worldPos, center); } } } @@ -110,23 +130,27 @@ public class Impostors : MonoBehaviour cameras = new Camera[gridResolution * gridResolution]; int idx = 0; + Bounds bounds = GetCombinedBounds(); + Vector3 center = bounds.center; + float radius = GetBoundingSphereRadius(); + for (int y = 0; y < gridResolution; y++) { for (int x = 0; x < gridResolution; x++) { Vector3 localDir = PlaneToHemiOctahedron(x, y); - Vector3 worldPos = transform.position + (transform.rotation * localDir) * (Radius + nearClippingDistance); + Vector3 worldPos = center + (transform.rotation * localDir) * (radius + nearClippingDistance); GameObject camObj = new GameObject($"Camera_{x}_{y}"); camObj.transform.SetParent(parent.transform, false); camObj.transform.position = worldPos; - camObj.transform.LookAt(transform.position, transform.up); + camObj.transform.LookAt(center, transform.up); Camera cam = camObj.AddComponent<Camera>(); cam.orthographic = true; - cam.orthographicSize = Radius; + cam.orthographicSize = radius; cam.nearClipPlane = nearClippingDistance; - cam.farClipPlane = Radius * 2f + nearClippingDistance; + cam.farClipPlane = radius * 2f + nearClippingDistance; cam.cullingMask = cullingMask; cam.clearFlags = renderSkybox ? CameraClearFlags.Skybox : CameraClearFlags.SolidColor; cam.backgroundColor = Color.clear; @@ -250,7 +274,7 @@ public class Impostors : MonoBehaviour public void BakeTexture() { SetRenderersEnabled(true); - if (cameras == null || cameras.Length != gridResolution * gridResolution || cameras[0] == null) CreateCameras(); + CreateCameras(); Shader depthBlitShader = Shader.Find("Hidden/yum_food/DepthBlit"); if (depthBlitShader == null) { Debug.LogError("DepthBlit shader not found"); return; } @@ -539,14 +563,17 @@ public class Impostors : MonoBehaviour Shader shader = Shader.Find("yum_food/3ner"); if (shader == null) { Debug.LogError("Shader not found"); return; } + Bounds bounds = GetCombinedBounds(); + float radius = GetBoundingSphereRadius(); + impostorMaterial = new Material(shader); impostorMaterial.enableInstancing = true; for (int i = 0; i < textures.Length; i++) impostorMaterial.SetTexture(exportSettings[i].materialProp, textures[i]); impostorMaterial.SetInt("_Impostors_Grid_Resolution", gridResolution); - impostorMaterial.SetFloat("_Impostors_Sphere_Radius", sphere_radius_); + impostorMaterial.SetFloat("_Impostors_Sphere_Radius", radius); impostorMaterial.SetFloat("_Impostors_Near_Clip", nearClippingDistance); - impostorMaterial.SetFloat("_Impostors_Far_Clip", sphere_radius_ * 2f + nearClippingDistance); + impostorMaterial.SetFloat("_Impostors_Far_Clip", radius * 2f + nearClippingDistance); impostorMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.LessEqual); impostorMaterial.SetFloat("_Impostors_Enabled", 1); impostorMaterial.SetFloat("_Impostors_Parallax", 1); @@ -555,8 +582,9 @@ public class Impostors : MonoBehaviour impostorObject = GameObject.CreatePrimitive(PrimitiveType.Quad); impostorObject.name = "Impostor"; - impostorObject.transform.SetParent(transform, false); - impostorObject.transform.localScale = Vector3.one * sphere_radius_ * 2.0f; + impostorObject.transform.position = bounds.center; + impostorObject.transform.localScale = Vector3.one * radius * 2.0f; + impostorObject.transform.SetParent(transform, true); DestroyImmediate(impostorObject.GetComponent<Collider>()); impostorObject.GetComponent<MeshRenderer>().sharedMaterial = impostorMaterial; @@ -584,7 +612,11 @@ public class Impostors : MonoBehaviour if (originalMesh == null) return; foreach (Renderer r in originalMesh.GetComponentsInChildren<Renderer>(true)) r.enabled = enabled; - if (impostorObject != null) impostorObject.SetActive(!enabled); + if (impostorObject != null) + { + Renderer impostorRenderer = impostorObject.GetComponent<Renderer>(); + if (impostorRenderer != null) impostorRenderer.enabled = !enabled; + } } } diff --git a/impostor.cginc b/impostor.cginc index fe08b67..14fee5b 100755 --- a/impostor.cginc +++ b/impostor.cginc @@ -89,24 +89,22 @@ ImpostorSample SampleImpostorCell(float2 cell, float2 uvInCell, float invGridRes return s; } -float2 ImpostorParallaxOffset(float3 planeX, float3 planeY, float3 planeN, float3 pivotToCamOS, float encodedDepth, float rcpObjScale, float objRadiusScaled, float objNearScaled) { +float2 ImpostorParallaxOffset(float3 planeX, float3 planeY, float3 planeN, float3 pivotToCamOS, float encodedDepth) { float2 camXY = float2(dot(pivotToCamOS, planeX), dot(pivotToCamOS, planeY)); float camZ = dot(pivotToCamOS, planeN); camZ = (abs(camZ) < 1e-4) ? (camZ < 0 ? -1e-4 : 1e-4) : camZ; float worldSpaceDepth = lerp(_Impostors_Near_Clip, _Impostors_Far_Clip, encodedDepth); - float depth01 = (worldSpaceDepth - objNearScaled) * objRadiusScaled; + float depth01 = (worldSpaceDepth - _Impostors_Near_Clip) / (2.0 * _Impostors_Sphere_Radius); float height = 0.5 - depth01; return (camXY / camZ) * height; } -float3 ReconstructObjectOffset(float3 planeX, float3 planeY, float3 planeN, float2 uv, float encodedDepth, float rcpObjScale, float objRadius, float objNear) { - float objFar = _Impostors_Far_Clip * rcpObjScale; - - float2 offsetXY = (0.5 - uv) * (2.0 * objRadius); - float objectSpaceDepth = lerp(objNear, objFar, encodedDepth); - float offsetZ = (objRadius + objNear) - objectSpaceDepth; +float3 ReconstructObjectOffset(float3 planeX, float3 planeY, float3 planeN, float2 uv, float encodedDepth) { + float2 offsetXY = (0.5 - uv) * (2.0 * _Impostors_Sphere_Radius); + float worldSpaceDepth = lerp(_Impostors_Near_Clip, _Impostors_Far_Clip, encodedDepth); + float offsetZ = (_Impostors_Sphere_Radius + _Impostors_Near_Clip) - worldSpaceDepth; return offsetXY.x * planeX + offsetXY.y * planeY + offsetZ * planeN; } @@ -212,21 +210,14 @@ ImpostorResult impostor_frag(float3 worldPos) { return result; } - // Pre-compute scale values once for both parallax and reconstruction - float objScale = max(2.0 * _Impostors_Sphere_Radius, 1e-4); - float rcpObjScale = rcp(objScale); - float objRadius = _Impostors_Sphere_Radius * rcpObjScale; - float objRadiusScaled = rcp(2.0 * objRadius); - float objNearScaled = _Impostors_Near_Clip * rcpObjScale; - float2 parallaxOffset0 = 0, parallaxOffset1 = 0, parallaxOffset2 = 0; bool needsParallaxResample = false; [branch] if (parallaxStrength > 0.001) { - parallaxOffset0 = ImpostorParallaxOffset(planeX0, planeY0, planeN0, pivotToCamOS, depthBlended, rcpObjScale, objRadiusScaled, objNearScaled) * parallaxStrength; - parallaxOffset1 = ImpostorParallaxOffset(planeX1, planeY1, planeN1, pivotToCamOS, depthBlended, rcpObjScale, objRadiusScaled, objNearScaled) * parallaxStrength; - parallaxOffset2 = ImpostorParallaxOffset(planeX2, planeY2, planeN2, pivotToCamOS, depthBlended, rcpObjScale, objRadiusScaled, objNearScaled) * parallaxStrength; + parallaxOffset0 = ImpostorParallaxOffset(planeX0, planeY0, planeN0, pivotToCamOS, depthBlended) * parallaxStrength; + parallaxOffset1 = ImpostorParallaxOffset(planeX1, planeY1, planeN1, pivotToCamOS, depthBlended) * parallaxStrength; + parallaxOffset2 = ImpostorParallaxOffset(planeX2, planeY2, planeN2, pivotToCamOS, depthBlended) * parallaxStrength; float maxOffsetSq = max(max(dot(parallaxOffset0, parallaxOffset0), dot(parallaxOffset1, parallaxOffset1)), dot(parallaxOffset2, parallaxOffset2)); needsParallaxResample = maxOffsetSq > 0.00005; @@ -275,9 +266,9 @@ ImpostorResult impostor_frag(float3 worldPos) { result.smoothness = blended.metallicGloss.g; #if defined(_IMPOSTORS_DEPTH) - float3 offset0 = ReconstructObjectOffset(planeX0, planeY0, planeN0, finalUv0, depth0, rcpObjScale, objRadius, objNearScaled); - float3 offset1 = ReconstructObjectOffset(planeX1, planeY1, planeN1, finalUv1, depth1, rcpObjScale, objRadius, objNearScaled); - float3 offset2 = ReconstructObjectOffset(planeX2, planeY2, planeN2, finalUv2, depth2, rcpObjScale, objRadius, objNearScaled); + float3 offset0 = ReconstructObjectOffset(planeX0, planeY0, planeN0, finalUv0, depth0); + float3 offset1 = ReconstructObjectOffset(planeX1, planeY1, planeN1, finalUv1, depth1); + float3 offset2 = ReconstructObjectOffset(planeX2, planeY2, planeN2, finalUv2, depth2); result.objPos = offset0 * bw.x + offset1 * bw.y + offset2 * bw.z; #endif |
