void DrawDebugCapsule(const UWorld* InWorld, FVector const& Center, float HalfHeight, float Radius, const FQuat & Rotation, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority) { // no debug line drawing on dedicated server if (GEngine->GetNetMode(InWorld) != NM_DedicatedServer) { const int32 DrawCollisionSides = 16; FVector Origin = Center; FMatrix Axes = FQuatRotationTranslationMatrix(Rotation, FVector::ZeroVector); FVector XAxis = Axes.GetScaledAxis( EAxis::X ); FVector YAxis = Axes.GetScaledAxis( EAxis::Y ); FVector ZAxis = Axes.GetScaledAxis( EAxis::Z ); // Draw top and bottom circles float HalfAxis = FMath::Max<float>(HalfHeight - Radius, 1.f); FVector TopEnd = Origin + HalfAxis*ZAxis; FVector BottomEnd = Origin - HalfAxis*ZAxis; DrawCircle(InWorld, TopEnd, XAxis, YAxis, Color, Radius, DrawCollisionSides, bPersistentLines, LifeTime, DepthPriority); DrawCircle(InWorld, BottomEnd, XAxis, YAxis, Color, Radius, DrawCollisionSides, bPersistentLines, LifeTime, DepthPriority); // Draw domed caps DrawHalfCircle(InWorld, TopEnd, YAxis, ZAxis, Color, Radius, DrawCollisionSides, bPersistentLines, LifeTime, DepthPriority); DrawHalfCircle(InWorld, TopEnd, XAxis, ZAxis, Color, Radius, DrawCollisionSides, bPersistentLines, LifeTime, DepthPriority); FVector NegZAxis = -ZAxis; DrawHalfCircle(InWorld, BottomEnd, YAxis, NegZAxis, Color, Radius, DrawCollisionSides, bPersistentLines, LifeTime, DepthPriority); DrawHalfCircle(InWorld, BottomEnd, XAxis, NegZAxis, Color, Radius, DrawCollisionSides, bPersistentLines, LifeTime, DepthPriority); // Draw connecty lines DrawDebugLine(InWorld, TopEnd + Radius*XAxis, BottomEnd + Radius*XAxis, Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, TopEnd - Radius*XAxis, BottomEnd - Radius*XAxis, Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, TopEnd + Radius*YAxis, BottomEnd + Radius*YAxis, Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, TopEnd - Radius*YAxis, BottomEnd - Radius*YAxis, Color, bPersistentLines, LifeTime, DepthPriority); } }
/** * Set current transform and the relative to ParentTransform. * Equates to This = This->GetRelativeTransform(Parent), but saves the intermediate FTransform storage and copy. */ void FTransform::SetToRelativeTransform(const FTransform& ParentTransform) { // A * B(-1) = VQS(B)(-1) (VQS (A)) // // Scale = S(A)/S(B) // Rotation = Q(B)(-1) * Q(A) // Translation = 1/S(B) *[Q(B)(-1)*(T(A)-T(B))*Q(B)] // where A = this, B = Other #if DEBUG_INVERSE_TRANSFORM FMatrix AM = ToMatrixWithScale(); FMatrix BM = ParentTransform.ToMatrixWithScale(); #endif checkSlow(ParentTransform.IsRotationNormalized()); // Scale = S(A)/S(B) VectorRegister VSafeScale3D = VectorSet_W0(GetSafeScaleReciprocal(ParentTransform.Scale3D)); Scale3D = VectorMultiply(Scale3D, VSafeScale3D); //VQTranslation = ( ( T(A).X - T(B).X ), ( T(A).Y - T(B).Y ), ( T(A).Z - T(B).Z), 0.f ); VectorRegister VQTranslation = VectorSet_W0(VectorSubtract(Translation, ParentTransform.Translation)); // Translation = 1/S(B) *[Q(B)(-1)*(T(A)-T(B))*Q(B)] VectorRegister VInverseParentRot = VectorQuaternionInverse(ParentTransform.Rotation); VectorRegister VQT = VectorQuaternionMultiply2(VInverseParentRot, VQTranslation); VectorRegister VR = VectorQuaternionMultiply2(VQT, ParentTransform.Rotation); Translation = VectorMultiply(VR, VSafeScale3D); // Rotation = Q(B)(-1) * Q(A) Rotation = VectorQuaternionMultiply2(VInverseParentRot, Rotation ); DiagnosticCheckNaN_All(); #if DEBUG_INVERSE_TRANSFORM DebugEqualMatrix(AM * BM.InverseFast()); #endif }
void FEditorCommonDrawHelper::DrawGridSection(float ViewportGridY,FVector* A,FVector* B,float* AX,float* BX,int32 Axis,const FSceneView* View,FPrimitiveDrawInterface* PDI, const EAxisLines::Type LineType ) { if( ViewportGridY == 0 ) { // Don't draw zero-size grid return; } const FMatrix InvViewProjMatrix = View->ViewMatrices.ProjMatrix.Inverse() * View->ViewMatrices.ViewMatrix.Inverse(); int32 FirstLine = FMath::Trunc(InvViewProjMatrix.TransformPosition(FVector(-1,-1,0.5f)).Component(Axis) / ViewportGridY); int32 LastLine = FMath::Trunc(InvViewProjMatrix.TransformPosition(FVector(+1,+1,0.5f)).Component(Axis) / ViewportGridY); if( FirstLine > LastLine ) { Exchange(FirstLine,LastLine); } const float SizeX = View->ViewRect.Width(); const float Zoom = (1.0f / View->ViewMatrices.ProjMatrix.M[0][0]) * 2.0f / SizeX; const int32 Dist = FMath::Trunc(SizeX * Zoom / ViewportGridY); // Figure out alpha interpolator for fading in the grid lines. float Alpha; int32 IncBits=0; { if( Dist+Dist >= SizeX/4 ) { while( (Dist>>IncBits) >= SizeX/4 ) { IncBits++; } Alpha = 2 - 2*(float)Dist / (float)((1<<IncBits) * SizeX/4); } else { Alpha = 1.0; } }
virtual void _add(Real alpha, const FMatrix &mX, const ScalarAltMatrix &mA) override { if(alpha < 0) KQP_THROW_EXCEPTION(not_implemented_exception, "Downdating with accumulator"); // If there is nothing to add if (mA.cols() == 0) return; // Do a deep copy of mA combination_matrices.push_back(mA); alphas.push_back(Eigen::internal::sqrt(alpha)); fMatrix->add(mX); offsets_X.push_back(offsets_X.back() + mX->size()); offsets_A.push_back(offsets_A.back() + mA.cols()); }
/** * Set current transform and the relative to ParentTransform. * Equates to This = This->GetRelativeTransform(Parent), but saves the intermediate FTransform storage and copy. */ void FTransform::SetToRelativeTransform(const FTransform& ParentTransform) { // A * B(-1) = VQS(B)(-1) (VQS (A)) // // Scale = S(A)/S(B) // Rotation = Q(B)(-1) * Q(A) // Translation = 1/S(B) *[Q(B)(-1)*(T(A)-T(B))*Q(B)] // where A = this, B = Other #if DEBUG_INVERSE_TRANSFORM FMatrix AM = ToMatrixWithScale(); FMatrix BM = ParentTransform.ToMatrixWithScale(); #endif const FVector SafeRecipScale3D = GetSafeScaleReciprocal(ParentTransform.Scale3D); const FQuat InverseRot = ParentTransform.Rotation.Inverse(); Scale3D *= SafeRecipScale3D; Translation = (InverseRot * (Translation - ParentTransform.Translation)) * SafeRecipScale3D; Rotation = InverseRot * Rotation; #if DEBUG_INVERSE_TRANSFORM DebugEqualMatrix(AM * BM.InverseFast()); #endif }
void DrawTransformedRectangle( FRHICommandListImmediate& RHICmdList, float X, float Y, float SizeX, float SizeY, const FMatrix& PosTransform, float U, float V, float SizeU, float SizeV, const FMatrix& TexTransform, FIntPoint TargetSize, FIntPoint TextureSize ) { float ClipSpaceQuadZ = 0.0f; // we don't do the triangle optimization as this case is rare for the DrawTransformedRectangle case FFilterVertex Vertices[4]; Vertices[0].Position = PosTransform.TransformFVector4(FVector4(X, Y, ClipSpaceQuadZ, 1)); Vertices[1].Position = PosTransform.TransformFVector4(FVector4(X + SizeX, Y, ClipSpaceQuadZ, 1)); Vertices[2].Position = PosTransform.TransformFVector4(FVector4(X, Y + SizeY, ClipSpaceQuadZ, 1)); Vertices[3].Position = PosTransform.TransformFVector4(FVector4(X + SizeX, Y + SizeY, ClipSpaceQuadZ, 1)); Vertices[0].UV = FVector2D(TexTransform.TransformFVector4(FVector(U, V, 0))); Vertices[1].UV = FVector2D(TexTransform.TransformFVector4(FVector(U + SizeU, V, 0))); Vertices[2].UV = FVector2D(TexTransform.TransformFVector4(FVector(U, V + SizeV, 0))); Vertices[3].UV = FVector2D(TexTransform.TransformFVector4(FVector(U + SizeU, V + SizeV, 0))); for (int32 VertexIndex = 0; VertexIndex < 4; VertexIndex++) { Vertices[VertexIndex].Position.X = -1.0f + 2.0f * (Vertices[VertexIndex].Position.X) / (float)TargetSize.X; Vertices[VertexIndex].Position.Y = (+1.0f - 2.0f * (Vertices[VertexIndex].Position.Y) / (float)TargetSize.Y) * GProjectionSignY; Vertices[VertexIndex].UV.X = Vertices[VertexIndex].UV.X / (float)TextureSize.X; Vertices[VertexIndex].UV.Y = Vertices[VertexIndex].UV.Y / (float)TextureSize.Y; } static const uint16 Indices[] = { 0, 1, 3, 0, 3, 2 }; DrawIndexedPrimitiveUP(RHICmdList, PT_TriangleList, 0, 4, 2, Indices, sizeof(Indices[0]), Vertices, sizeof(Vertices[0])); }
void DrawFrustumWireframe( FPrimitiveDrawInterface* PDI, const FMatrix& FrustumToWorld, FColor Color, uint8 DepthPriority ) { FVector Vertices[2][2][2]; for(uint32 Z = 0;Z < 2;Z++) { for(uint32 Y = 0;Y < 2;Y++) { for(uint32 X = 0;X < 2;X++) { FVector4 UnprojectedVertex = FrustumToWorld.TransformFVector4( FVector4( (X ? -1.0f : 1.0f), (Y ? -1.0f : 1.0f), (Z ? 0.0f : 1.0f), 1.0f ) ); Vertices[X][Y][Z] = FVector(UnprojectedVertex) / UnprojectedVertex.W; } } } PDI->DrawLine(Vertices[0][0][0],Vertices[0][0][1],Color,DepthPriority); PDI->DrawLine(Vertices[1][0][0],Vertices[1][0][1],Color,DepthPriority); PDI->DrawLine(Vertices[0][1][0],Vertices[0][1][1],Color,DepthPriority); PDI->DrawLine(Vertices[1][1][0],Vertices[1][1][1],Color,DepthPriority); PDI->DrawLine(Vertices[0][0][0],Vertices[0][1][0],Color,DepthPriority); PDI->DrawLine(Vertices[1][0][0],Vertices[1][1][0],Color,DepthPriority); PDI->DrawLine(Vertices[0][0][1],Vertices[0][1][1],Color,DepthPriority); PDI->DrawLine(Vertices[1][0][1],Vertices[1][1][1],Color,DepthPriority); PDI->DrawLine(Vertices[0][0][0],Vertices[1][0][0],Color,DepthPriority); PDI->DrawLine(Vertices[0][1][0],Vertices[1][1][0],Color,DepthPriority); PDI->DrawLine(Vertices[0][0][1],Vertices[1][0][1],Color,DepthPriority); PDI->DrawLine(Vertices[0][1][1],Vertices[1][1][1],Color,DepthPriority); }
void DrawDebugFrustum(const UWorld* InWorld, const FMatrix& FrustumToWorld, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority) { // no debug line drawing on dedicated server if (GEngine->GetNetMode(InWorld) != NM_DedicatedServer) { FVector Vertices[2][2][2]; for(uint32 Z = 0;Z < 2;Z++) { for(uint32 Y = 0;Y < 2;Y++) { for(uint32 X = 0;X < 2;X++) { FVector4 UnprojectedVertex = FrustumToWorld.TransformFVector4( FVector4( (X ? -1.0f : 1.0f), (Y ? -1.0f : 1.0f), (Z ? 0.0f : 1.0f), 1.0f ) ); Vertices[X][Y][Z] = FVector(UnprojectedVertex) / UnprojectedVertex.W; } } } DrawDebugLine(InWorld, Vertices[0][0][0], Vertices[0][0][1],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[1][0][0], Vertices[1][0][1],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[0][1][0], Vertices[0][1][1],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[1][1][0], Vertices[1][1][1],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[0][0][0], Vertices[0][1][0],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[1][0][0], Vertices[1][1][0],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[0][0][1], Vertices[0][1][1],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[1][0][1], Vertices[1][1][1],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[0][0][0], Vertices[1][0][0],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[0][1][0], Vertices[1][1][0],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[0][0][1], Vertices[1][0][1],Color, bPersistentLines, LifeTime, DepthPriority); DrawDebugLine(InWorld, Vertices[0][1][1], Vertices[1][1][1],Color, bPersistentLines, LifeTime, DepthPriority); } }
void GetViewFrustumBounds(FConvexVolume& OutResult, const FMatrix& ViewProjectionMatrix, const FPlane& InFarPlane, bool bOverrideFarPlane, bool UseNearPlane) { OutResult.Planes.Empty( 6 ); FPlane Temp; // Near clipping plane. if(UseNearPlane && ViewProjectionMatrix.GetFrustumNearPlane(Temp)) { OutResult.Planes.Add(Temp); } // Left clipping plane. if(ViewProjectionMatrix.GetFrustumLeftPlane(Temp)) { OutResult.Planes.Add(Temp); } // Right clipping plane. if(ViewProjectionMatrix.GetFrustumRightPlane(Temp)) { OutResult.Planes.Add(Temp); } // Top clipping plane. if(ViewProjectionMatrix.GetFrustumTopPlane(Temp)) { OutResult.Planes.Add(Temp); } // Bottom clipping plane. if(ViewProjectionMatrix.GetFrustumBottomPlane(Temp)) { OutResult.Planes.Add(Temp); } // Far clipping plane. if (bOverrideFarPlane) { OutResult.Planes.Add(InFarPlane); } else if(ViewProjectionMatrix.GetFrustumFarPlane(Temp)) { OutResult.Planes.Add(Temp); } OutResult.Init(); }
void AAmethystCharacter::OnCameraUpdate(const FVector& CameraLocation, const FRotator& CameraRotation) { USkeletalMeshComponent* DefMesh1P = Cast<USkeletalMeshComponent>(GetClass()->GetDefaultSubobjectByName(TEXT("PawnMesh1P"))); const FMatrix DefMeshLS = FRotationTranslationMatrix(DefMesh1P->RelativeRotation, DefMesh1P->RelativeLocation); const FMatrix LocalToWorld = ActorToWorld().ToMatrixWithScale(); // Mesh rotating code expect uniform scale in LocalToWorld matrix const FRotator RotCameraPitch(CameraRotation.Pitch, 0.0f, 0.0f); const FRotator RotCameraYaw(0.0f, CameraRotation.Yaw, 0.0f); const FMatrix LeveledCameraLS = FRotationTranslationMatrix(RotCameraYaw, CameraLocation) * LocalToWorld.Inverse(); const FMatrix PitchedCameraLS = FRotationMatrix(RotCameraPitch) * LeveledCameraLS; const FMatrix MeshRelativeToCamera = DefMeshLS * LeveledCameraLS.Inverse(); const FMatrix PitchedMesh = MeshRelativeToCamera * PitchedCameraLS; Mesh1P->SetRelativeLocationAndRotation(PitchedMesh.GetOrigin(), PitchedMesh.Rotator()); }
FBox FBox::TransformProjectBy(const FMatrix& ProjM) const { FVector Vertices[8] = { FVector(Min), FVector(Min.X, Min.Y, Max.Z), FVector(Min.X, Max.Y, Min.Z), FVector(Max.X, Min.Y, Min.Z), FVector(Max.X, Max.Y, Min.Z), FVector(Max.X, Min.Y, Max.Z), FVector(Min.X, Max.Y, Max.Z), FVector(Max) }; FBox NewBox(0); for (int32 VertexIndex = 0; VertexIndex < ARRAY_COUNT(Vertices); VertexIndex++) { FVector4 ProjectedVertex = ProjM.TransformPosition(Vertices[VertexIndex]); NewBox += ((FVector)ProjectedVertex) / ProjectedVertex.W; } return NewBox; }
void UCameraModifier_CameraShake::UpdateCameraShake(float DeltaTime, FCameraShakeInstance& Shake, FMinimalViewInfo& InOutPOV) { if (!Shake.SourceShake) { return; } // this is the base scale for the whole shake, anim and oscillation alike float const BaseShakeScale = GetShakeScale(Shake); // do not update if percentage is null if (BaseShakeScale <= 0.f) { return; } // update anims with any desired scaling if (Shake.AnimInst) { Shake.AnimInst->TransientScaleModifier *= BaseShakeScale; } // update oscillation times if (Shake.OscillatorTimeRemaining > 0.f) { Shake.OscillatorTimeRemaining -= DeltaTime; Shake.OscillatorTimeRemaining = FMath::Max(0.f, Shake.OscillatorTimeRemaining); } if (Shake.bBlendingIn) { Shake.CurrentBlendInTime += DeltaTime; } if (Shake.bBlendingOut) { Shake.CurrentBlendOutTime += DeltaTime; } // see if we've crossed any important time thresholds and deal appropriately bool bOscillationFinished = false; if (Shake.OscillatorTimeRemaining == 0.f) { // finished! bOscillationFinished = true; } else if (Shake.OscillatorTimeRemaining < 0.0f) { // indefinite shaking } else if (Shake.OscillatorTimeRemaining < Shake.SourceShake->OscillationBlendOutTime) { // start blending out Shake.bBlendingOut = true; Shake.CurrentBlendOutTime = Shake.SourceShake->OscillationBlendOutTime - Shake.OscillatorTimeRemaining; } if (Shake.bBlendingIn) { if (Shake.CurrentBlendInTime > Shake.SourceShake->OscillationBlendInTime) { // done blending in! Shake.bBlendingIn = false; } } if (Shake.bBlendingOut) { if (Shake.CurrentBlendOutTime > Shake.SourceShake->OscillationBlendOutTime) { // done!! Shake.CurrentBlendOutTime = Shake.SourceShake->OscillationBlendOutTime; bOscillationFinished = true; } } // calculate blend weight. calculating separately and taking the minimum handles overlapping blends nicely. float const BlendInWeight = (Shake.bBlendingIn) ? (Shake.CurrentBlendInTime / Shake.SourceShake->OscillationBlendInTime) : 1.f; float const BlendOutWeight = (Shake.bBlendingOut) ? (1.f - Shake.CurrentBlendOutTime / Shake.SourceShake->OscillationBlendOutTime) : 1.f; float const CurrentBlendWeight = FMath::Min(BlendInWeight, BlendOutWeight); // Do not update oscillation further if finished if (bOscillationFinished) { return; } // this is the oscillation scale, which includes oscillation fading float const OscillationScale = GetShakeScale(Shake) * CurrentBlendWeight; if (OscillationScale > 0.f) { // View location offset, compute sin wave value for each component FVector LocOffset = FVector(0); LocOffset.X = UpdateFOscillator(Shake.SourceShake->LocOscillation.X, Shake.LocSinOffset.X, DeltaTime); LocOffset.Y = UpdateFOscillator(Shake.SourceShake->LocOscillation.Y, Shake.LocSinOffset.Y, DeltaTime); LocOffset.Z = UpdateFOscillator(Shake.SourceShake->LocOscillation.Z, Shake.LocSinOffset.Z, DeltaTime); LocOffset *= OscillationScale; // View rotation offset, compute sin wave value for each component FRotator RotOffset; RotOffset.Pitch = UpdateFOscillator(Shake.SourceShake->RotOscillation.Pitch, Shake.RotSinOffset.X, DeltaTime) * OscillationScale; RotOffset.Yaw = UpdateFOscillator(Shake.SourceShake->RotOscillation.Yaw, Shake.RotSinOffset.Y, DeltaTime) * OscillationScale; RotOffset.Roll = UpdateFOscillator(Shake.SourceShake->RotOscillation.Roll, Shake.RotSinOffset.Z, DeltaTime) * OscillationScale; if (Shake.PlaySpace == CAPS_CameraLocal) { // the else case will handle this as well, but this is the faster, cleaner, most common code path // apply loc offset relative to camera orientation FRotationMatrix CamRotMatrix(InOutPOV.Rotation); InOutPOV.Location += CamRotMatrix.TransformVector(LocOffset); // apply rot offset relative to camera orientation FRotationMatrix const AnimRotMat( RotOffset ); InOutPOV.Rotation = (AnimRotMat * FRotationMatrix(InOutPOV.Rotation)).Rotator(); } else { // find desired space FMatrix const PlaySpaceToWorld = (Shake.PlaySpace == CAPS_UserDefined) ? Shake.UserPlaySpaceMatrix : FMatrix::Identity; // apply loc offset relative to desired space InOutPOV.Location += PlaySpaceToWorld.TransformVector( LocOffset ); // apply rot offset relative to desired space // find transform from camera to the "play space" FRotationMatrix const CamToWorld(InOutPOV.Rotation); FMatrix const CameraToPlaySpace = CamToWorld * PlaySpaceToWorld.InverseSafe(); // CameraToWorld * WorldToPlaySpace // find transform from anim (applied in playspace) back to camera FRotationMatrix const AnimToPlaySpace(RotOffset); FMatrix const AnimToCamera = AnimToPlaySpace * CameraToPlaySpace.InverseSafe(); // AnimToPlaySpace * PlaySpaceToCamera // RCS = rotated camera space, meaning camera space after it's been animated // this is what we're looking for, the diff between rotated cam space and regular cam space. // apply the transform back to camera space from the post-animated transform to get the RCS FMatrix const RCSToCamera = CameraToPlaySpace * AnimToCamera; // now apply to real camera InOutPOV.Rotation = (RCSToCamera * CamToWorld).Rotator(); } // Compute FOV change InOutPOV.FOV += OscillationScale * UpdateFOscillator(Shake.SourceShake->FOVOscillation, Shake.FOVSinOffset, DeltaTime); } }
void FAnimNode_Trail::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer& RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms) { check(OutBoneTransforms.Num() == 0); if( ChainLength < 2 ) { return; } // The incoming BoneIndex is the 'end' of the spline chain. We need to find the 'start' by walking SplineLength bones up hierarchy. // Fail if we walk past the root bone. int32 WalkBoneIndex = TrailBone.BoneIndex; TArray<int32> ChainBoneIndices; ChainBoneIndices.AddZeroed(ChainLength); ChainBoneIndices[ChainLength - 1] = WalkBoneIndex; for (int32 i = 1; i < ChainLength; i++) { // returns to avoid a crash // @TODO : shows an error message why failed if (WalkBoneIndex == 0) { return; } // Get parent bone. WalkBoneIndex = RequiredBones.GetParentBoneIndex(WalkBoneIndex); //Insert indices at the start of array, so that parents are before children in the array. int32 TransformIndex = ChainLength - (i + 1); ChainBoneIndices[TransformIndex] = WalkBoneIndex; } OutBoneTransforms.AddZeroed(ChainLength); // If we have >0 this frame, but didn't last time, record positions of all the bones. // Also do this if number has changed or array is zero. bool bHasValidStrength = (Alpha > 0.f); if(TrailBoneLocations.Num() != ChainLength || (bHasValidStrength && !bHadValidStrength)) { TrailBoneLocations.Empty(); TrailBoneLocations.AddZeroed(ChainLength); for(int32 i=0; i<ChainBoneIndices.Num(); i++) { int32 ChildIndex = ChainBoneIndices[i]; FTransform ChainTransform = MeshBases.GetComponentSpaceTransform(ChildIndex); TrailBoneLocations[i] = ChainTransform.GetTranslation(); } OldLocalToWorld = SkelComp->GetTransformMatrix(); } bHadValidStrength = bHasValidStrength; // transform between last frame and now. FMatrix OldToNewTM = OldLocalToWorld * SkelComp->GetTransformMatrix().InverseFast(); // Add fake velocity if present to all but root bone if(!FakeVelocity.IsZero()) { FVector FakeMovement = -FakeVelocity * ThisTimstep; if (bActorSpaceFakeVel && SkelComp->GetOwner()) { const FTransform BoneToWorld(SkelComp->GetOwner()->GetActorRotation(), SkelComp->GetOwner()->GetActorLocation()); FakeMovement = BoneToWorld.TransformVector(FakeMovement); } FakeMovement = SkelComp->GetTransformMatrix().InverseTransformVector(FakeMovement); // Then add to each bone for(int32 i=1; i<TrailBoneLocations.Num(); i++) { TrailBoneLocations[i] += FakeMovement; } } // Root bone of trail is not modified. int32 RootIndex = ChainBoneIndices[0]; FTransform ChainTransform = MeshBases.GetComponentSpaceTransform(RootIndex); OutBoneTransforms[0] = FBoneTransform(RootIndex, ChainTransform); TrailBoneLocations[0] = ChainTransform.GetTranslation(); // Starting one below head of chain, move bones. for(int32 i=1; i<ChainBoneIndices.Num(); i++) { // Parent bone position in component space. int32 ParentIndex = ChainBoneIndices[i-1]; FVector ParentPos = TrailBoneLocations[i-1]; FVector ParentAnimPos = MeshBases.GetComponentSpaceTransform(ParentIndex).GetTranslation(); // Child bone position in component space. int32 ChildIndex = ChainBoneIndices[i]; FVector ChildPos = OldToNewTM.TransformPosition(TrailBoneLocations[i]); // move from 'last frames component' frame to 'this frames component' frame FVector ChildAnimPos = MeshBases.GetComponentSpaceTransform(ChildIndex).GetTranslation(); // Desired parent->child offset. FVector TargetDelta = (ChildAnimPos - ParentAnimPos); // Desired child position. FVector ChildTarget = ParentPos + TargetDelta; // Find vector from child to target FVector Error = ChildTarget - ChildPos; // Calculate how much to push the child towards its target float Correction = FMath::Clamp<float>(ThisTimstep * TrailRelaxation, 0.f, 1.f); // Scale correction vector and apply to get new world-space child position. TrailBoneLocations[i] = ChildPos + (Error * Correction); // If desired, prevent bones stretching too far. if(bLimitStretch) { float RefPoseLength = TargetDelta.Size(); FVector CurrentDelta = TrailBoneLocations[i] - TrailBoneLocations[i-1]; float CurrentLength = CurrentDelta.Size(); // If we are too far - cut it back (just project towards parent particle). if( (CurrentLength - RefPoseLength > StretchLimit) && CurrentLength > SMALL_NUMBER ) { FVector CurrentDir = CurrentDelta / CurrentLength; TrailBoneLocations[i] = TrailBoneLocations[i-1] + (CurrentDir * (RefPoseLength + StretchLimit)); } } // Modify child matrix OutBoneTransforms[i] = FBoneTransform(ChildIndex, MeshBases.GetComponentSpaceTransform(ChildIndex)); OutBoneTransforms[i].Transform.SetTranslation(TrailBoneLocations[i]); // Modify rotation of parent matrix to point at this one. // Calculate the direction that parent bone is currently pointing. FVector CurrentBoneDir = OutBoneTransforms[i-1].Transform.TransformVector( GetAlignVector(ChainBoneAxis, bInvertChainBoneAxis) ); CurrentBoneDir = CurrentBoneDir.SafeNormal(SMALL_NUMBER); // Calculate vector from parent to child. FVector NewBoneDir = FVector(OutBoneTransforms[i].Transform.GetTranslation() - OutBoneTransforms[i - 1].Transform.GetTranslation()).SafeNormal(SMALL_NUMBER); // Calculate a quaternion that gets us from our current rotation to the desired one. FQuat DeltaLookQuat = FQuat::FindBetween(CurrentBoneDir, NewBoneDir); FTransform DeltaTM( DeltaLookQuat, FVector(0.f) ); // Apply to the current parent bone transform. FTransform TmpMatrix = FTransform::Identity; TmpMatrix.CopyRotationPart(OutBoneTransforms[i - 1].Transform); TmpMatrix = TmpMatrix * DeltaTM; OutBoneTransforms[i - 1].Transform.CopyRotationPart(TmpMatrix); } // For the last bone in the chain, use the rotation from the bone above it. OutBoneTransforms[ChainLength - 1].Transform.CopyRotationPart(OutBoneTransforms[ChainLength - 2].Transform); // Update OldLocalToWorld OldLocalToWorld = SkelComp->GetTransformMatrix(); }
//trains a neural net void FBNN::train(const FMatrix & train_x, const FMatrix & train_y, const Opts & opts, const FMatrix & valid_x, const FMatrix & valid_y, const FBNN_ptr pFBNN) { int ibatchNum = train_x.rows() / opts.batchsize + (train_x.rows() % opts.batchsize != 0); FMatrix L = zeros(opts.numpochs * ibatchNum, 1); m_oLp = std::make_shared<FMatrix>(L); Loss loss; // std::cout << "numpochs = " << opts.numpochs << std::endl; for(int i = 0; i < opts.numpochs; ++i) { std::cout << "start numpochs " << i << std::endl; int elapsedTime = count_elapse_second([&train_x,&train_y,&L,&opts,i,pFBNN,ibatchNum,this]{ std::vector<int> iRandVec; randperm(train_x.rows(),iRandVec); std::cout << "start batch: "; for(int j = 0; j < ibatchNum; ++j) { std::cout << " " << j; if(pFBNN)//pull { // TMutex::scoped_lock lock; // lock.acquire(pFBNN->W_RWMutex,false); // lock.release();//reader lock tbb boost::shared_lock<RWMutex> rlock(pFBNN->W_RWMutex); set_m_oWs(pFBNN->get_m_oWs()); if(m_fMomentum > 0) set_m_oVWs(pFBNN->get_m_oVWs()); rlock.unlock(); } int curBatchSize = opts.batchsize; if(j == ibatchNum - 1 && train_x.rows() % opts.batchsize != 0) curBatchSize = train_x.rows() % opts.batchsize; FMatrix batch_x(curBatchSize,train_x.columns()); for(int r = 0; r < curBatchSize; ++r)//randperm() row(batch_x,r) = row(train_x,iRandVec[j * opts.batchsize + r]); //Add noise to input (for use in denoising autoencoder) if(m_fInputZeroMaskedFraction != 0) batch_x = bitWiseMul(batch_x,(rand(curBatchSize,train_x.columns())>m_fInputZeroMaskedFraction)); FMatrix batch_y(curBatchSize,train_y.columns()); for(int r = 0; r < curBatchSize; ++r)//randperm() row(batch_y,r) = row(train_y,iRandVec[j * opts.batchsize + r]); L(i*ibatchNum+j,0) = nnff(batch_x,batch_y); nnbp(); nnapplygrads(); if(pFBNN)//push { // TMutex::scoped_lock lock; // lock.acquire(W_RWMutex); // lock.release();//writer lock tbb boost::unique_lock<RWMutex> wlock(pFBNN->W_RWMutex); pFBNN->set_m_odWs(m_odWs); pFBNN->nnapplygrads(); wlock.unlock(); } // std::cout << "end batch " << j << std::endl; } std::cout << std::endl; }); std::cout << "elapsed time: " << elapsedTime << "s" << std::endl; //loss calculate use nneval if(valid_x.rows() == 0 || valid_y.rows() == 0){ nneval(loss, train_x, train_y); std::cout << "Full-batch train mse = " << loss.train_error.back() << std::endl; } else{ nneval(loss, train_x, train_y, valid_x, valid_y); std::cout << "Full-batch train mse = " << loss.train_error.back() << " , val mse = " << loss.valid_error.back() << std::endl; } std::cout << "epoch " << i+1 << " / " << opts.numpochs << " took " << elapsedTime << " seconds." << std::endl; std::cout << "Mini-batch mean squared error on training set is " << columnMean(submatrix(L,i*ibatchNum,0UL,ibatchNum,L.columns())) << std::endl; m_iLearningRate *= m_fScalingLearningRate; // std::cout << "end numpochs " << i << std::endl; } }
//NNFF performs a feedforward pass double FBNN::nnff(const FMatrix& x, const FMatrix& y) { // std::cout << "start nnff x = (" << x.rows() << "," << x.columns() << ")" << std::endl; double L = 0; if(m_oAs.empty()) { for(int i = 0; i < m_iN; ++i) m_oAs.push_back(std::make_shared<FMatrix>(FMatrix())); } *m_oAs[0] = addPreColumn(x,1); if(m_fDropoutFraction > 0 && !m_fTesting) { if(m_odOMs.empty())//clear dropOutMask { for(int i = 0; i < m_iN - 1; ++i) m_odOMs.push_back(std::make_shared<FMatrix>(FMatrix())); } } // std::cout << "start feedforward" << std::endl; //feedforward pass for(int i = 1; i < m_iN - 1; ++i) { // std::cout << "activation function" << std::endl; //activation function if(m_strActivationFunction == "sigm") { //Calculate the unit's outputs (including the bias term) *m_oAs[i] = sigm((*m_oAs[i-1]) * blaze::trans(*m_oWs[i-1])); } else if(m_strActivationFunction == "tanh_opt") { *m_oAs[i] = tanh_opt((*m_oAs[i-1]) * blaze::trans(*m_oWs[i-1])); } // std::cout << "dropout" << std::endl; //dropout if(m_fDropoutFraction > 0) { if(m_fTesting) *m_oAs[i] = (*m_oAs[i]) * (1 - m_fDropoutFraction); else { *m_odOMs[i] = rand(m_oAs[i]->rows(),m_oAs[i]->columns()) > m_fDropoutFraction; *m_oAs[i] = bitWiseMul(*m_oAs[i],*m_odOMs[i]); } } // std::cout << "sparsity" << std::endl; //calculate running exponential activations for use with sparsity if(m_fNonSparsityPenalty > 0) *m_oPs[i] = (*m_oPs[i]) * 0.99 + columnMean(*m_oAs[i]); // std::cout << "Add the bias term" << std::endl; //Add the bias term *m_oAs[i] = addPreColumn(*m_oAs[i],1); } // std::cout << "start calculate output" << std::endl; if(m_strOutput == "sigm") { *m_oAs[m_iN -1] = sigm((*m_oAs[m_iN-2]) * blaze::trans(*m_oWs[m_iN-2])); } else if(m_strOutput == "linear") { *m_oAs[m_iN -1] = (*m_oAs[m_iN-2]) * blaze::trans(*m_oWs[m_iN-2]); } else if(m_strOutput == "softmax") { *m_oAs[m_iN -1] = softmax((*m_oAs[m_iN-2]) * blaze::trans(*m_oWs[m_iN-2])); } // std::cout << "start error and loss" << std::endl; //error and loss m_oEp = std::make_shared<FMatrix>(y - (*m_oAs[m_iN-1])); if(m_strOutput == "sigm" || m_strOutput == "linear") { L = 0.5 * matrixSum(bitWiseSquare(*m_oEp)) / x.rows(); } else if(m_strOutput == "softmax") { L = -matrixSum(bitWiseMul(y,bitWiseLog(*m_oAs[m_iN-1]))) / x.rows(); } // std::cout << "end nnff" << std::endl; return L; }
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; } }
FMatrix FDecalRendering::ComputeComponentToClipMatrix(const FViewInfo& View, const FMatrix& DecalComponentToWorld) { FMatrix ComponentToWorldMatrixTrans = DecalComponentToWorld.ConcatTranslation(View.ViewMatrices.PreViewTranslation); return ComponentToWorldMatrixTrans * View.ViewMatrices.TranslatedViewProjectionMatrix; }
void DrawDebugCone(const UWorld* InWorld, FVector const& Origin, FVector const& Direction, float Length, float AngleWidth, float AngleHeight, int32 NumSides, FColor const& DrawColor, bool bPersistentLines, float LifeTime, uint8 DepthPriority) { // no debug line drawing on dedicated server if (GEngine->GetNetMode(InWorld) != NM_DedicatedServer) { // Need at least 4 sides NumSides = FMath::Max(NumSides, 4); const float Angle1 = FMath::Clamp<float>(AngleHeight, (float)KINDA_SMALL_NUMBER, (float)(PI - KINDA_SMALL_NUMBER)); const float Angle2 = FMath::Clamp<float>(AngleWidth, (float)KINDA_SMALL_NUMBER, (float)(PI - KINDA_SMALL_NUMBER)); const float SinX_2 = FMath::Sin(0.5f * Angle1); const float SinY_2 = FMath::Sin(0.5f * Angle2); const float SinSqX_2 = SinX_2 * SinX_2; const float SinSqY_2 = SinY_2 * SinY_2; const float TanX_2 = FMath::Tan(0.5f * Angle1); const float TanY_2 = FMath::Tan(0.5f * Angle2); TArray<FVector> ConeVerts; ConeVerts.AddUninitialized(NumSides); for(int32 i = 0; i < NumSides; i++) { const float Fraction = (float)i/(float)(NumSides); const float Thi = 2.f * PI * Fraction; const float Phi = FMath::Atan2(FMath::Sin(Thi)*SinY_2, FMath::Cos(Thi)*SinX_2); const float SinPhi = FMath::Sin(Phi); const float CosPhi = FMath::Cos(Phi); const float SinSqPhi = SinPhi*SinPhi; const float CosSqPhi = CosPhi*CosPhi; const float RSq = SinSqX_2*SinSqY_2 / (SinSqX_2*SinSqPhi + SinSqY_2*CosSqPhi); const float R = FMath::Sqrt(RSq); const float Sqr = FMath::Sqrt(1-RSq); const float Alpha = R*CosPhi; const float Beta = R*SinPhi; ConeVerts[i].X = (1 - 2*RSq); ConeVerts[i].Y = 2 * Sqr * Alpha; ConeVerts[i].Z = 2 * Sqr * Beta; } // Calculate transform for cone. FVector YAxis, ZAxis; FVector DirectionNorm = Direction.SafeNormal(); DirectionNorm.FindBestAxisVectors(YAxis, ZAxis); const FMatrix ConeToWorld = FScaleMatrix(FVector(Length)) * FMatrix(DirectionNorm, YAxis, ZAxis, Origin); // this means foreground lines can't be persistent ULineBatchComponent* const LineBatcher = GetDebugLineBatcher( InWorld, bPersistentLines, LifeTime, (DepthPriority == SDPG_Foreground) ); if(LineBatcher != NULL) { float const LineLifeTime = (LifeTime > 0.f) ? LifeTime : LineBatcher->DefaultLifeTime; TArray<FBatchedLine> Lines; Lines.Empty(NumSides); FVector CurrentPoint, PrevPoint, FirstPoint; for(int32 i = 0; i < NumSides; i++) { CurrentPoint = ConeToWorld.TransformPosition(ConeVerts[i]); Lines.Add(FBatchedLine(ConeToWorld.GetOrigin(), CurrentPoint, DrawColor, LineLifeTime, 0.0f, DepthPriority)); // PrevPoint must be defined to draw junctions if( i > 0 ) { Lines.Add(FBatchedLine(PrevPoint, CurrentPoint, DrawColor, LineLifeTime, 0.0f, DepthPriority)); } else { FirstPoint = CurrentPoint; } PrevPoint = CurrentPoint; } // Connect last junction to first Lines.Add(FBatchedLine(CurrentPoint, FirstPoint, DrawColor, LineLifeTime, 0.0f, DepthPriority)); LineBatcher->DrawLines(Lines); } } }
void APlayerCameraManager::ApplyAnimToCamera(ACameraActor const* AnimatedCamActor, UCameraAnimInst const* AnimInst, FMinimalViewInfo& InOutPOV) { if (AnimInst->CamAnim->bRelativeToInitialTransform) { // move animated cam actor to initial-relative position FTransform const AnimatedCamToWorld = AnimatedCamActor->GetTransform(); FTransform const AnimatedCamToInitialCam = AnimatedCamToWorld * AnimInst->InitialCamToWorld.Inverse(); ACameraActor* const MutableCamActor = const_cast<ACameraActor*>(AnimatedCamActor); MutableCamActor->SetActorTransform(AnimatedCamToInitialCam); } float const Scale = AnimInst->CurrentBlendWeight; FRotationMatrix const CameraToWorld(InOutPOV.Rotation); if (AnimInst->PlaySpace == ECameraAnimPlaySpace::CameraLocal) { // the code in the else block will handle this just fine, but this path provides efficiency and simplicity for the most common case // loc FVector const LocalOffset = CameraToWorld.TransformVector( AnimatedCamActor->GetActorLocation()*Scale ); InOutPOV.Location += LocalOffset; // rot FRotationMatrix const AnimRotMat( AnimatedCamActor->GetActorRotation()*Scale ); InOutPOV.Rotation = (AnimRotMat * CameraToWorld).Rotator(); } else { // handle playing the anim in an arbitrary space relative to the camera // find desired space FMatrix const PlaySpaceToWorld = (AnimInst->PlaySpace == ECameraAnimPlaySpace::UserDefined) ? AnimInst->UserPlaySpaceMatrix : FMatrix::Identity; // loc FVector const LocalOffset = PlaySpaceToWorld.TransformVector( AnimatedCamActor->GetActorLocation()*Scale ); InOutPOV.Location += LocalOffset; // rot // find transform from camera to the "play space" FMatrix const CameraToPlaySpace = CameraToWorld * PlaySpaceToWorld.Inverse(); // CameraToWorld * WorldToPlaySpace // find transform from anim (applied in playspace) back to camera FRotationMatrix const AnimToPlaySpace(AnimatedCamActor->GetActorRotation()*Scale); FMatrix const AnimToCamera = AnimToPlaySpace * CameraToPlaySpace.Inverse(); // AnimToPlaySpace * PlaySpaceToCamera // RCS = rotated camera space, meaning camera space after it's been animated // this is what we're looking for, the diff between rotated cam space and regular cam space. // apply the transform back to camera space from the post-animated transform to get the RCS FMatrix const RCSToCamera = CameraToPlaySpace * AnimToCamera; // now apply to real camera FRotationMatrix const RealCamToWorld(InOutPOV.Rotation); InOutPOV.Rotation = (RCSToCamera * RealCamToWorld).Rotator(); } // fov const float FOVMin = 5.f; const float FOVMax = 170.f; InOutPOV.FOV += (AnimatedCamActor->GetCameraComponent()->FieldOfView - AnimInst->InitialFOV) * Scale; InOutPOV.FOV = FMath::Clamp<float>(InOutPOV.FOV, FOVMin, FOVMax); // postprocess if (AnimatedCamActor->GetCameraComponent()->PostProcessBlendWeight > 0.f) { AddCachedPPBlend(AnimatedCamActor->GetCameraComponent()->PostProcessSettings, AnimatedCamActor->GetCameraComponent()->PostProcessBlendWeight); } }
void UTexAlignerFit::AlignSurf( ETexAlign InTexAlignType, UModel* InModel, FBspSurfIdx* InSurfIdx, FPoly* InPoly, FVector* InNormal ) { // @todo: Support cycling between texture corners by FIT'ing again? Each Ctrl+Shift+F would rotate texture. // @todo: Consider making initial FIT match the texture's current orientation as close as possible? // @todo: Handle subtractive brush polys differently? (flip U texture direction) // @todo: Option to ignore pixel aspect for quads (e.g. stretch full texture non-uniformly over quad) // Compute world space vertex positions TArray< FVector > WorldSpacePolyVertices; for( int32 VertexIndex = 0; VertexIndex < InPoly->Vertices.Num(); ++VertexIndex ) { WorldSpacePolyVertices.Add( InSurfIdx->Surf->Actor->ActorToWorld().TransformPosition( InPoly->Vertices[ VertexIndex ] ) ); } // Create an orthonormal basis for the polygon FMatrix WorldToPolyRotationMatrix; const FVector& FirstPolyVertex = WorldSpacePolyVertices[ 0 ]; { const FVector& VertexA = FirstPolyVertex; const FVector& VertexB = WorldSpacePolyVertices[ 1 ]; FVector UpVec = ( VertexB - VertexA ).GetSafeNormal(); FVector RightVec = InPoly->Normal ^ UpVec; WorldToPolyRotationMatrix.SetIdentity(); WorldToPolyRotationMatrix.SetAxes( &RightVec, &UpVec, &InPoly->Normal ); } // Find a corner of the polygon that's closest to a 90 degree angle. When there are multiple corners with // similar angles, we'll use the one closest to the local space bottom-left along the polygon's plane const float DesiredAbsDotProduct = 0.0f; int32 BestVertexIndex = INDEX_NONE; float BestDotProductDiff = 10000.0f; float BestPositivity = 10000.0f; for( int32 VertexIndex = 0; VertexIndex < WorldSpacePolyVertices.Num(); ++VertexIndex ) { // Compute the previous and next vertex in the winding const int32 PrevWindingVertexIndex = ( VertexIndex > 0 ) ? ( VertexIndex - 1 ) : ( WorldSpacePolyVertices.Num() - 1 ); const int32 NextWindingVertexIndex = ( VertexIndex < WorldSpacePolyVertices.Num() - 1 ) ? ( VertexIndex + 1 ) : 0; const FVector& PrevVertex = WorldSpacePolyVertices[ PrevWindingVertexIndex ]; const FVector& CurVertex = WorldSpacePolyVertices[ VertexIndex ]; const FVector& NextVertex = WorldSpacePolyVertices[ NextWindingVertexIndex ]; // Compute the corner angle float AbsDotProduct = FMath::Abs( ( PrevVertex - CurVertex ).GetSafeNormal() | ( NextVertex - CurVertex ).GetSafeNormal() ); // Compute how 'positive' this vertex is relative to the bottom left position in the polygon's plane FVector PolySpaceVertex = WorldToPolyRotationMatrix.InverseTransformVector( CurVertex - FirstPolyVertex ); const float Positivity = PolySpaceVertex.X + PolySpaceVertex.Y; // Is the corner angle closer to 90 degrees than our current best? const float DotProductDiff = FMath::Abs( AbsDotProduct - DesiredAbsDotProduct ); if( FMath::IsNearlyEqual( DotProductDiff, BestDotProductDiff, 0.1f ) ) { // This angle is just as good as the current best, so check to see which is closer to the local space // bottom-left along the polygon's plane if( Positivity < BestPositivity ) { // This vertex is in a more suitable location for the bottom-left of the texture BestVertexIndex = VertexIndex; if( DotProductDiff < BestDotProductDiff ) { // Only store the new dot product if it's actually better than the existing one BestDotProductDiff = DotProductDiff; } BestPositivity = Positivity; } } else if( DotProductDiff <= BestDotProductDiff ) { // This angle is definitely better! BestVertexIndex = VertexIndex; BestDotProductDiff = DotProductDiff; BestPositivity = Positivity; } } // Compute orthonormal basis for the 'best corner' of the polygon. The texture will be positioned at the corner // of the bounds of the poly in this coordinate system const FVector& BestVertex = WorldSpacePolyVertices[ BestVertexIndex ]; const int32 NextWindingVertexIndex = ( BestVertexIndex < WorldSpacePolyVertices.Num() - 1 ) ? ( BestVertexIndex + 1 ) : 0; const FVector& NextVertex = WorldSpacePolyVertices[ NextWindingVertexIndex ]; FVector TextureUpVec = ( NextVertex - BestVertex ).GetSafeNormal(); FVector TextureRightVec = InPoly->Normal ^ TextureUpVec; FMatrix WorldToTextureRotationMatrix; WorldToTextureRotationMatrix.SetIdentity(); WorldToTextureRotationMatrix.SetAxes( &TextureRightVec, &TextureUpVec, &InPoly->Normal ); // Compute bounds of polygon along plane float MinX = FLT_MAX; float MaxX = -FLT_MAX; float MinY = FLT_MAX; float MaxY = -FLT_MAX; for( int32 VertexIndex = 0; VertexIndex < WorldSpacePolyVertices.Num(); ++VertexIndex ) { const FVector& CurVertex = WorldSpacePolyVertices[ VertexIndex ]; // Transform vertex into the coordinate system of our texture FVector TextureSpaceVertex = WorldToTextureRotationMatrix.InverseTransformVector( CurVertex - BestVertex ); if( TextureSpaceVertex.X < MinX ) { MinX = TextureSpaceVertex.X; } if( TextureSpaceVertex.X > MaxX ) { MaxX = TextureSpaceVertex.X; } if( TextureSpaceVertex.Y < MinY ) { MinY = TextureSpaceVertex.Y; } if( TextureSpaceVertex.Y > MaxY ) { MaxY = TextureSpaceVertex.Y; } } // We'll use the texture space corner of the bounds as the origin of the texture. This ensures that // the texture fits over the entire polygon without revealing any tiling const FVector TextureSpaceBasePos( MinX, MinY, 0.0f ); FVector WorldSpaceBasePos = WorldToTextureRotationMatrix.TransformVector( TextureSpaceBasePos ) + BestVertex; // Apply scale to UV vectors. We incorporate the parameterized tiling rations and scale by our texture size const float WorldTexelScale = UModel::GetGlobalBSPTexelScale(); const float TextureSizeU = FMath::Abs( MaxX - MinX ); const float TextureSizeV = FMath::Abs( MaxY - MinY ); FVector TextureUVector = UTile * TextureRightVec * WorldTexelScale / TextureSizeU; FVector TextureVVector = VTile * TextureUpVec * WorldTexelScale / TextureSizeV; // Flip the texture vertically if we want that const bool bFlipVertically = true; if( bFlipVertically ) { WorldSpaceBasePos += TextureUpVec * TextureSizeV; TextureVVector *= -1.0f; } // Apply texture base position { const bool bExactMatch = false; InSurfIdx->Surf->pBase = FBSPOps::bspAddPoint( InModel, const_cast< FVector* >( &WorldSpaceBasePos ), bExactMatch ); } // Apply texture UV vectors { const bool bExactMatch = false; InSurfIdx->Surf->vTextureU = FBSPOps::bspAddVector( InModel, const_cast< FVector* >( &TextureUVector ), bExactMatch ); InSurfIdx->Surf->vTextureV = FBSPOps::bspAddVector( InModel, const_cast< FVector* >( &TextureVVector ), bExactMatch ); } }
void FDecalRendering::BuildVisibleDecalList(const FScene& Scene, const FViewInfo& View, EDecalRenderStage DecalRenderStage, FTransientDecalRenderDataList& OutVisibleDecals) { QUICK_SCOPE_CYCLE_COUNTER(BuildVisibleDecalList); OutVisibleDecals.Empty(Scene.Decals.Num()); const float FadeMultiplier = CVarDecalFadeScreenSizeMultiplier.GetValueOnRenderThread(); const EShaderPlatform ShaderPlatform = View.GetShaderPlatform(); const bool bIsPerspectiveProjection = View.IsPerspectiveProjection(); // Build a list of decals that need to be rendered for this view in SortedDecals for (const FDeferredDecalProxy* DecalProxy : Scene.Decals) { bool bIsShown = true; if (!DecalProxy->IsShown(&View)) { bIsShown = false; } const FMatrix ComponentToWorldMatrix = DecalProxy->ComponentTrans.ToMatrixWithScale(); // can be optimized as we test against a sphere around the box instead of the box itself const float ConservativeRadius = FMath::Sqrt( ComponentToWorldMatrix.GetScaledAxis(EAxis::X).SizeSquared() + ComponentToWorldMatrix.GetScaledAxis(EAxis::Y).SizeSquared() + ComponentToWorldMatrix.GetScaledAxis(EAxis::Z).SizeSquared()); // can be optimized as the test is too conservative (sphere instead of OBB) if(ConservativeRadius < SMALL_NUMBER || !View.ViewFrustum.IntersectSphere(ComponentToWorldMatrix.GetOrigin(), ConservativeRadius)) { bIsShown = false; } if (bIsShown) { FTransientDecalRenderData Data(Scene, DecalProxy, ConservativeRadius); // filter out decals with blend modes that are not supported on current platform if (IsBlendModeSupported(ShaderPlatform, Data.DecalBlendMode)) { if (bIsPerspectiveProjection && Data.DecalProxy->Component->FadeScreenSize != 0.0f) { float Distance = (View.ViewMatrices.ViewOrigin - ComponentToWorldMatrix.GetOrigin()).Size(); float Radius = ComponentToWorldMatrix.GetMaximumAxisScale(); float CurrentScreenSize = ((Radius / Distance) * FadeMultiplier); // fading coefficient needs to increase with increasing field of view and decrease with increasing resolution // FadeCoeffScale is an empirically determined constant to bring us back roughly to fraction of screen size for FadeScreenSize const float FadeCoeffScale = 600.0f; float FOVFactor = ((2.0f/View.ViewMatrices.ProjMatrix.M[0][0]) / View.ViewRect.Width()) * FadeCoeffScale; float FadeCoeff = Data.DecalProxy->Component->FadeScreenSize * FOVFactor; float FadeRange = FadeCoeff * 0.5f; float Alpha = (CurrentScreenSize - FadeCoeff) / FadeRange; Data.FadeAlpha = FMath::Min(Alpha, 1.0f); } EDecalRenderStage LocalDecalRenderStage = FDecalRenderingCommon::ComputeRenderStage(ShaderPlatform, Data.DecalBlendMode); // we could do this test earlier to avoid the decal intersection but getting DecalBlendMode also costs if (View.Family->EngineShowFlags.ShaderComplexity || (DecalRenderStage == LocalDecalRenderStage && Data.FadeAlpha>0.0f) ) { OutVisibleDecals.Add(Data); } } } } if (OutVisibleDecals.Num() > 0) { // Sort by sort order to allow control over composited result // Then sort decals by state to reduce render target switches // Also sort by component since Sort() is not stable struct FCompareFTransientDecalRenderData { FORCEINLINE bool operator()(const FTransientDecalRenderData& A, const FTransientDecalRenderData& B) const { if (B.DecalProxy->SortOrder != A.DecalProxy->SortOrder) { return A.DecalProxy->SortOrder < B.DecalProxy->SortOrder; } // bHasNormal here is more important then blend mode because we want to render every decals that output normals before those that read normal. if (B.bHasNormal != A.bHasNormal) { return B.bHasNormal < A.bHasNormal; // < so that those outputting normal are first. } if (B.DecalBlendMode != A.DecalBlendMode) { return (int32)B.DecalBlendMode < (int32)A.DecalBlendMode; } // Batch decals with the same material together if (B.MaterialProxy != A.MaterialProxy) { return B.MaterialProxy < A.MaterialProxy; } return (PTRINT)B.DecalProxy->Component < (PTRINT)A.DecalProxy->Component; } }; // Sort decals by blend mode to reduce render target switches OutVisibleDecals.Sort(FCompareFTransientDecalRenderData()); } }
void FGridWidget::DrawNewGrid(const FSceneView* View, FPrimitiveDrawInterface* PDI) { if (LevelGridMaterial->IsCompilingOrHadCompileError(View->GetFeatureLevel()) || LevelGridMaterial2->IsCompilingOrHadCompileError(View->GetFeatureLevel())) { // The material would appear to be black (because we don't use a MaterialDomain but a UsageFlag - we should change that). // Here we rather want to hide it. return; } bool bUseTextureSolution = CVarEditorNewLevelGrid.GetValueOnGameThread() > 1; UMaterialInstanceDynamic *MaterialInst = bUseTextureSolution ? LevelGridMaterialInst2 : LevelGridMaterialInst; if(!MaterialInst) { return; } bool bMSAA = IsEditorCompositingMSAAEnabled(View->GetFeatureLevel()); bool bIsPerspective = ( View->ViewMatrices.ProjMatrix.M[3][3] < 1.0f ); // in unreal units float SnapGridSize = GEditor->GetGridSize(); // not used yet const bool bSnapEnabled = GetDefault<ULevelEditorViewportSettings>()->GridEnabled; float SnapAlphaMultiplier = 1.0f; // to get a light grid in a black level but use a high opacity value to be able to see it in a bright level static float Darken = 0.11f; static FName GridColorName("GridColor"); static FName SnapColorName("SnapColor"); static FName ExponentName("Exponent"); static FName AlphaBiasName("AlphaBias"); if(bIsPerspective) { MaterialInst->SetVectorParameterValue(GridColorName, FLinearColor(0.6f * Darken, 0.6f * Darken, 0.6f * Darken, CVarEditor3DGridFade.GetValueOnGameThread())); MaterialInst->SetVectorParameterValue(SnapColorName, FLinearColor(0.5f, 0.0f, 0.0f, SnapAlphaMultiplier * CVarEditor3DSnapFade.GetValueOnGameThread())); } else { MaterialInst->SetVectorParameterValue(GridColorName, FLinearColor(0.6f * Darken, 0.6f * Darken, 0.6f * Darken, CVarEditor2DGridFade.GetValueOnGameThread())); MaterialInst->SetVectorParameterValue(SnapColorName, FLinearColor(0.5f, 0.0f, 0.0f, SnapAlphaMultiplier * CVarEditor2DSnapFade.GetValueOnGameThread())); } // true:1m, false:1dm ios smallest grid size bool bLarger1mGrid = true; const int Exponent = 10; // 2 is the default so we need to set it MaterialInst->SetScalarParameterValue(ExponentName, (float)Exponent); // without MSAA we need the grid to be more see through so lines behind it can be recognized MaterialInst->SetScalarParameterValue(AlphaBiasName, bMSAA ? 0.0f : 0.05f); // grid for size float GridSplit = 0.5f; // red dots to visualize the snap float SnapSplit = 0.075f; float WorldToUVScale = 0.001f; if(bLarger1mGrid) { WorldToUVScale *= 0.1f; GridSplit *= 0.1f; } // in 2D all grid lines are same size in world space (they are at different scale so we need to adjust here) FLinearColor GridSplitTriple(GridSplit * 0.01f, GridSplit * 0.1f, GridSplit); if(bIsPerspective) { // largest grid lines GridSplitTriple.R *= 8.0f; // medium grid lines GridSplitTriple.G *= 3.0f; // fine grid lines GridSplitTriple.B *= 1.0f; } if(!bIsPerspective) { // screenspace size looks better in 2d float ScaleX = View->ViewMatrices.ProjMatrix.M[0][0] * View->ViewRect.Width(); float ScaleY = View->ViewMatrices.ProjMatrix.M[1][1] * View->ViewRect.Height(); float Scale = FMath::Min(ScaleX, ScaleY); float GridScale = CVarEditor2DSnapScale.GetValueOnGameThread(); float GridMin = CVarEditor2DSnapMin.GetValueOnGameThread(); // we need to account for a larger grids setting SnapSplit = 1.25f * FMath::Min(GridScale / SnapGridSize / Scale, GridMin); // hack test GridSplitTriple.R = 0.25f * FMath::Min(GridScale / 100 / Scale * 0.01f, GridMin); GridSplitTriple.G = 0.25f * FMath::Min(GridScale / 100 / Scale * 0.1f, GridMin); GridSplitTriple.B = 0.25f * FMath::Min(GridScale / 100 / Scale, GridMin); } float SnapTile = (1.0f / WorldToUVScale) / FMath::Max(1.0f, SnapGridSize); MaterialInst->SetVectorParameterValue("GridSplit", GridSplitTriple); MaterialInst->SetScalarParameterValue("SnapSplit", SnapSplit); MaterialInst->SetScalarParameterValue("SnapTile", SnapTile); FMatrix ObjectToWorld = FMatrix::Identity; FVector CameraPos = View->ViewMatrices.ViewOrigin; FVector2D UVCameraPos = FVector2D(CameraPos.X, CameraPos.Y); ObjectToWorld.SetOrigin(FVector(CameraPos.X, CameraPos.Y, 0)); FLinearColor AxisColors[3]; GetAxisColors(AxisColors, true); FLinearColor UAxisColor = AxisColors[1]; FLinearColor VAxisColor = AxisColors[0]; if(!bIsPerspective) { float FarZ = 100000.0f; if(View->ViewMatrices.ViewMatrix.M[1][1] == -1.f ) // Top { ObjectToWorld.SetOrigin(FVector(CameraPos.X, CameraPos.Y, -FarZ)); } if(View->ViewMatrices.ViewMatrix.M[1][2] == -1.f ) // Front { UVCameraPos = FVector2D(CameraPos.Z, CameraPos.X); ObjectToWorld.SetAxis(0, FVector(0,0,1)); ObjectToWorld.SetAxis(1, FVector(1,0,0)); ObjectToWorld.SetAxis(2, FVector(0,1,0)); ObjectToWorld.SetOrigin(FVector(CameraPos.X, -FarZ, CameraPos.Z)); UAxisColor = AxisColors[0]; VAxisColor = AxisColors[2]; } else if(View->ViewMatrices.ViewMatrix.M[1][0] == 1.f ) // Side { UVCameraPos = FVector2D(CameraPos.Y, CameraPos.Z); ObjectToWorld.SetAxis(0, FVector(0,1,0)); ObjectToWorld.SetAxis(1, FVector(0,0,1)); ObjectToWorld.SetAxis(2, FVector(1,0,0)); ObjectToWorld.SetOrigin(FVector(FarZ, CameraPos.Y, CameraPos.Z)); UAxisColor = AxisColors[2]; VAxisColor = AxisColors[1]; } } MaterialInst->SetVectorParameterValue("UAxisColor", UAxisColor); MaterialInst->SetVectorParameterValue("VAxisColor", VAxisColor); // We don't want to affect the mouse interaction. PDI->SetHitProxy(0); // good enough to avoid the AMD artifacts, horizon still appears to be a line float Radii = 100000; if(bIsPerspective) { // the higher we get the larger we make the geometry to give the illusion of an infinite grid while maintains the precision nearby Radii *= FMath::Max( 1.0f, FMath::Abs(CameraPos.Z) / 1000.0f ); } else { float ScaleX = View->ViewMatrices.ProjMatrix.M[0][0]; float ScaleY = View->ViewMatrices.ProjMatrix.M[1][1]; float Scale = FMath::Min(ScaleX, ScaleY); Scale *= View->ViewRect.Width(); // We render a larger grid if we are zoomed out more (good precision at any scale) Radii *= 1.0f / Scale; } FVector2D UVMid = UVCameraPos * WorldToUVScale; float UVRadi = Radii * WorldToUVScale; FVector2D UVMin = UVMid + FVector2D(-UVRadi, -UVRadi); FVector2D UVMax = UVMid + FVector2D(UVRadi, UVRadi); // vertex pos is in -1..1 range DrawPlane10x10(PDI, ObjectToWorld, Radii, UVMin, UVMax, MaterialInst->GetRenderProxy(false), SDPG_World ); }
void UParticleModuleVelocityOverLifetime::Update(FParticleEmitterInstance* Owner, int32 Offset, float DeltaTime) { check(Owner && Owner->Component); UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); check(LODLevel); FVector OwnerScale(1.0f); if ((bApplyOwnerScale == true) && Owner->Component) { OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); } if (Absolute) { if (LODLevel->RequiredModule->bUseLocalSpace == false) { if (bInWorldSpace == false) { FVector Vel; const FMatrix LocalToWorld = Owner->Component->ComponentToWorld.ToMatrixNoScale(); BEGIN_UPDATE_LOOP; { Vel = VelOverLife.GetValue(Particle.RelativeTime, Owner->Component); Particle.Velocity = LocalToWorld.TransformVector(Vel) * OwnerScale; } END_UPDATE_LOOP; } else { BEGIN_UPDATE_LOOP; { Particle.Velocity = VelOverLife.GetValue(Particle.RelativeTime, Owner->Component) * OwnerScale; } END_UPDATE_LOOP; } } else { if (bInWorldSpace == false) { BEGIN_UPDATE_LOOP; { Particle.Velocity = VelOverLife.GetValue(Particle.RelativeTime, Owner->Component) * OwnerScale; } END_UPDATE_LOOP; } else { FVector Vel; const FMatrix LocalToWorld = Owner->Component->ComponentToWorld.ToMatrixNoScale(); const FMatrix InvMat = LocalToWorld.InverseFast(); BEGIN_UPDATE_LOOP; { Vel = VelOverLife.GetValue(Particle.RelativeTime, Owner->Component); Particle.Velocity = InvMat.TransformVector(Vel) * OwnerScale; } END_UPDATE_LOOP; } } } else { if (LODLevel->RequiredModule->bUseLocalSpace == false) { FVector Vel; if (bInWorldSpace == false) { const FMatrix LocalToWorld = Owner->Component->ComponentToWorld.ToMatrixNoScale(); BEGIN_UPDATE_LOOP; { Vel = VelOverLife.GetValue(Particle.RelativeTime, Owner->Component); Particle.Velocity *= LocalToWorld.TransformVector(Vel) * OwnerScale; } END_UPDATE_LOOP; } else { BEGIN_UPDATE_LOOP; { Particle.Velocity *= VelOverLife.GetValue(Particle.RelativeTime, Owner->Component) * OwnerScale; } END_UPDATE_LOOP; } } else { if (bInWorldSpace == false) { BEGIN_UPDATE_LOOP; { Particle.Velocity *= VelOverLife.GetValue(Particle.RelativeTime, Owner->Component) * OwnerScale; } END_UPDATE_LOOP; } else { FVector Vel; const FMatrix LocalToWorld = Owner->Component->ComponentToWorld.ToMatrixNoScale(); const FMatrix InvMat = LocalToWorld.InverseFast(); BEGIN_UPDATE_LOOP; { Vel = VelOverLife.GetValue(Particle.RelativeTime, Owner->Component); Particle.Velocity *= InvMat.TransformVector(Vel) * OwnerScale; } END_UPDATE_LOOP; } } } }
void FSimpleHMD::PushViewCanvas(EStereoscopicPass StereoPass, FCanvas *InCanvas, UCanvas *InCanvasObject, FSceneView *InView) const { FMatrix m; m.SetIdentity(); InCanvas->PushAbsoluteTransform(m); }
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 FLightSceneProxy::SetTransform(const FMatrix& InLightToWorld,const FVector4& InPosition) { LightToWorld = InLightToWorld; WorldToLight = InLightToWorld.InverseFast(); Position = InPosition; }
void FEditorCommonDrawHelper::DrawGridSection(float ViewportGridY,FVector* A,FVector* B,float* AX,float* BX,int32 Axis,const FSceneView* View,FPrimitiveDrawInterface* PDI ) { if( ViewportGridY == 0 ) { // Don't draw zero-size grid return; } // todo int32 Exponent = GEditor->IsGridSizePowerOfTwo() ? 8 : 10; const float SizeX = View->ViewRect.Width(); const float Zoom = (1.0f / View->ViewMatrices.ProjMatrix.M[0][0]) * 2.0f / SizeX; const float Dist = SizeX * Zoom / ViewportGridY; // when the grid fades static float Tweak = 4.0f; float IncValue = FMath::LogX(Exponent, Dist / (float)(SizeX / Tweak)); int32 IncScale = 1; for(float x = 0; x < IncValue; ++x) { IncScale *= Exponent; } if (IncScale == 0) { // Prevent divide by zero return; } // 0 excluded for hard transitions .. 0.5f for very soft transitions const float TransitionRegion = 0.5f; const float InvTransitionRegion = 1.0f / TransitionRegion; float Fract = IncValue - floorf(IncValue); float AlphaA = FMath::Clamp(Fract * InvTransitionRegion, 0.0f, 1.0f); float AlphaB = FMath::Clamp(InvTransitionRegion - Fract * InvTransitionRegion, 0.0f, 1.0f); if(IncValue < -0.5f) { // no fade in magnification case AlphaA = 1.0f; AlphaB = 1.0f; } const int32 MajorLineInterval = GEditor->GetGridInterval(); const FLinearColor Background = View->BackgroundColor; FLinearColor MajorColor = FMath::Lerp(Background, FLinearColor::White, 0.05f); FLinearColor MinorColor = FMath::Lerp(Background, FLinearColor::White, 0.02f); const FMatrix InvViewProjMatrix = View->ViewMatrices.ProjMatrix.InverseFast() * View->ViewMatrices.ViewMatrix.InverseFast(); int32 FirstLine = FMath::TruncToInt(InvViewProjMatrix.TransformPosition(FVector(-1, -1, 0.5f)).Component(Axis) / ViewportGridY); int32 LastLine = FMath::TruncToInt(InvViewProjMatrix.TransformPosition(FVector(+1, +1, 0.5f)).Component(Axis) / ViewportGridY); if (FirstLine > LastLine) { Exchange(FirstLine, LastLine); } // Draw major and minor grid lines const int32 FirstLineClamped = FMath::Max<int32>(FirstLine - 1,-HALF_WORLD_MAX/ViewportGridY) / IncScale; const int32 LastLineClamped = FMath::Min<int32>(LastLine + 1, +HALF_WORLD_MAX/ViewportGridY) / IncScale; for( int32 LineIndex = FirstLineClamped; LineIndex <= LastLineClamped; ++LineIndex ) { *AX = FPlatformMath::TruncToFloat(LineIndex * ViewportGridY) * IncScale; *BX = FPlatformMath::TruncToFloat(LineIndex * ViewportGridY) * IncScale; // Only minor lines fade out with ortho zoom distance. Origin lines and major lines are drawn // at 100% opacity, but with a brighter value const bool bIsMajorLine = (LineIndex % MajorLineInterval) == 0; { // Don't bother drawing the world origin line. We'll do that later. const bool bIsOriginLine = ( LineIndex == 0 ); if( !bIsOriginLine ) { FLinearColor Color; if( bIsMajorLine ) { Color = FMath::Lerp( Background, MajorColor, AlphaA ); } else { Color = FMath::Lerp( Background, MinorColor, AlphaB ); } PDI->DrawLine(*A,*B,Color,SDPG_World); } } } }
void UKismetMathLibrary::MinimumAreaRectangle(class UObject* WorldContextObject, const TArray<FVector>& InVerts, const FVector& SampleSurfaceNormal, FVector& OutRectCenter, FRotator& OutRectRotation, float& OutSideLengthX, float& OutSideLengthY, bool bDebugDraw) { float MinArea = -1.f; float CurrentArea = -1.f; FVector SupportVectorA, SupportVectorB; FVector RectSideA, RectSideB; float MinDotResultA, MinDotResultB, MaxDotResultA, MaxDotResultB; FVector TestEdge; float TestEdgeDot = 0.f; FVector PolyNormal(0.f, 0.f, 1.f); TArray<int32> PolyVertIndices; // Bail if we receive an empty InVerts array if( InVerts.Num() == 0 ) { return; } // Compute the approximate normal of the poly, using the direction of SampleSurfaceNormal for guidance PolyNormal = (InVerts[InVerts.Num() / 3] - InVerts[0]) ^ (InVerts[InVerts.Num() * 2 / 3] - InVerts[InVerts.Num() / 3]); if( (PolyNormal | SampleSurfaceNormal) < 0.f ) { PolyNormal = -PolyNormal; } // Transform the sample points to 2D FMatrix SurfaceNormalMatrix = FRotationMatrix::MakeFromZX(PolyNormal, FVector(1.f, 0.f, 0.f)); TArray<FVector> TransformedVerts; OutRectCenter = FVector(0.f); for( int32 Idx = 0; Idx < InVerts.Num(); ++Idx ) { OutRectCenter += InVerts[Idx]; TransformedVerts.Add(SurfaceNormalMatrix.InverseTransformVector(InVerts[Idx])); } OutRectCenter /= InVerts.Num(); // Compute the convex hull of the sample points ConvexHull2D::ComputeConvexHull(TransformedVerts, PolyVertIndices); // Minimum area rectangle as computed by http://www.geometrictools.com/Documentation/MinimumAreaRectangle.pdf for( int32 Idx = 1; Idx < PolyVertIndices.Num() - 1; ++Idx ) { SupportVectorA = (TransformedVerts[PolyVertIndices[Idx]] - TransformedVerts[PolyVertIndices[Idx-1]]).SafeNormal(); SupportVectorA.Z = 0.f; SupportVectorB.X = -SupportVectorA.Y; SupportVectorB.Y = SupportVectorA.X; SupportVectorB.Z = 0.f; MinDotResultA = MinDotResultB = MaxDotResultA = MaxDotResultB = 0.f; for (int TestVertIdx = 1; TestVertIdx < PolyVertIndices.Num(); ++TestVertIdx ) { TestEdge = TransformedVerts[PolyVertIndices[TestVertIdx]] - TransformedVerts[PolyVertIndices[0]]; TestEdgeDot = SupportVectorA | TestEdge; if( TestEdgeDot < MinDotResultA ) { MinDotResultA = TestEdgeDot; } else if(TestEdgeDot > MaxDotResultA ) { MaxDotResultA = TestEdgeDot; } TestEdgeDot = SupportVectorB | TestEdge; if( TestEdgeDot < MinDotResultB ) { MinDotResultB = TestEdgeDot; } else if( TestEdgeDot > MaxDotResultB ) { MaxDotResultB = TestEdgeDot; } } CurrentArea = (MaxDotResultA - MinDotResultA) * (MaxDotResultB - MinDotResultB); if( MinArea < 0.f || CurrentArea < MinArea ) { MinArea = CurrentArea; RectSideA = SupportVectorA * (MaxDotResultA - MinDotResultA); RectSideB = SupportVectorB * (MaxDotResultB - MinDotResultB); } } RectSideA = SurfaceNormalMatrix.TransformVector(RectSideA); RectSideB = SurfaceNormalMatrix.TransformVector(RectSideB); OutRectRotation = FRotationMatrix::MakeFromZX(PolyNormal, RectSideA).Rotator(); OutSideLengthX = RectSideA.Size(); OutSideLengthY = RectSideB.Size(); if( bDebugDraw ) { DrawDebugSphere(GEngine->GetWorldFromContextObject(WorldContextObject), OutRectCenter, 10.f, 12, FColor::Yellow, true); DrawDebugCoordinateSystem(GEngine->GetWorldFromContextObject(WorldContextObject), OutRectCenter, SurfaceNormalMatrix.Rotator(), 100.f, true); DrawDebugLine(GEngine->GetWorldFromContextObject(WorldContextObject), OutRectCenter - RectSideA * 0.5f + FVector(0,0,10.f), OutRectCenter + RectSideA * 0.5f + FVector(0,0,10.f), FColor::Green, true,-1, 0, 5.f); DrawDebugLine(GEngine->GetWorldFromContextObject(WorldContextObject), OutRectCenter - RectSideB * 0.5f + FVector(0,0,10.f), OutRectCenter + RectSideB * 0.5f + FVector(0,0,10.f), FColor::Blue, true,-1, 0, 5.f); } }
void UCameraAnimInst::ApplyToView(FMinimalViewInfo& InOutPOV) const { if (CurrentBlendWeight > 0.f) { ACameraActor const* AnimatedCamActor = dynamic_cast<ACameraActor*>(InterpGroupInst->GetGroupActor()); if (AnimatedCamActor) { if (CamAnim->bRelativeToInitialTransform) { // move animated cam actor to initial-relative position FTransform const AnimatedCamToWorld = AnimatedCamActor->GetTransform(); FTransform const AnimatedCamToInitialCam = AnimatedCamToWorld * InitialCamToWorld.Inverse(); ACameraActor* const MutableCamActor = const_cast<ACameraActor*>(AnimatedCamActor); MutableCamActor->SetActorTransform(AnimatedCamToInitialCam); } float const Scale = CurrentBlendWeight; FRotationMatrix const CameraToWorld(InOutPOV.Rotation); if (PlaySpace == ECameraAnimPlaySpace::CameraLocal) { // the code in the else block will handle this just fine, but this path provides efficiency and simplicity for the most common case // loc FVector const LocalOffset = CameraToWorld.TransformVector(AnimatedCamActor->GetActorLocation()*Scale); InOutPOV.Location += LocalOffset; // rot FRotationMatrix const AnimRotMat(AnimatedCamActor->GetActorRotation()*Scale); InOutPOV.Rotation = (AnimRotMat * CameraToWorld).Rotator(); } else { // handle playing the anim in an arbitrary space relative to the camera // find desired space FMatrix const PlaySpaceToWorld = (PlaySpace == ECameraAnimPlaySpace::UserDefined) ? UserPlaySpaceMatrix : FMatrix::Identity; // loc FVector const LocalOffset = PlaySpaceToWorld.TransformVector(AnimatedCamActor->GetActorLocation()*Scale); InOutPOV.Location += LocalOffset; // rot // find transform from camera to the "play space" FMatrix const CameraToPlaySpace = CameraToWorld * PlaySpaceToWorld.Inverse(); // CameraToWorld * WorldToPlaySpace // find transform from anim (applied in playspace) back to camera FRotationMatrix const AnimToPlaySpace(AnimatedCamActor->GetActorRotation()*Scale); FMatrix const AnimToCamera = AnimToPlaySpace * CameraToPlaySpace.Inverse(); // AnimToPlaySpace * PlaySpaceToCamera // RCS = rotated camera space, meaning camera space after it's been animated // this is what we're looking for, the diff between rotated cam space and regular cam space. // apply the transform back to camera space from the post-animated transform to get the RCS FMatrix const RCSToCamera = CameraToPlaySpace * AnimToCamera; // now apply to real camera FRotationMatrix const RealCamToWorld(InOutPOV.Rotation); InOutPOV.Rotation = (RCSToCamera * RealCamToWorld).Rotator(); } // fov if (bHasFOVTrack) { const float FOVMin = 5.f; const float FOVMax = 170.f; // Interp the FOV toward the camera component's FOV based on Scale if (CamAnim->bRelativeToInitialFOV) { InOutPOV.FOV += (AnimatedCamActor->GetCameraComponent()->FieldOfView - InitialFOV) * Scale; } else { const int32 DesiredDirection = FMath::Sign(AnimatedCamActor->GetCameraComponent()->FieldOfView - InOutPOV.FOV); const int32 InitialDirection = FMath::Sign(AnimatedCamActor->GetCameraComponent()->FieldOfView - InitialFOV); if (DesiredDirection != InitialDirection) { InOutPOV.FOV = FMath::Clamp(InOutPOV.FOV + ((AnimatedCamActor->GetCameraComponent()->FieldOfView - InOutPOV.FOV) * Scale), InOutPOV.FOV, AnimatedCamActor->GetCameraComponent()->FieldOfView); } else { InOutPOV.FOV = FMath::Clamp(InOutPOV.FOV + ((AnimatedCamActor->GetCameraComponent()->FieldOfView - InitialFOV) * Scale), AnimatedCamActor->GetCameraComponent()->FieldOfView, InitialFOV); } } InOutPOV.FOV = FMath::Clamp<float>(InOutPOV.FOV, FOVMin, FOVMax); } } } }
void FRCPassPostProcessDeferredDecals::Process(FRenderingCompositePassContext& Context) { FRHICommandListImmediate& RHICmdList = Context.RHICmdList; FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList); const bool bShaderComplexity = Context.View.Family->EngineShowFlags.ShaderComplexity; const bool bDBuffer = IsDBufferEnabled(); const bool bStencilSizeThreshold = CVarStencilSizeThreshold.GetValueOnRenderThread() >= 0; SCOPED_DRAW_EVENTF(RHICmdList, DeferredDecals, TEXT("DeferredDecals %s"), GetStageName(CurrentStage)); if (CurrentStage == DRS_BeforeBasePass) { // before BasePass, only if DBuffer is enabled check(bDBuffer); FPooledRenderTargetDesc GBufferADesc; SceneContext.GetGBufferADesc(GBufferADesc); // DBuffer: Decal buffer FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(GBufferADesc.Extent, PF_B8G8R8A8, FClearValueBinding::None, TexCreate_None, TexCreate_ShaderResource | TexCreate_RenderTargetable, false, 1, true, true)); if (!SceneContext.DBufferA) { Desc.ClearValue = FClearValueBinding::Black; GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferA, TEXT("DBufferA")); } if (!SceneContext.DBufferB) { Desc.ClearValue = FClearValueBinding(FLinearColor(128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f, 1)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferB, TEXT("DBufferB")); } Desc.Format = PF_R8G8; if (!SceneContext.DBufferC) { Desc.ClearValue = FClearValueBinding(FLinearColor(0, 1, 0, 1)); GRenderTargetPool.FindFreeElement(RHICmdList, Desc, SceneContext.DBufferC, TEXT("DBufferC")); } // we assume views are non overlapping, then we need to clear only once in the beginning, otherwise we would need to set scissor rects // and don't get FastClear any more. bool bFirstView = Context.View.Family->Views[0] == &Context.View; if (bFirstView) { SCOPED_DRAW_EVENT(RHICmdList, DBufferClear); FRHIRenderTargetView RenderTargets[3]; RenderTargets[0] = FRHIRenderTargetView(SceneContext.DBufferA->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); RenderTargets[1] = FRHIRenderTargetView(SceneContext.DBufferB->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); RenderTargets[2] = FRHIRenderTargetView(SceneContext.DBufferC->GetRenderTargetItem().TargetableTexture, 0, -1, ERenderTargetLoadAction::EClear, ERenderTargetStoreAction::EStore); FRHIDepthRenderTargetView DepthView(SceneContext.GetSceneDepthTexture(), ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, ERenderTargetLoadAction::ELoad, ERenderTargetStoreAction::ENoAction, FExclusiveDepthStencil(FExclusiveDepthStencil::DepthRead_StencilWrite)); FRHISetRenderTargetsInfo Info(3, RenderTargets, DepthView); RHICmdList.SetRenderTargetsAndClear(Info); } } // this cast is safe as only the dedicated server implements this differently and this pass should not be executed on the dedicated server const FViewInfo& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); bool bHasValidDBufferMask = false; if(ViewFamily.EngineShowFlags.Decals) { if(CurrentStage == DRS_BeforeBasePass || CurrentStage == DRS_BeforeLighting) { RenderMeshDecals(Context, CurrentStage); } FScene& Scene = *(FScene*)ViewFamily.Scene; //don't early return. Resolves must be run for fast clears to work. if (Scene.Decals.Num()) { FDecalRenderTargetManager RenderTargetManager(RHICmdList, Context.GetShaderPlatform(), CurrentStage); // Build a list of decals that need to be rendered for this view FTransientDecalRenderDataList SortedDecals; FDecalRendering::BuildVisibleDecalList(Scene, View, CurrentStage, SortedDecals); if (SortedDecals.Num() > 0) { SCOPED_DRAW_EVENTF(RHICmdList, DeferredDecalsInner, TEXT("DeferredDecalsInner %d/%d"), SortedDecals.Num(), Scene.Decals.Num()); // optimization to have less state changes EDecalRasterizerState LastDecalRasterizerState = DRS_Undefined; FDecalDepthState LastDecalDepthState; int32 LastDecalBlendMode = -1; int32 LastDecalHasNormal = -1; // Decal state can change based on its normal property.(SM5) FDecalRenderingCommon::ERenderTargetMode LastRenderTargetMode = FDecalRenderingCommon::RTM_Unknown; const ERHIFeatureLevel::Type SMFeatureLevel = Context.GetFeatureLevel(); SCOPED_DRAW_EVENT(RHICmdList, Decals); INC_DWORD_STAT_BY(STAT_Decals, SortedDecals.Num()); for (int32 DecalIndex = 0, DecalCount = SortedDecals.Num(); DecalIndex < DecalCount; DecalIndex++) { const FTransientDecalRenderData& DecalData = SortedDecals[DecalIndex]; const FDeferredDecalProxy& DecalProxy = *DecalData.DecalProxy; const FMatrix ComponentToWorldMatrix = DecalProxy.ComponentTrans.ToMatrixWithScale(); const FMatrix FrustumComponentToClip = FDecalRendering::ComputeComponentToClipMatrix(View, ComponentToWorldMatrix); EDecalBlendMode DecalBlendMode = DecalData.DecalBlendMode; EDecalRenderStage LocalDecalStage = FDecalRenderingCommon::ComputeRenderStage(View.GetShaderPlatform(), DecalBlendMode); bool bStencilThisDecal = IsStencilOptimizationAvailable(LocalDecalStage); FDecalRenderingCommon::ERenderTargetMode CurrentRenderTargetMode = FDecalRenderingCommon::ComputeRenderTargetMode(View.GetShaderPlatform(), DecalBlendMode, DecalData.bHasNormal); if (bShaderComplexity) { CurrentRenderTargetMode = FDecalRenderingCommon::RTM_SceneColor; // we want additive blending for the ShaderComplexity mode DecalBlendMode = DBM_Emissive; } // Here we assume that GBuffer can only be WorldNormal since it is the only GBufferTarget handled correctly. if (RenderTargetManager.bGufferADirty && DecalData.MaterialResource->NeedsGBuffer()) { RHICmdList.CopyToResolveTarget(SceneContext.GBufferA->GetRenderTargetItem().TargetableTexture, SceneContext.GBufferA->GetRenderTargetItem().TargetableTexture, true, FResolveParams()); RenderTargetManager.TargetsToResolve[FDecalRenderTargetManager::GBufferAIndex] = nullptr; RenderTargetManager.bGufferADirty = false; } // fewer rendertarget switches if possible if (CurrentRenderTargetMode != LastRenderTargetMode) { LastRenderTargetMode = CurrentRenderTargetMode; RenderTargetManager.SetRenderTargetMode(CurrentRenderTargetMode, DecalData.bHasNormal); Context.SetViewportAndCallRHI(Context.View.ViewRect); } bool bThisDecalUsesStencil = false; if (bStencilThisDecal && bStencilSizeThreshold) { // note this is after a SetStreamSource (in if CurrentRenderTargetMode != LastRenderTargetMode) call as it needs to get the VB input bThisDecalUsesStencil = RenderPreStencil(Context, ComponentToWorldMatrix, FrustumComponentToClip); LastDecalRasterizerState = DRS_Undefined; LastDecalDepthState = FDecalDepthState(); LastDecalBlendMode = -1; } const bool bBlendStateChange = DecalBlendMode != LastDecalBlendMode;// Has decal mode changed. const bool bDecalNormalChanged = GSupportsSeparateRenderTargetBlendState && // has normal changed for SM5 stain/translucent decals? (DecalBlendMode == DBM_Translucent || DecalBlendMode == DBM_Stain) && (int32)DecalData.bHasNormal != LastDecalHasNormal; // fewer blend state changes if possible if (bBlendStateChange || bDecalNormalChanged) { LastDecalBlendMode = DecalBlendMode; LastDecalHasNormal = (int32)DecalData.bHasNormal; SetDecalBlendState(RHICmdList, SMFeatureLevel, CurrentStage, (EDecalBlendMode)LastDecalBlendMode, DecalData.bHasNormal); } // todo const float ConservativeRadius = DecalData.ConservativeRadius; // const int32 IsInsideDecal = ((FVector)View.ViewMatrices.ViewOrigin - ComponentToWorldMatrix.GetOrigin()).SizeSquared() < FMath::Square(ConservativeRadius * 1.05f + View.NearClippingDistance * 2.0f) + ( bThisDecalUsesStencil ) ? 2 : 0; const bool bInsideDecal = ((FVector)View.ViewMatrices.ViewOrigin - ComponentToWorldMatrix.GetOrigin()).SizeSquared() < FMath::Square(ConservativeRadius * 1.05f + View.NearClippingDistance * 2.0f); // const bool bInsideDecal = !(IsInsideDecal & 1); // update rasterizer state if needed { bool bReverseHanded = false; { // Account for the reversal of handedness caused by negative scale on the decal const auto& Scale3d = DecalProxy.ComponentTrans.GetScale3D(); bReverseHanded = Scale3d[0] * Scale3d[1] * Scale3d[2] < 0.f; } EDecalRasterizerState DecalRasterizerState = ComputeDecalRasterizerState(bInsideDecal, bReverseHanded, View); if (LastDecalRasterizerState != DecalRasterizerState) { LastDecalRasterizerState = DecalRasterizerState; SetDecalRasterizerState(DecalRasterizerState, RHICmdList); } } // update DepthStencil state if needed { FDecalDepthState DecalDepthState = ComputeDecalDepthState(LocalDecalStage, bInsideDecal, bThisDecalUsesStencil); if (LastDecalDepthState != DecalDepthState) { LastDecalDepthState = DecalDepthState; SetDecalDepthState(DecalDepthState, RHICmdList); } } FDecalRendering::SetShader(RHICmdList, View, DecalData, FrustumComponentToClip); RHICmdList.DrawIndexedPrimitive(GetUnitCubeIndexBuffer(), PT_TriangleList, 0, 0, 8, 0, ARRAY_COUNT(GCubeIndices) / 3, 1); RenderTargetManager.bGufferADirty |= (RenderTargetManager.TargetsToResolve[FDecalRenderTargetManager::GBufferAIndex] != nullptr); } // we don't modify stencil but if out input was having stencil for us (after base pass - we need to clear) // Clear stencil to 0, which is the assumed default by other passes RHICmdList.Clear(false, FLinearColor::White, false, (float)ERHIZBuffer::FarPlane, true, 0, FIntRect()); } if (CurrentStage == DRS_BeforeBasePass) { // combine DBuffer RTWriteMasks; will end up in one texture we can load from in the base pass PS and decide whether to do the actual work or not RenderTargetManager.FlushMetaData(); if (GSupportsRenderTargetWriteMask) { DecodeRTWriteMask(Context); bHasValidDBufferMask = true; } } RenderTargetManager.ResolveTargets(); } if (CurrentStage == DRS_BeforeBasePass) { // before BasePass GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.DBufferA); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.DBufferB); GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.DBufferC); } } if (CurrentStage == DRS_BeforeBasePass && !bHasValidDBufferMask) { // Return the DBufferMask to the render target pool. // FDeferredPixelShaderParameters will fall back to setting a white dummy mask texture. // This allows us to ignore the DBufferMask on frames without decals, without having to explicitly clear the texture. SceneContext.DBufferMask = nullptr; } }