private static string GetFluidResponseSource( ICollisionSettings settings, string roughSurfaceSource) { var src = ""; if (settings.RoughSurface) { src += roughSurfaceSource; } src += $@" float projVelocity = dot(n, velocity); float3 normalVelocity = projVelocity * n; float3 tangentVelocity = velocity - normalVelocity; float3 v = 0; if (projVelocity < 0) {{ v -= ((1 + Elasticity) * projVelocity) * n; }} v -= Friction * tangentVelocity; // Repulsion force {(settings.RepulsionForce ? "force += v * (1.0f / mass) * RepulsionForce * invDt;" : "")} velocity += v; oldPosition = position; age += (LifetimeLoss * lifetime);"; return(src); }
private static string GetFluidResponseSource( ICollisionSettings settings, string roughSurfaceSource) { var hasPreviousPosition = false; var hasLifetime = false; var block = settings as VFXBlock; if (block != null) { hasPreviousPosition = block.GetData().IsCurrentAttributeWritten(FluvioFXAttribute.PreviousPosition); hasLifetime = block.GetData().IsCurrentAttributeWritten(VFXAttribute.Alive); } var src = ""; if (settings.RoughSurface) { src += roughSurfaceSource; } src += $@" float projVelocity = dot(n, velocity); float3 normalVelocity = projVelocity * n; float3 tangentVelocity = velocity - normalVelocity; float3 v = 0; if (projVelocity < 0) {{ v -= ((1 + Bounce) * projVelocity) * n; }} v -= Friction * tangentVelocity; // Repulsion force {(settings.RepulsionForce ? "force += v * (1.0f / mass) * RepulsionForce * invDt;" : "")} velocity += v; {(hasPreviousPosition ? "previousPosition = position - v;" : "")} age += (LifetimeLoss * lifetime);"; return(src); }
public static IEnumerable <VFXPropertyWithValue> GetInputProperties( ICollisionSettings collisionSettings, IEnumerable <VFXPropertyWithValue> baseProperties) { var properties = baseProperties; if (collisionSettings.BoundaryPressure) { properties = properties .Concat(FluvioFXBlock.PropertiesFromType(typeof(BoundaryPressureProperties))); } if (collisionSettings.BoundaryViscosity) { properties = properties .Concat(FluvioFXBlock.PropertiesFromType(typeof(BoundaryViscosityProperties))); } if (collisionSettings.RepulsionForce) { properties = properties .Concat(FluvioFXBlock.PropertiesFromType(typeof(RepulsionForceProperties))); } return(properties); }
public static string GetCollisionSource( ICollisionSettings settings, string baseSource, string collisionResponseSource, string roughSurfaceSource) { if (!settings.BoundaryPressure && !settings.BoundaryViscosity) { return(baseSource.Replace(collisionResponseSource, GetFluidResponseSource(settings, roughSurfaceSource))); } var proxyTestSource = baseSource .Replace("float3 nextPos = position + velocity * deltaTime;", "") .Replace("nextPos", "proxyPosition") .Replace("position", "dummyPosition") .Replace(collisionResponseSource, " collisionTest = true;"); var split = proxyTestSource.Split(new [] { "\r\n", "\r", "\n" }, StringSplitOptions.None); proxyTestSource = string.Join("\n ", split); var data = (settings as VFXBlock)?.GetData(); return($@"{FluvioFXBlock.CheckAlive(data)} {{ float3 offset, proxyPosition, dummyPosition, dist; float density = 0; float pressure, lenSq, diffSq; bool collisionTest = false; float searchRadius = solverData_KernelSize.x; float step = solverData_KernelSize.w; float3 gridJitter = float3(FIXED_RAND3(0x5f7b48e2)) * step; float x, y, z; // Fluid density calculation for(x = -searchRadius; x < searchRadius; x += step) {{ for(y = -searchRadius; y < searchRadius; y += step) {{ for(z = -searchRadius; z < searchRadius; z += step) {{ // Get proxy particle position offset = float3(x, y, z); proxyPosition = position + offset; // Snap to random grid, but keep the grid consistent per particle proxyPosition = (round(proxyPosition / step) * step) + gridJitter; collisionTest = false; {proxyTestSource} if (collisionTest) {{ // Range check // TODO: We can optimize this away since we know the precise step size dist = position - proxyPosition; lenSq = dot(dist, dist); if (lenSq < solverData_KernelSize.y) {{ // Sum density diffSq = solverData_KernelSize.y - lenSq; density += mass * Poly6Calculate(diffSq, solverData_KernelFactors.x); }} }} }} }} }} density = max(density, solverData_Fluid_MinimumDensity); pressure = solverData_Fluid_GasConstant * (density - solverData_Fluid_Density); float2 neighborDensityPressure = float2( solverData_Fluid_Density, {(settings.BoundaryPressure ? "GasConstant * solverData_Fluid_Density" : "0")}); float len, len3, diff, bodyRadiusSq, scalar; float3 f, neighborVelocity, bodyDist; for(x = -searchRadius; x < searchRadius; x += step) {{ for(y = -searchRadius; y < searchRadius; y += step) {{ for(z = -searchRadius; z < searchRadius; z += step) {{ if (abs(x) < step && abs(y) < step && abs(z) < step) {{ continue; }} // Get proxy particle position offset = float3(x, y, z); proxyPosition = position + offset; // Snap to random grid, but keep the grid consistent per particle proxyPosition = (round(proxyPosition / step) * step) + gridJitter; collisionTest = false; {proxyTestSource} if (collisionTest) {{ // Range check // TODO: We can optimize this away since we know the precise step size dist = position - proxyPosition; lenSq = dot(dist, dist); if (lenSq < solverData_KernelSize.y) {{ // For kernels lenSq = dot(dist, dist); len = sqrt(lenSq); len3 = len * len * len; diffSq = solverData_KernelSize.y - lenSq; diff = solverData_KernelSize.x - len; {(settings.BoundaryPressure ? @"// Pressure term scalar = mass * (pressure + neighborDensityPressure.y) / (neighborDensityPressure.x * 2.0f); f = SpikyCalculateGradient(dist, diff, len, solverData_KernelFactors.y); f *= scalar; force -= f;" : "")} {(settings.BoundaryViscosity ? @"// Viscosity term bodyDist = proxyPosition - CenterOfGravity; bodyRadiusSq = sqrt(dot(bodyDist, bodyDist)); neighborVelocity = Velocity + (AngularVelocity / FLUVIO_TAU) * FLUVIO_TAU * bodyRadiusSq; scalar = mass * ViscosityCalculateLaplacian( diff, solverData_KernelSize.z, solverData_KernelFactors.z) * (1.0f / neighborDensityPressure.x); f = neighborVelocity - velocity; f *= scalar * Viscosity; force += f;" : "")} }} }} }} }} }} // Write totals to density/pressure (zw) density = max(densityPressure.z + density, solverData_Fluid_MinimumDensity); pressure = solverData_Fluid_GasConstant * (density - solverData_Fluid_Density); densityPressure.zw = float2(density, pressure); }} {baseSource.Replace(collisionResponseSource, GetFluidResponseSource(settings,roughSurfaceSource))}"); }