summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xScripts/Impostors.cs64
-rwxr-xr-ximpostor.cginc33
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