예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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))}");
        }