Circle Capsule::CrossSection(float yPos) const { assume(yPos >= 0.f); assume(yPos <= 1.f); yPos *= Height(); float3 up = UpDirection(); float3 centerPos = Bottom() + up * yPos; if (yPos < r) // First section, between Bottom() and lower point. return Circle(centerPos, up, Sqrt(r*r - (r-yPos)*(r-yPos))); if (yPos < l.Length() + r) // Second section, between lower and upper points. return Circle(centerPos, up, r); float d = yPos - r - l.Length(); // Third section, above upper point. return Circle(centerPos, up, Sqrt(r*r - d*d)); }
void UParticleModuleVelocityCone::Render3DPreview(FParticleEmitterInstance* Owner, const FSceneView* View,FPrimitiveDrawInterface* PDI) { #if WITH_EDITOR float ConeMaxAngle = 0.0f; float ConeMinAngle = 0.0f; Angle.GetOutRange(ConeMinAngle, ConeMaxAngle); float ConeMaxVelocity = 0.0f; float ConeMinVelocity = 0.0f; Velocity.GetOutRange(ConeMinVelocity, ConeMaxVelocity); float MaxLifetime = 0.0f; TArray<UParticleModule*>& Modules = Owner->SpriteTemplate->GetCurrentLODLevel(Owner)->Modules; for (int32 ModuleIndex = 0; ModuleIndex < Modules.Num(); ModuleIndex++) { UParticleModuleLifetimeBase* LifetimeMod = Cast<UParticleModuleLifetimeBase>(Modules[ModuleIndex]); if (LifetimeMod != NULL) { MaxLifetime = LifetimeMod->GetMaxLifetime(); break; } } const int32 ConeSides = 16; const float ConeRadius = ConeMaxVelocity * MaxLifetime; // Calculate direction transform const FVector DefaultDirection(0.0f, 0.0f, 1.0f); const FVector ForwardDirection = (Direction != FVector::ZeroVector)? Direction.GetSafeNormal(): DefaultDirection; FVector UpDirection(0.0f, 0.0f, 1.0f); FVector RightDirection(1.0f, 0.0f, 0.0f); if ((ForwardDirection != UpDirection) && (-ForwardDirection != UpDirection)) { RightDirection = UpDirection ^ ForwardDirection; UpDirection = ForwardDirection ^ RightDirection; } else { UpDirection = ForwardDirection ^ RightDirection; RightDirection = UpDirection ^ ForwardDirection; } FMatrix DirectionRotation; DirectionRotation.SetIdentity(); DirectionRotation.SetAxis(0, RightDirection.GetSafeNormal()); DirectionRotation.SetAxis(1, UpDirection.GetSafeNormal()); DirectionRotation.SetAxis(2, ForwardDirection); // Calculate the owning actor's scale and rotation UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); check(LODLevel); FVector OwnerScale(1.0f); FMatrix OwnerRotation(FMatrix::Identity); FVector LocalToWorldOrigin(0.0f); FMatrix LocalToWorld(FMatrix::Identity); if (Owner->Component) { AActor* Actor = Owner->Component->GetOwner(); if (Actor) { if (bApplyOwnerScale == true) { OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); } OwnerRotation = FQuatRotationMatrix(Actor->GetActorQuat()); } LocalToWorldOrigin = Owner->Component->ComponentToWorld.GetLocation(); LocalToWorld = Owner->Component->ComponentToWorld.ToMatrixWithScale().RemoveTranslation(); LocalToWorld.RemoveScaling(); } FMatrix Transform; Transform.SetIdentity(); // DrawWireCone() draws a cone down the X axis, but this cone's default direction is down Z const FRotationMatrix XToZRotation(FRotator((int32)(HALF_PI * 10430), 0, 0)); Transform *= XToZRotation; // Apply scale Transform.SetAxis(0, Transform.GetScaledAxis( EAxis::X ) * OwnerScale.X); Transform.SetAxis(1, Transform.GetScaledAxis( EAxis::Y ) * OwnerScale.Y); Transform.SetAxis(2, Transform.GetScaledAxis( EAxis::Z ) * OwnerScale.Z); // Apply direction transform Transform *= DirectionRotation; // Transform according to world and local space flags if (!LODLevel->RequiredModule->bUseLocalSpace && !bInWorldSpace) { Transform *= LocalToWorld; } else if (LODLevel->RequiredModule->bUseLocalSpace && bInWorldSpace) { Transform *= OwnerRotation; Transform *= LocalToWorld.InverseFast(); } else if (!bInWorldSpace) { Transform *= OwnerRotation; } // Apply translation Transform.SetOrigin(LocalToWorldOrigin); TArray<FVector> OuterVerts; TArray<FVector> InnerVerts; // Draw inner and outer cones DrawWireCone(PDI, InnerVerts, Transform, ConeRadius, ConeMinAngle, ConeSides, ModuleEditorColor, SDPG_World); DrawWireCone(PDI, OuterVerts, Transform, ConeRadius, ConeMaxAngle, ConeSides, ModuleEditorColor, SDPG_World); // Draw radial spokes for (int32 i = 0; i < ConeSides; ++i) { PDI->DrawLine( OuterVerts[i], InnerVerts[i], ModuleEditorColor, SDPG_World ); } #endif }
void UParticleModuleVelocityCone::SpawnEx(FParticleEmitterInstance* Owner, int32 Offset, float SpawnTime, struct FRandomStream* InRandomStream, FBaseParticle* ParticleBase) { static const float TwoPI = 2.0f * PI; static const float ToRads = PI / 180.0f; static const int32 UUPerRad = 10430; static const FVector DefaultDirection(0.0f, 0.0f, 1.0f); // Calculate the owning actor's scale UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); check(LODLevel); FVector OwnerScale(1.0f); if ((bApplyOwnerScale == true) && Owner->Component) { OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); } // Spawn particles SPAWN_INIT { // Calculate the default position (prior to the Direction vector being factored in) const float SpawnAngle = Angle.GetValue(Owner->EmitterTime, Owner->Component, InRandomStream); const float SpawnVelocity = Velocity.GetValue(Owner->EmitterTime, Owner->Component, InRandomStream); const float LatheAngle = FMath::SRand() * TwoPI; const FRotator DefaultDirectionRotater((int32)(SpawnAngle * ToRads * UUPerRad), (int32)(LatheAngle * UUPerRad), 0); const FRotationMatrix DefaultDirectionRotation(DefaultDirectionRotater); const FVector DefaultSpawnDirection = DefaultDirectionRotation.TransformVector(DefaultDirection); // Orientate the cone along the direction vector const FVector ForwardDirection = (Direction != FVector::ZeroVector)? Direction.GetSafeNormal(): DefaultDirection; FVector UpDirection(0.0f, 0.0f, 1.0f); FVector RightDirection(1.0f, 0.0f, 0.0f); if ((ForwardDirection != UpDirection) && (-ForwardDirection != UpDirection)) { RightDirection = UpDirection ^ ForwardDirection; UpDirection = ForwardDirection ^ RightDirection; } else { UpDirection = ForwardDirection ^ RightDirection; RightDirection = UpDirection ^ ForwardDirection; } FMatrix DirectionRotation; DirectionRotation.SetIdentity(); DirectionRotation.SetAxis(0, RightDirection.GetSafeNormal()); DirectionRotation.SetAxis(1, UpDirection.GetSafeNormal()); DirectionRotation.SetAxis(2, ForwardDirection); FVector SpawnDirection = DirectionRotation.TransformVector(DefaultSpawnDirection); // Transform according to world and local space flags if (!LODLevel->RequiredModule->bUseLocalSpace && !bInWorldSpace) { SpawnDirection = Owner->Component->ComponentToWorld.TransformVector(SpawnDirection); } else if (LODLevel->RequiredModule->bUseLocalSpace && bInWorldSpace) { SpawnDirection = Owner->Component->ComponentToWorld.InverseTransformVector(SpawnDirection); } // Set final velocity vector const FVector FinalVelocity = SpawnDirection * SpawnVelocity * OwnerScale; Particle.Velocity += FinalVelocity; Particle.BaseVelocity += FinalVelocity; } }
float3 Capsule::Top() const { return l.b + UpDirection() * r; }
float3 Capsule::Bottom() const { return l.a - UpDirection() * r; }