UE4透明粒子距離場碰撞隨機分佈解決方案

由於景深碰撞不能應用於透明物體,因此試了一下UE4的距離場碰撞,效果還可以接受,但是發現發射器的Collision中Random Spread和Random Distribution參數都失效了,粒子只能按照法線做反彈。
這裏寫圖片描述
檢查源碼發現CollideWithDepthBuffer函數中的一行ComputeCollidingVelocity函數在CollideWithDistanceField中被改寫成過程了,而且裏面沒有隨機分佈的相關代碼,把部分過程刪掉換成NewVelocity = ComputeCollidingVelocity(MidVelocity, CollisionPlane.xyz, RelativeTime, Resilience);就可以解決問題了。

//C:\Program Files\Epic Games\UE_4.17\Engine\Shaders\Private\ParticleSimulationShader.usf
/**
 * Compute collision with the global signed distance field
 */
void CollideWithDistanceField(
    out float3 NewPosition,
    out float3 NewVelocity,
    inout float RelativeTime,
    in float3 InPosition,
    in float3 InVelocity,
    in float3 Acceleration,
    in float CollisionRadius,
    in float Resilience
    )
{
    // Integration assuming no collision.
    float3 MidVelocity = InVelocity.xyz + 0.5f * Acceleration;
    float3 DeltaPosition = DeltaSeconds * MidVelocity;
    NewPosition = InPosition.xyz + DeltaPosition;
    NewVelocity = InVelocity.xyz + Acceleration;

    float DistanceToNearestSurface = GetDistanceToNearestSurfaceGlobal(InPosition);
    float MaxCollisionDistance = CollisionRadius + length(DeltaPosition.xyz);

    if (DistanceToNearestSurface < MaxCollisionDistance)
    { 
        float3 CollisionWorldNormal = normalize(GetDistanceFieldGradientGlobal(InPosition));
        float3 CollisionWorldPosition = InPosition - CollisionWorldNormal * DistanceToNearestSurface;

        float4 CollisionPlane = float4(CollisionWorldNormal.xyz, dot(CollisionWorldPosition.xyz, CollisionWorldNormal.xyz));

        // Compute the portion of velocity normal to the collision plane.
        float VelocityDot = dot(CollisionPlane.xyz, DeltaPosition.xyz);
        float InvVelocityDot = rcp(VelocityDot + 0.0001f); // Add a small amount to avoid division by zero.

        // Distance to the plane from the center of the particle.
        float DistanceToPlane = dot(CollisionPlane.xyz, InPosition.xyz) - CollisionPlane.w;

        // Find out the time of intersection for both the front and back of the sphere.
        float t_back = -(DistanceToPlane + CollisionRadius) * InvVelocityDot;
        float t_front = -(DistanceToPlane - CollisionRadius) * InvVelocityDot;

        //if (t_back >= 0 && t_front <= 1 && DistanceToPlane >= 0)
        if (step(0, t_back) * step(t_front, 1) * step(0, DistanceToPlane))
        {
            NewVelocity = ComputeCollidingVelocity(MidVelocity, CollisionPlane.xyz, RelativeTime, Resilience);
            // If the particle lies approximately on the collision plane, don't jump to the point of collision.
            t_front *= step(VelocityDot,-1);

            // Integrate position taking the collision in to account.
            NewPosition = InPosition + DeltaPosition * t_front + NewVelocity * (1.0f - t_front) * DeltaSeconds;

            // Update the relative time. Usually this does nothing, but if the
            // user has elected to kill the particle upon collision this will do
            // so.
            RelativeTime += Simulation.CollisionTimeBias;
        }
        //else if (t_front > 0 && t_back < 1 && DistanceToPlane < 0)
        else if (step(0, t_front) * step(t_back, 1) * step(DistanceToPlane,0))
        {
            // The particle has collided against a backface, kill it by setting
            // relative time to a value > 1.0.
            RelativeTime = 1.1f;
        }
    }
}

這裏寫圖片描述

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章