You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

173 lines
6.3 KiB

using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace UnityEditor.VFX.Block
{
class CollisionSDF : CollisionShapeBase
{
public class InputProperties
{
[Tooltip("Sets the Signed Distance Field to sample from.")]
public Texture3D DistanceField = VFXResources.defaultResources.signedDistanceField;
[Tooltip("Sets the transform with which to position, scale, or rotate the field.")]
public OrientedBox FieldTransform = OrientedBox.defaultValue;
}
public override IEnumerable<VFXNamedExpression> GetParameters(CollisionBase collisionBase, IEnumerable<VFXNamedExpression> collisionBaseParameters)
{
VFXExpression transform = null;
VFXExpression SDF = null;
foreach (var p in base.GetParameters(collisionBase, collisionBaseParameters))
{
if (p.name == "FieldTransform")
{
transform = p.exp;
VFXExpression scale = new VFXExpressionAbs(new VFXExpressionExtractScaleFromMatrix(transform));
yield return new VFXNamedExpression(VFXOperatorUtility.Reciprocal(scale), "invScale");
yield return new VFXNamedExpression(VFXOperatorUtility.IsTRSMatrixZeroScaled(transform), "isZeroScaled");
yield return new VFXNamedExpression(new VFXExpressionInverseTRSMatrix(transform), "InvFieldTransform");
}
if (p.name == "DistanceField")
SDF = p.exp;
yield return p;
}
var w = new VFXExpressionCastUintToFloat(new VFXExpressionTextureWidth(SDF));
var h = new VFXExpressionCastUintToFloat(new VFXExpressionTextureHeight(SDF));
var d = new VFXExpressionCastUintToFloat(new VFXExpressionTextureDepth(SDF));
var uvStep = VFXOperatorUtility.Reciprocal(new VFXExpressionCombine(w, h, d));
var maxDim = VFXOperatorUtility.Max3(w, h, d);
var textureDimScale = uvStep * new VFXExpressionCombine(maxDim, maxDim, maxDim);
var textureDimInvScale = VFXOperatorUtility.Reciprocal(textureDimScale);
var stepSize = VFXOperatorUtility.Reciprocal(maxDim);
yield return new VFXNamedExpression(uvStep, "uvStep");
yield return new VFXNamedExpression(textureDimScale, "textureDimScale");
yield return new VFXNamedExpression(textureDimInvScale, "textureDimInvScale");
yield return new VFXNamedExpression(stepSize, "stepSizeMeter");
}
public override string GetSource(CollisionBase collisionBase)
{
string handlingSelectionCode = collisionBase.mode == CollisionBase.Mode.Solid ? @"
if(currentDistanceToBox <= length(tDelta)) //Potential hit
{
if(currentDistanceToBox >= 0) //Find first ray box intersection
{
float3 dummyNormal;
bool boxHit = RayBoxIntersection(tPos, tDelta, halfBoxSize, 1, tHit, dummyNormal);
needsSphereMarching = boxHit;
tPos += tHit * tDelta;
}
else
{
float3 uvw = saturate(tPos + 0.5f);
float dist = SampleSDF(DistanceField, uvw) - radiusOffset;
needsSphereMarching = dist > 0;
needsProjecting = !needsSphereMarching;
}
}
" : @"
if(currentDistanceToBox > 0)
{
needsProjecting = true;
tPos = ProjectOnBox(tPos, halfBoxSize);
}
else
{
float3 uvw = saturate(tPos + 0.5f);
float dist = SampleSDF(DistanceField, uvw) - radiusOffset;
needsSphereMarching = dist < 0 && abs(dist) <= length(tDelta) ;
needsProjecting = dist >= 0;
}
";
string sphereMarchingCode = @"
float3 uvw = saturate(tPos + 0.5f);
float dist = colliderSign * (SampleSDF(DistanceField, uvw) - radiusOffset);
//Sphere March
const int ITERATION_COUNT = 8;
int i = 0;
hit = false;
float maxDist = length(tDelta * textureDimInvScale);
for(i = 0; i < ITERATION_COUNT; i++)
{
uvw = uvw + tDir * textureDimScale * dist;
float newDist = colliderSign * (SampleSDF(DistanceField, uvw) - radiusOffset);
tHit += dist/maxDist;
if(newDist < VFX_EPSILON)
{
hit = tHit <= 1 && tHit >= 0;
break;
}
if(tHit > 1)
{
hit = false;
break;
}
dist = newDist;
}
if(hit)
{
tPos = uvw - 0.5f;
hitPos = mul(FieldTransform, float4(tPos, 1.0f)).xyz;
hitNormal = SampleSDFUnscaledDerivatives(DistanceField, uvw, uvStep) * textureDimScale;
hitNormal = colliderSign * VFXSafeNormalize(mul(float4(hitNormal, 0.0f), InvFieldTransform).xyz);
}";
string projectOnSurfaceCode = @"
hit = true;
const int ITERATION_COUNT = 4;
int i = 0;
float3 uvw = saturate(tPos + 0.5f);
float3 sdfNormal = normalize(SampleSDFUnscaledDerivatives(DistanceField, uvw, uvStep));
float radiusOffset = colliderSign * dot(sdfNormal*sdfNormal ,invScale * textureDimInvScale) * radius;
for(i = 0; i < ITERATION_COUNT; i++)
{
uvw = IterateTowardSDFSurface(DistanceField, uvw, uvStep, radiusOffset, stepSizeMeter, sdfNormal);
}
tPos = uvw - 0.5f;
hitPos = mul(FieldTransform, float4(tPos, 1.0f)).xyz;
hitNormal = sdfNormal * textureDimScale;
hitNormal = colliderSign * VFXSafeNormalize(mul(float4(hitNormal, 0.0f), InvFieldTransform).xyz);
tHit = 0;
";
var Source = new StringBuilder($@"
if (isZeroScaled)
return;
float3 tPos = mul(InvFieldTransform, float4(position,1.0f)).xyz;
float3 tVel = mul(InvFieldTransform, float4(velocity, 0.0f)).xyz;
float3 tDelta = tVel * deltaTime;
float3 tDir = VFXSafeNormalize(tVel);
float radiusOffset = colliderSign * dot(tDir * tDir,invScale * textureDimInvScale) * radius;
float3 halfBoxSize = 0.5f + radius * invScale * colliderSign;
float currentDistanceToBox = DistanceToBox(tPos, halfBoxSize);
bool needsSphereMarching = false;
bool needsProjecting = false;
{handlingSelectionCode}
if(needsSphereMarching)
{{
{sphereMarchingCode}
}}
else if (needsProjecting)
{{
{projectOnSurfaceCode}
}}
else
{{
hit = false;
tHit = 0;
}}");
return Source.ToString();
}
}
}