//----------------------------------------------------------------------// // DEBUG //----------------------------------------------------------------------// FString UAISense_Sight::GetDebugLegend() const { static const FColor SightColor = GetDebugSightRangeColor(); static const FColor LoseSightColor = GetDebugLoseSightColor(); return FString::Printf(TEXT("{%s} Sight, {%s} Lose Sight,"), *SightColor.ToString(), *LoseSightColor.ToString()); }
void FTileRenderer::DrawTile(FRHICommandListImmediate& RHICmdList, const class FSceneView& View, const FMaterialRenderProxy* MaterialRenderProxy, bool bNeedsToSwitchVerticalAxis, float X, float Y, float SizeX, float SizeY, float U, float V, float SizeU, float SizeV, bool bIsHitTesting, const FHitProxyId HitProxyId, const FColor InVertexColor) { FMaterialTileVertex DestVertex[4]; // create verts if (bNeedsToSwitchVerticalAxis) { DestVertex[0].Initialize(X + SizeX, View.ViewRect.Height() - (Y + SizeY), U + SizeU, V + SizeV); DestVertex[1].Initialize(X, View.ViewRect.Height() - (Y + SizeY), U, V + SizeV); DestVertex[2].Initialize(X + SizeX, View.ViewRect.Height() - Y, U + SizeU, V); DestVertex[3].Initialize(X, View.ViewRect.Height() - Y, U, V); } else { DestVertex[0].Initialize(X + SizeX, Y, U + SizeU, V); DestVertex[1].Initialize(X, Y, U, V); DestVertex[2].Initialize(X + SizeX, Y + SizeY, U + SizeU, V + SizeV); DestVertex[3].Initialize(X, Y + SizeY, U, V + SizeV); } DestVertex[0].Color = InVertexColor.DWColor(); DestVertex[1].Color = InVertexColor.DWColor(); DestVertex[2].Color = InVertexColor.DWColor(); DestVertex[3].Color = InVertexColor.DWColor(); // update the FMeshBatch FMeshBatch& Mesh = GTileMesh.MeshElement; Mesh.UseDynamicData = true; Mesh.DynamicVertexData = DestVertex; Mesh.MaterialRenderProxy = MaterialRenderProxy; GetRendererModule().DrawTileMesh(RHICmdList, View, Mesh, bIsHitTesting, HitProxyId); }
void UPaperTerrainComponent::PostLoad() { Super::PostLoad(); const int32 PaperVer = GetLinkerCustomVersion(FPaperCustomVersion::GUID); if (PaperVer < FPaperCustomVersion::FixVertexColorSpace) { const FColor SRGBColor = TerrainColor.ToFColor(/*bSRGB=*/ true); TerrainColor = SRGBColor.ReinterpretAsLinear(); } }
FColor HSB::hsbFromRgb(const FColor& rgb) { const auto brightness = max( max(RGB::red(rgb), RGB::green(rgb)), RGB::blue(rgb)); auto hue = 0.0f, saturation = 0.0f; if (not near(brightness, 0.0)) { const auto darkest = min( min(RGB::red(rgb), RGB::green(rgb)), RGB::blue(rgb)); const auto range = brightness - darkest; saturation = range / brightness; if (not near(saturation, 0.0)) { const float r = (brightness - RGB::red(rgb)) / range; const float g = (brightness - RGB::green(rgb)) / range; const float b = (brightness - RGB::blue(rgb)) / range; if (near(RGB::red(rgb), brightness)) hue = b - g; else if (near(RGB::green(rgb), brightness)) hue = 2.0f + r - b; else hue = 4.0f + g - r; hue /= 6.0f; if (hue < 0) hue += 1.0f; } } return FColor(hue, saturation, brightness, rgb.alpha()); }
bool ParseTag(FColor& OutColor) { FString TagString; EStringParserToken Token = ReadToken(); for (; Token != EStringParserToken::EndOfString && Token != EStringParserToken::CloseTag; Token = ReadToken()) { if (Token == EStringParserToken::RegularChar) { TagString.AppendChar(DataString[DataIndex]); } DataIndex++; } bool bResult = false; if (Token == EStringParserToken::CloseTag) { const FString TagColorLower = TagString.ToLower(); const bool bIsColorName = GColorList.IsValidColorName(*TagColorLower); if (bIsColorName) { OutColor = GColorList.GetFColorByName(*TagColorLower); bResult = true; } else { bResult = OutColor.InitFromString(TagString); } } return bResult; }
void BatchRenderer::DrawSolidTriangle3D( const Vec3D& a, const Vec3D& b, const Vec3D& c, const FColor& color ) { const U4 rgbaColor = color.ToRGBA32(); SetBatchState( this, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); const UINT iBaseVertex = self->batchedVertices.Num(); Vertex & v0 = self->batchedVertices.Add(); Vertex & v1 = self->batchedVertices.Add(); Vertex & v2 = self->batchedVertices.Add(); v0.xyz.x = a.x; v0.xyz.y = a.y; v0.xyz.z = a.z; v0.rgba.asU32 = rgbaColor; v1.xyz.x = b.x; v1.xyz.y = b.y; v1.xyz.z = b.z; v1.rgba.asU32 = rgbaColor; v2.xyz.x = c.x; v2.xyz.y = c.y; v2.xyz.z = c.z; v2.rgba.asU32 = rgbaColor; self->batchedIndices.Add( iBaseVertex + 0 ); self->batchedIndices.Add( iBaseVertex + 1 ); self->batchedIndices.Add( iBaseVertex + 2 ); }
uint32 ParseTag( FString& OutData ) { FString TagString; int32 OryginalIndex = Index; uint8 token = ReadToken(); while (token != EndOfString && token != CloseTag) { if (token == RegularChar) { TagString.AppendChar(DataString[Index++]); } token = ReadToken(); } int OutTag = ErrorTag; if (token != CloseTag) { Index = OryginalIndex; OutData = FString::Printf( TEXT("{%s"), *TagString); OutData.AppendChar(DataString[Index-1]); return OutTag; } if (GColorList.IsValidColorName(*TagString.ToLower())) { OutTag = DefinedColor; OutData = TagString; } else { FColor Color; if (Color.InitFromString(TagString)) { OutTag = OtherColor; OutData = TagString; } else { OutTag = ErrorTag; OutData = FString::Printf( TEXT("{%s"), *TagString); OutData.AppendChar(DataString[Index-1]); } } //Index++; return OutTag; }
void FD3DGPUProfiler::PushEvent(const TCHAR* Name, FColor Color) { #if WITH_DX_PERF D3DPERF_BeginEvent(Color.DWColor(), Name); #endif FGPUProfiler::PushEvent(Name, Color); }
void FColorStructCustomization::OnSetColorFromColorPicker( FLinearColor NewColor ) { FString ColorString; if( bIsLinearColor ) { ColorString = NewColor.ToString(); } else { // Handled by the color picker const bool bSRGB = false; FColor NewFColor = NewColor.ToFColor(bSRGB); ColorString = NewFColor.ToString(); } StructPropertyHandle->SetValueFromFormattedString( ColorString, bIsInteractive ? EPropertyValueSetFlags::InteractiveChange : 0 ); }
void FColorStructCustomization::CreateColorPicker( bool bUseAlpha, bool bOnlyRefreshOnOk ) { int32 NumObjects = StructPropertyHandle->GetNumOuterObjects(); SavedPreColorPickerColors.Empty(); TArray<FString> PerObjectValues; StructPropertyHandle->GetPerObjectValues( PerObjectValues ); for( int32 ObjectIndex = 0; ObjectIndex < NumObjects; ++ObjectIndex ) { if( bIsLinearColor ) { FLinearColor Color; Color.InitFromString( PerObjectValues[ObjectIndex] ); SavedPreColorPickerColors.Add( Color ); } else { FColor Color; Color.InitFromString( PerObjectValues[ObjectIndex] ); SavedPreColorPickerColors.Add( Color.ReinterpretAsLinear() ); } } FLinearColor InitialColor; GetColorAsLinear(InitialColor); // This needs to be meta data. Other colors could benefit from this const bool bRefreshOnlyOnOk = StructPropertyHandle->GetProperty()->GetOwnerClass()->IsChildOf(UMaterialExpressionConstant3Vector::StaticClass()); FColorPickerArgs PickerArgs; PickerArgs.bUseAlpha = !bIgnoreAlpha; PickerArgs.bOnlyRefreshOnMouseUp = false; PickerArgs.bOnlyRefreshOnOk = bRefreshOnlyOnOk; PickerArgs.DisplayGamma = TAttribute<float>::Create( TAttribute<float>::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma) ); PickerArgs.OnColorCommitted = FOnLinearColorValueChanged::CreateSP( this, &FColorStructCustomization::OnSetColorFromColorPicker ); PickerArgs.OnColorPickerCancelled = FOnColorPickerCancelled::CreateSP( this, &FColorStructCustomization::OnColorPickerCancelled ); PickerArgs.OnInteractivePickBegin = FSimpleDelegate::CreateSP( this, &FColorStructCustomization::OnColorPickerInteractiveBegin ); PickerArgs.OnInteractivePickEnd = FSimpleDelegate::CreateSP( this, &FColorStructCustomization::OnColorPickerInteractiveEnd ); PickerArgs.InitialColorOverride = InitialColor; PickerArgs.ParentWidget = ColorPickerParentWidget; OpenColorPicker(PickerArgs); }
// from http://www.cs.rit.edu/~ncs/color/t_convert.html FColor HSB::hsbToRgb(const FColor& hsb) { auto h = hue(hsb), s = saturation(hsb), b = brightness(hsb); float red, green, blue; if (s == 0) { // achromatic (grey) red = green = blue = b; } else { h *= 6; // sector 0 to 5 int i = floor(h); auto f = h - i; // factorial part of h auto p = b * (1 - s); auto q = b * (1 - s * f); auto t = b * (1 - s * (1 - f)); switch(i) { case 0: red = b; green = t; blue = p; break; case 1: red = q; green = b; blue = p; break; case 2: red = p; green = b; blue = t; break; case 3: red = p; green = q; blue = b; break; case 4: red = t; green = p; blue = b; break; case 5: default: red = b; green = p; blue = q; break; } } return FColor(red, green, blue, hsb.alpha()); }
TSharedRef<SColorPicker> FColorStructCustomization::CreateInlineColorPicker() { int32 NumObjects = StructPropertyHandle->GetNumOuterObjects(); SavedPreColorPickerColors.Empty(); TArray<FString> PerObjectValues; StructPropertyHandle->GetPerObjectValues( PerObjectValues ); for( int32 ObjectIndex = 0; ObjectIndex < NumObjects; ++ObjectIndex ) { if( bIsLinearColor ) { FLinearColor Color; Color.InitFromString( PerObjectValues[ObjectIndex] ); SavedPreColorPickerColors.Add( Color ); } else { FColor Color; Color.InitFromString( PerObjectValues[ObjectIndex] ); SavedPreColorPickerColors.Add( Color.ReinterpretAsLinear() ); } } FLinearColor InitialColor; GetColorAsLinear(InitialColor); // This needs to be meta data. Other colors could benefit from this const bool bRefreshOnlyOnOk = StructPropertyHandle->GetProperty()->GetOwnerClass()->IsChildOf(UMaterialExpressionConstant3Vector::StaticClass()); return SNew(SColorPicker) .Visibility(this, &FColorStructCustomization::GetInlineColorPickerVisibility) .DisplayInlineVersion(true) .OnlyRefreshOnMouseUp(false) .OnlyRefreshOnOk(bRefreshOnlyOnOk) .DisplayGamma(TAttribute<float>::Create( TAttribute<float>::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma) )) .OnColorCommitted(FOnLinearColorValueChanged::CreateSP( this, &FColorStructCustomization::OnSetColorFromColorPicker )) .OnColorPickerCancelled(FOnColorPickerCancelled::CreateSP( this, &FColorStructCustomization::OnColorPickerCancelled )) .OnInteractivePickBegin(FSimpleDelegate::CreateSP( this, &FColorStructCustomization::OnColorPickerInteractiveBegin )) .OnInteractivePickEnd(FSimpleDelegate::CreateSP( this, &FColorStructCustomization::OnColorPickerInteractiveEnd )) .TargetColorAttribute(InitialColor); }
void BatchRenderer::DrawSprite( const Matrix4& cameraWorldMatrix, const Vec3D& spriteOrigin, const FLOAT spriteSizeX, const FLOAT spriteSizeY, const FColor& color ) { const Vec3D spriteX = cameraWorldMatrix[0].ToVec3() * spriteSizeX; const Vec3D spriteY = cameraWorldMatrix[1].ToVec3() * spriteSizeY; const U4 rgbaColor = color.ToRGBA32(); SetBatchState( this, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); const UINT iBaseVertex = self->batchedVertices.Num(); Vertex & v0 = self->batchedVertices.Add(); Vertex & v1 = self->batchedVertices.Add(); Vertex & v2 = self->batchedVertices.Add(); Vertex & v3 = self->batchedVertices.Add(); v0.xyz = spriteOrigin - spriteX - spriteY; // bottom left v0.uv.x = 0.0f; v0.uv.y = 1.0f; v0.rgba.asU32 = rgbaColor; v1.xyz = spriteOrigin - spriteX + spriteY; // top left v1.uv.x = 0.0f; v1.uv.y = 0.0f; v1.rgba.asU32 = rgbaColor; v2.xyz = spriteOrigin + spriteX + spriteY; // top right v2.uv.x = 1.0f; v2.uv.y = 0.0f; v2.rgba.asU32 = rgbaColor; v3.xyz = spriteOrigin + spriteX - spriteY; // bottom right v3.uv.x = 1.0f; v3.uv.y = 1.0f; v3.rgba.asU32 = rgbaColor; // indices: // 0, 1, 2, // 0, 2, 3, self->batchedIndices.Add( iBaseVertex + 0 ); self->batchedIndices.Add( iBaseVertex + 1 ); self->batchedIndices.Add( iBaseVertex + 2 ); self->batchedIndices.Add( iBaseVertex + 0 ); self->batchedIndices.Add( iBaseVertex + 2 ); self->batchedIndices.Add( iBaseVertex + 3 ); }
void UPaperSpriteComponent::PostLoad() { Super::PostLoad(); const int32 PaperVer = GetLinkerCustomVersion(FPaperCustomVersion::GUID); if (PaperVer < FPaperCustomVersion::ConvertPaperSpriteComponentToBeMeshComponent) { if (MaterialOverride_DEPRECATED != nullptr) { SetMaterial(0, MaterialOverride_DEPRECATED); } } if (PaperVer < FPaperCustomVersion::FixVertexColorSpace) { const FColor SRGBColor = SpriteColor.ToFColor(/*bSRGB=*/ true); SpriteColor = SRGBColor.ReinterpretAsLinear(); } }
void DrawDebugPoint(const UWorld* InWorld, FVector const& Position, float Size, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority) { // no debug line drawing on dedicated server if (GEngine->GetNetMode(InWorld) != NM_DedicatedServer) { // this means foreground lines can't be persistent ULineBatchComponent* const LineBatcher = GetDebugLineBatcher( InWorld, bPersistentLines, LifeTime, (DepthPriority == SDPG_Foreground) ); if(LineBatcher != NULL) { LineBatcher->DrawPoint(Position, Color.ReinterpretAsLinear(), Size, DepthPriority, LifeTime); } } }
void FColorStructCustomization::OnColorPickerCancelled( FLinearColor OriginalColor ) { TArray<FString> PerObjectColors; for( int32 ColorIndex = 0; ColorIndex < SavedPreColorPickerColors.Num(); ++ColorIndex ) { if( bIsLinearColor ) { PerObjectColors.Add( SavedPreColorPickerColors[ColorIndex].ToString() ); } else { const bool bSRGB = false; FColor Color = SavedPreColorPickerColors[ColorIndex].ToFColor( bSRGB ); PerObjectColors.Add( Color.ToString() ); } } StructPropertyHandle->SetPerObjectValues( PerObjectColors ); PerObjectColors.Empty(); }
void BatchRenderer::DrawTriangle3D( const Vec3D& a, const Vec3D& b, const Vec3D& c, const FColor& color ) { #if 0 DrawLine3D( a, b, color, color ); DrawLine3D( b, c, color, color ); DrawLine3D( c, a, color, color ); #else SetBatchState( this, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP ); Vertex & v0 = self->batchedVertices.Add(); Vertex & v1 = self->batchedVertices.Add(); Vertex & v2 = self->batchedVertices.Add(); Vertex & v3 = self->batchedVertices.Add(); v0.xyz.x = a.x; v0.xyz.y = a.y; v0.xyz.z = a.z; v0.rgba.asU32 = color.ToRGBA32(); v1.xyz.x = b.x; v1.xyz.y = b.y; v1.xyz.z = b.z; v1.rgba.asU32 = color.ToRGBA32(); v2.xyz.x = c.x; v2.xyz.y = c.y; v2.xyz.z = c.z; v2.rgba.asU32 = color.ToRGBA32(); v3.xyz.x = a.x; v3.xyz.y = a.y; v3.xyz.z = a.z; v3.rgba.asU32 = color.ToRGBA32(); #endif }
void Window::drawWindow(Renderer2D &out, IRect rect, FColor color, int outline) { FColor lighter(color.rgb() * 1.2f, color.a); FColor darker(color.rgb() * 0.8f, color.a); int aoutline = fwk::abs(outline); if(outline) { int2 hsize(rect.width(), aoutline); int2 vsize(aoutline, rect.height()); FColor col1 = outline < 0? darker : lighter; out.addFilledRect(IRect(rect.min, rect.min + hsize), col1); out.addFilledRect(IRect(rect.min, rect.min + vsize), col1); int2 p1(rect.min.x, rect.max.y - aoutline); int2 p2(rect.max.x - aoutline, rect.min.y); FColor col2 = outline < 0? lighter : darker; out.addFilledRect(IRect(p1, p1 + hsize), col2); out.addFilledRect(IRect(p2, p2 + vsize), col2); } int2 off(aoutline, aoutline); out.addFilledRect(inset(rect, off, off), color); }
void FSequencerFolderNode::SetFolderColor() { InitialFolderColor = MovieSceneFolder.GetFolderColor(); bFolderPickerWasCancelled = false; FColorPickerArgs PickerArgs; PickerArgs.bUseAlpha = false; PickerArgs.DisplayGamma = TAttribute<float>::Create( TAttribute<float>::FGetter::CreateUObject(GEngine, &UEngine::GetDisplayGamma) ); PickerArgs.InitialColorOverride = InitialFolderColor.ReinterpretAsLinear(); PickerArgs.OnColorCommitted = FOnLinearColorValueChanged::CreateSP( this, &FSequencerFolderNode::OnColorPickerPicked); PickerArgs.OnColorPickerWindowClosed = FOnWindowClosed::CreateSP( this, &FSequencerFolderNode::OnColorPickerClosed); PickerArgs.OnColorPickerCancelled = FOnColorPickerCancelled::CreateSP( this, &FSequencerFolderNode::OnColorPickerCancelled ); OpenColorPicker(PickerArgs); }
FTetrisBlockSet *FTetrisGameController::GenerateBlockSet(){ bool texture = scene->GetTexture(); unsigned int textureid = scene->GetTextureId(); FTetrisBlockSet::BLOCKOPTIONS option = FTetrisBlockSet::I; FColor *color = new FColor(0, 0, 0, 1); int myoption = rand(); switch(myoption % 7){ case 0: option = FTetrisBlockSet::I; color->SetR(1); break; case 1: option = FTetrisBlockSet::J; color->SetG(1); break; case 2: option = FTetrisBlockSet::L; color->SetB(1); break; case 3: option = FTetrisBlockSet::O; color->SetR(1); color->SetB(1); break; case 4: option = FTetrisBlockSet::T; color->SetB(1); color->SetG(1); break; case 5: option = FTetrisBlockSet::S; color->SetR(1); color->SetG(1); break; case 6: option = FTetrisBlockSet::Z; color->SetR(1); color->SetG(1); color->SetB(1); break; } FTetrisBlockSet *blockset = new FTetrisBlockSet(0, 0, option, field->GetBoxWidth(), field->GetBoxHeight(), field->GetCubeWidth(), field->GetCubeHeight(), color, false, texture, textureid, false); return blockset; }
void AGameplayDebuggingHUDComponent::PrintString(FPrintContext& Context, const FColor& InColor, const FString& InString ) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) PrintString(Context, FString::Printf(TEXT("{%s}%s"), *InColor.ToString(), *InString)); #endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST) }
TArray<FColor> USceneCapturer::SaveAtlas(FString Folder, const TArray<FColor>& SurfaceData) { SCOPE_CYCLE_COUNTER( STAT_SPSavePNG ); TArray<FColor> SphericalAtlas; SphericalAtlas.AddZeroed(SphericalAtlasWidth * SphericalAtlasHeight); const FVector2D slicePlaneDim = FVector2D( 2.0f * FMath::Tan(FMath::DegreesToRadians(sliceHFov) / 2.0f), 2.0f * FMath::Tan(FMath::DegreesToRadians(sliceVFov) / 2.0f)); //For each direction, // Find corresponding slice // Calculate intersection of slice plane // Calculate intersection UVs by projecting onto plane tangents // Supersample that UV coordinate from the unprojected atlas { SCOPE_CYCLE_COUNTER(STAT_SPSampleSpherical); // Dump out how long the process took const FDateTime SamplingStartTime = FDateTime::UtcNow(); UE_LOG(LogStereoPanorama, Log, TEXT("Sampling atlas...")); for (int32 y = 0; y < SphericalAtlasHeight; y++) { for (int32 x = 0; x < SphericalAtlasWidth; x++) { FLinearColor samplePixelAccum = FLinearColor(0, 0, 0, 0); //TODO: ikrimae: Seems that bilinear filtering sans supersampling is good enough. Supersampling sans bilerp seems best. // After more tests, come back to optimize by folding supersampling in and remove this outer sampling loop. const auto& ssPattern = g_ssPatterns[SSMethod]; for (int32 SampleCount = 0; SampleCount < ssPattern.numSamples; SampleCount++) { const float sampleU = ((float)x + ssPattern.ssOffsets[SampleCount].X) / SphericalAtlasWidth; const float sampleV = ((float)y + ssPattern.ssOffsets[SampleCount].Y) / SphericalAtlasHeight; const float sampleTheta = sampleU * 360.0f; const float samplePhi = sampleV * 180.0f; const FVector sampleDir = FVector( FMath::Sin(FMath::DegreesToRadians(samplePhi)) * FMath::Cos(FMath::DegreesToRadians(sampleTheta)), FMath::Sin(FMath::DegreesToRadians(samplePhi)) * FMath::Sin(FMath::DegreesToRadians(sampleTheta)), FMath::Cos(FMath::DegreesToRadians(samplePhi))); //TODO: ikrimae: ugh, ugly. const int32 sliceXIndex = FMath::TruncToInt(FRotator::ClampAxis(sampleTheta + hAngIncrement / 2.0f) / hAngIncrement); int32 sliceYIndex = 0; //Slice Selection = slice with max{sampleDir dot sliceNormal } { float largestCosAngle = 0; for (int VerticalStep = 0; VerticalStep < NumberOfVerticalSteps; VerticalStep++) { const FVector2D sliceCenterThetaPhi = FVector2D( hAngIncrement * sliceXIndex, vAngIncrement * VerticalStep); //TODO: ikrimae: There has got to be a faster way. Rethink reparametrization later const FVector sliceDir = FVector( FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.Y))); const float cosAngle = sampleDir | sliceDir; if (cosAngle > largestCosAngle) { largestCosAngle = cosAngle; sliceYIndex = VerticalStep; } } } const FVector2D sliceCenterThetaPhi = FVector2D( hAngIncrement * sliceXIndex, vAngIncrement * sliceYIndex); //TODO: ikrimae: Reparameterize with an inverse mapping (e.g. project from slice pixels onto final u,v coordinates. // Should make code simpler and faster b/c reduces to handful of sin/cos calcs per slice. // Supersampling will be more difficult though. const FVector sliceDir = FVector( FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.Y))); const FPlane slicePlane = FPlane(sliceDir, -sliceDir); //Tangents from partial derivatives of sphere equation const FVector slicePlanePhiTangent = FVector( FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), -FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y))).GetSafeNormal(); //Should be reconstructed to get around discontinuity of theta tangent at nodal points const FVector slicePlaneThetaTangent = (sliceDir ^ slicePlanePhiTangent).GetSafeNormal(); //const FVector slicePlaneThetaTangent = FVector( // -FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), // FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), // 0).SafeNormal(); check(!slicePlaneThetaTangent.IsZero() && !slicePlanePhiTangent.IsZero()); const double t = (double)-slicePlane.W / (sampleDir | sliceDir); const FVector sliceIntersection = FVector(t * sampleDir.X, t * sampleDir.Y, t * sampleDir.Z); //Calculate scalar projection of sliceIntersection onto tangent vectors. a dot b / |b| = a dot b when tangent vectors are normalized //Then reparameterize to U,V of the sliceplane based on slice plane dimensions const float sliceU = (sliceIntersection | slicePlaneThetaTangent) / slicePlaneDim.X; const float sliceV = (sliceIntersection | slicePlanePhiTangent) / slicePlaneDim.Y; check(sliceU >= -(0.5f + KINDA_SMALL_NUMBER) && sliceU <= (0.5f + KINDA_SMALL_NUMBER)); check(sliceV >= -(0.5f + KINDA_SMALL_NUMBER) && sliceV <= (0.5f + KINDA_SMALL_NUMBER)); //TODO: ikrimae: Supersample/bilinear filter const int32 slicePixelX = FMath::TruncToInt(dbgMatchCaptureSliceFovToAtlasSliceFov ? sliceU * StripWidth : sliceU * CaptureWidth); const int32 slicePixelY = FMath::TruncToInt(dbgMatchCaptureSliceFovToAtlasSliceFov ? sliceV * StripHeight : sliceV * CaptureHeight); FLinearColor slicePixelSample; if (bEnableBilerp) { //TODO: ikrimae: Clean up later; too tired now const int32 sliceCenterPixelX = (sliceXIndex + 0.5f) * StripWidth; const int32 sliceCenterPixelY = (sliceYIndex + 0.5f) * StripHeight; const FIntPoint atlasSampleTL(sliceCenterPixelX + FMath::Clamp(slicePixelX , -StripWidth/2, StripWidth/2), sliceCenterPixelY + FMath::Clamp(slicePixelY , -StripHeight/2, StripHeight/2)); const FIntPoint atlasSampleTR(sliceCenterPixelX + FMath::Clamp(slicePixelX + 1, -StripWidth/2, StripWidth/2), sliceCenterPixelY + FMath::Clamp(slicePixelY , -StripHeight/2, StripHeight/2)); const FIntPoint atlasSampleBL(sliceCenterPixelX + FMath::Clamp(slicePixelX , -StripWidth/2, StripWidth/2), sliceCenterPixelY + FMath::Clamp(slicePixelY + 1, -StripHeight/2, StripHeight/2)); const FIntPoint atlasSampleBR(sliceCenterPixelX + FMath::Clamp(slicePixelX + 1, -StripWidth/2, StripWidth/2), sliceCenterPixelY + FMath::Clamp(slicePixelY + 1, -StripHeight/2, StripHeight/2)); const FColor pixelColorTL = SurfaceData[atlasSampleTL.Y * UnprojectedAtlasWidth + atlasSampleTL.X]; const FColor pixelColorTR = SurfaceData[atlasSampleTR.Y * UnprojectedAtlasWidth + atlasSampleTR.X]; const FColor pixelColorBL = SurfaceData[atlasSampleBL.Y * UnprojectedAtlasWidth + atlasSampleBL.X]; const FColor pixelColorBR = SurfaceData[atlasSampleBR.Y * UnprojectedAtlasWidth + atlasSampleBR.X]; const float fracX = FMath::Frac(dbgMatchCaptureSliceFovToAtlasSliceFov ? sliceU * StripWidth : sliceU * CaptureWidth); const float fracY = FMath::Frac(dbgMatchCaptureSliceFovToAtlasSliceFov ? sliceV * StripHeight : sliceV * CaptureHeight); //Reinterpret as linear (a.k.a dont apply srgb inversion) slicePixelSample = FMath::BiLerp( pixelColorTL.ReinterpretAsLinear(), pixelColorTR.ReinterpretAsLinear(), pixelColorBL.ReinterpretAsLinear(), pixelColorBR.ReinterpretAsLinear(), fracX, fracY); } else { const int32 sliceCenterPixelX = (sliceXIndex + 0.5f) * StripWidth; const int32 sliceCenterPixelY = (sliceYIndex + 0.5f) * StripHeight; const int32 atlasSampleX = sliceCenterPixelX + slicePixelX; const int32 atlasSampleY = sliceCenterPixelY + slicePixelY; slicePixelSample = SurfaceData[atlasSampleY * UnprojectedAtlasWidth + atlasSampleX].ReinterpretAsLinear(); } samplePixelAccum += slicePixelSample; ////Output color map of projections //const FColor debugEquiColors[12] = { // FColor(205, 180, 76), // FColor(190, 88, 202), // FColor(127, 185, 194), // FColor(90, 54, 47), // FColor(197, 88, 53), // FColor(197, 75, 124), // FColor(130, 208, 72), // FColor(136, 211, 153), // FColor(126, 130, 207), // FColor(83, 107, 59), // FColor(200, 160, 157), // FColor(80, 66, 106) //}; //samplePixelAccum = ssPattern.numSamples * debugEquiColors[sliceYIndex * 4 + sliceXIndex]; } SphericalAtlas[y * SphericalAtlasWidth + x] = (samplePixelAccum / ssPattern.numSamples).Quantize(); // Force alpha value if (bForceAlpha) { SphericalAtlas[y * SphericalAtlasWidth + x].A = 255; } } } //Blit the first column into the last column to make the stereo image seamless at theta=360 for (int32 y = 0; y < SphericalAtlasHeight; y++) { SphericalAtlas[y * SphericalAtlasWidth + (SphericalAtlasWidth - 1)] = SphericalAtlas[y * SphericalAtlasWidth + 0]; } const FTimespan SamplingDuration = FDateTime::UtcNow() - SamplingStartTime; UE_LOG(LogStereoPanorama, Log, TEXT("...done! Duration: %g seconds"), SamplingDuration.GetTotalSeconds()); } // Generate name FString FrameString = FString::Printf( TEXT( "%s_%05d.png" ), *Folder, CurrentFrameCount ); FString AtlasName = OutputDir / Timestamp / FrameString; UE_LOG( LogStereoPanorama, Log, TEXT( "Writing atlas: %s" ), *AtlasName ); // Write out PNG //TODO: ikrimae: Use threads to write out the images for performance IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper( EImageFormat::PNG ); ImageWrapper->SetRaw(SphericalAtlas.GetData(), SphericalAtlas.GetAllocatedSize(), SphericalAtlasWidth, SphericalAtlasHeight, ERGBFormat::BGRA, 8); const TArray<uint8>& PNGData = ImageWrapper->GetCompressed(100); FFileHelper::SaveArrayToFile( PNGData, *AtlasName ); if (FStereoPanoramaManager::GenerateDebugImages->GetInt() != 0) { FString FrameStringUnprojected = FString::Printf(TEXT("%s_%05d_Unprojected.png"), *Folder, CurrentFrameCount); FString AtlasNameUnprojected = OutputDir / Timestamp / FrameStringUnprojected; ImageWrapper->SetRaw(SurfaceData.GetData(), SurfaceData.GetAllocatedSize(), UnprojectedAtlasWidth, UnprojectedAtlasHeight, ERGBFormat::BGRA, 8); const TArray<uint8>& PNGDataUnprojected = ImageWrapper->GetCompressed(100); FFileHelper::SaveArrayToFile(PNGData, *AtlasNameUnprojected); } ImageWrapper.Reset(); UE_LOG( LogStereoPanorama, Log, TEXT( " ... done!" ), *AtlasName ); return SphericalAtlas; }
void ParseString(const FString& StringToParse) { Index = 0; DataString = StringToParse; Strings.Add(StringNode()); if (Index >= DataString.Len()) return; uint8 Token = ReadToken(); while (Token != EndOfString) { switch (Token) { case RegularChar: Strings[Strings.Num()-1].String.AppendChar( DataString[Index++] ); break; case NewLine: Strings.Add(StringNode()); Strings[Strings.Num()-1].bNewLine = true; Strings[Strings.Num()-1].Color = Strings[Strings.Num()-2].Color; break; case EndOfString: break; case Tab: { const FString TabString(TEXT(" ")); Strings[Strings.Num()-1].String.Append(TabString); static bool sbTest = false; if (sbTest) { Index++; } break; } case OpenTag: { FString OutData; switch (ParseTag(OutData)) { case DefinedColor: { int32 i = Strings.Add(StringNode()); Strings[i].Color = GColorList.GetFColorByName(*OutData.ToLower()); } break; case OtherColor: { FColor NewColor; if (NewColor.InitFromString( OutData )) { int32 i = Strings.Add(StringNode()); Strings[i].Color = NewColor; break; } } default: Strings[Strings.Num()-1].String += OutData; break; } } break; } Token = ReadToken(); } }
FORCEINLINE R8G8B8A8 FColor_to_RGBA32( const FColor& theColor ) { R8G8B8A8 rgba; rgba.asU32 = theColor.ToRGBA32(); return rgba; }