summaryrefslogtreecommitdiffstats
path: root/instancing.cginc
diff options
context:
space:
mode:
Diffstat (limited to 'instancing.cginc')
-rwxr-xr-xinstancing.cginc109
1 files changed, 69 insertions, 40 deletions
diff --git a/instancing.cginc b/instancing.cginc
index 6672db4..5ad3b23 100755
--- a/instancing.cginc
+++ b/instancing.cginc
@@ -48,6 +48,11 @@ float3 qrotate(float4 q, float3 v) {
return v + q.w * t + cross(q.xyz, t);
}
+// Quaternion conjugate (inverse for unit quaternions)
+float4 qconj(float4 q) {
+ return float4(-q.xyz, q.w);
+}
+
// Create quaternion from Euler angles (in degrees)
float4 euler_to_quat(float3 euler) {
float3 rad = euler * 0.0174533; // deg to rad
@@ -83,90 +88,114 @@ float4 compute_rotation(int x, int z) {
return euler_to_quat(euler);
}
-#endif // _INSTANCE_TEXTURE_OFFSET
+bool get_instance_transform(out float3 center, out float4 rotation, out float3 scale);
-void instance_distance_culling(inout v2f i) {
-#if defined(_INSTANCE_DISTANCE_CULLING)
- // We want to measure the distance from the instance's transform to the camera.
- float3 instance_pos = mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz;
- float distance = length(_WorldSpaceCameraPos - instance_pos);
- if (distance > _Instance_Distance_Culling_Distance) {
- discard;
- }
-#endif // _INSTANCE_DISTANCE_CULLING
+bool get_instance_center(out float3 center) {
+#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED)
+ float4 rotation;
+ float3 scale;
+ return get_instance_transform(center, rotation, scale);
+#else
+ center = 0;
+ return false;
+#endif // _INSTANCE_TEXTURE_OFFSET && UNITY_INSTANCING_ENABLED
}
-void instancing_vert(inout appdata v) {
+bool get_instance_transform(out float3 center, out float4 rotation, out float3 scale) {
#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED)
- // Extract instance ID from the matrix translation component
- // We encoded it in the X translation (m03) on the CPU side
- float encodedID = unity_ObjectToWorld[0][3];
- uint instanceID = (uint)encodedID;
+ uint instanceID = (uint)UNITY_ACCESS_INSTANCED_PROP(InstanceProps, _Instance_ID);
- // Read grid coordinates from instance data texture
- // _TexelSize.zw contains (width, height)
float2 texDimensions = _Instance_Texture_Offset_Data_Tex_TexelSize.zw;
int2 texCoord = int2(instanceID % (uint)texDimensions.x,
instanceID / (uint)texDimensions.x);
float2 uv = (float2(texCoord) + 0.5) / texDimensions;
float4 instanceData = _Instance_Texture_Offset_Data_Tex.SampleLevel(point_repeat_s, uv, 0);
- // Check if this is a valid instance (alpha >= 0)
if (instanceData.w < 0) {
- // Invalid instance - collapse to degenerate triangle far away
- v.vertex.xyz = float3(0, -100000, 0);
- return;
+ center = 0;
+ rotation = float4(0, 0, 0, 1);
+ scale = 1.0;
+ return false;
}
int3 gridCoord = int3(instanceData.xyz);
-
- // Compute hash values for randomization
float h0, h1, h2, h3, h4;
Hash5(gridCoord.x, gridCoord.z, h0, h1, h2, h3, h4);
- // Base grid position
float3 basePosition = float3(
gridCoord.x * _Instance_Texture_Offset_Cell_Dimensions.x,
gridCoord.y * _Instance_Texture_Offset_Cell_Dimensions.y,
gridCoord.z * _Instance_Texture_Offset_Cell_Dimensions.z
);
- // Add randomized offset within cell
float3 positionOffset = float3(
_Instance_Texture_Offset_Cell_Dimensions.x * h0,
_Instance_Texture_Offset_Cell_Dimensions.y * h1,
_Instance_Texture_Offset_Cell_Dimensions.z * h2
);
- // Compute random rotation from hash (in world space)
+ center = basePosition + positionOffset;
+
float4 randomRotation = compute_rotation(gridCoord.x, gridCoord.z);
+ rotation = qmul(randomRotation, _Instance_Texture_Offset_Base_Rotation);
+
+ scale = _Instance_Texture_Offset_Base_Scale * (1.0 + h4 * _Instance_Texture_Offset_Scale_Randomization);
+ return true;
+#else
+ center = 0;
+ rotation = float4(0, 0, 0, 1);
+ scale = 1.0;
+ return false;
+#endif // _INSTANCE_TEXTURE_OFFSET && UNITY_INSTANCING_ENABLED
+}
- // Combine with base rotation: apply base rotation first, then world-space randomization
- float4 finalRotation = qmul(randomRotation, _Instance_Texture_Offset_Base_Rotation);
+#endif // _INSTANCE_TEXTURE_OFFSET
- // Compute scale
- float3 scale = _Instance_Texture_Offset_Base_Scale * (1.0 + h4 * _Instance_Texture_Offset_Scale_Randomization);
+bool instance_distance_culling() {
+#if defined(_INSTANCE_DISTANCE_CULLING)
+ float3 instance_pos;
+
+#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED)
+ if (!get_instance_center(instance_pos)) {
+ // Invalid instance, discard
+ return true;
+ }
+#else
+ instance_pos = mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz;
+#endif
+
+ float distance = length(_WorldSpaceCameraPos - instance_pos);
+ if (distance < _Instance_Distance_Culling_Min_Distance ||
+ distance > _Instance_Distance_Culling_Max_Distance) {
+ return true;
+ }
+#endif // _INSTANCE_DISTANCE_CULLING
+ return false;
+}
+
+void instancing_vert(inout appdata v) {
+#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED)
+ float3 center;
+ float4 finalRotation;
+ float3 scale;
+ if (!get_instance_transform(center, finalRotation, scale)) {
+ // Invalid instance - collapse to degenerate triangle far away
+ v.vertex.xyz = float3(0, -100000, 0);
+ return;
+ }
// Apply transform to vertex in object space
float3 scaledVertex = v.vertex.xyz * scale;
float3 rotatedVertex = qrotate(finalRotation, scaledVertex);
- float3 transformedVertex = rotatedVertex + basePosition + positionOffset;
-
- // Compensate for the encoded offset that Unity will apply via the matrix
- // Unity will add encodedID to X, so we subtract it here
- transformedVertex.x -= encodedID;
+ float3 transformedVertex = rotatedVertex + center;
// Update vertex position
v.vertex.xyz = transformedVertex;
- // Transform normal and tangent (only rotation, no scale - they're direction vectors)
+ // Transform normal and tangent
v.normal = qrotate(finalRotation, v.normal);
v.tangent.xyz = qrotate(finalRotation, v.tangent.xyz);
#endif // _INSTANCE_TEXTURE_OFFSET
}
-void instancing_frag(v2f i) {
- instance_distance_culling(i);
-}
-
#endif // __INSTANCING_INC