diff --git a/Content/Interaction/DomeDispay_BP.uasset b/Content/Interaction/DomeDispay_BP.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..c6a526e2e4dbad357b3a515bc76ab3b1d8c92db9
--- /dev/null
+++ b/Content/Interaction/DomeDispay_BP.uasset
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2928cfb222bb8eb20fa8885353effd679e621e3bc974773803ef2ae67bb554f5
+size 34674
diff --git a/Content/Interaction/FulldomeMasterGrid.uasset b/Content/Interaction/FulldomeMasterGrid.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..2d145b39430a9f4adcb44355a0c29356c95c364f
--- /dev/null
+++ b/Content/Interaction/FulldomeMasterGrid.uasset
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f8b6848483e3fcaccda4667e35437ca10de414700ef071eb3229cc4ebded5162
+size 1996778
diff --git a/Content/Interaction/MI_DomeDisplayGeneric.uasset b/Content/Interaction/MI_DomeDisplayGeneric.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..3e925d479aabfb46126b813522bdfa8024f5e375
--- /dev/null
+++ b/Content/Interaction/MI_DomeDisplayGeneric.uasset
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4eab88f1f0d7a3b2d02fe5ea604f1cef5214f20fc4ae3007e5fb4f817d969320
+size 132242
diff --git a/Content/Interaction/M_DomeDisplay.uasset b/Content/Interaction/M_DomeDisplay.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..859ae9c02f754808010a12ae799bd4e57c7600bf
--- /dev/null
+++ b/Content/Interaction/M_DomeDisplay.uasset
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:251fddde1ec9572bd5236ffb6bcca5b75468fd6e3bb15f6ff9dbfe91f3ff13e8
+size 103358
diff --git a/Content/Levels/ViewerMain.umap b/Content/Levels/ViewerMain.umap
index bbef24363cb6fcdf00ca3c15a32604beb4839b12..04109777cc0956326c2faf722ce44010cf99f9ab 100644
--- a/Content/Levels/ViewerMain.umap
+++ b/Content/Levels/ViewerMain.umap
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:a3aa7ddaf955bb854612b90c4bb6db93af855222f0c36f080773bc0ed412609f
-size 639326
+oid sha256:d5c22f25887f895a877ce9bd4418164898405ceec6eb8e9bcacc7d4ff0e4d9f1
+size 5042957
diff --git a/Content/Levels/ViewerMain_BuiltData.uasset b/Content/Levels/ViewerMain_BuiltData.uasset
index d5f0195db966373c9019841118ba5632cb78ae71..185789077d91560ab2965f3725ab32266c6a6f97 100644
--- a/Content/Levels/ViewerMain_BuiltData.uasset
+++ b/Content/Levels/ViewerMain_BuiltData.uasset
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:861f079ee62fb01f4d1a07378770a6b8b52e489e03da56c175d4a60a99c81371
+oid sha256:c2490fe53943792e9bcb8351d8f426c540a75d69e2633887bc8360497e92be3b
 size 1134373
diff --git a/Source/DomeViewerVR/DomeViewerVR.cpp b/Source/DomeViewerVR/DomeViewerVR.cpp
index 7463fa938a1839f5a9bf618da8ad553d6252e8da..f2adc9438c42b995d48e86f897de43c6bedf5e94 100644
--- a/Source/DomeViewerVR/DomeViewerVR.cpp
+++ b/Source/DomeViewerVR/DomeViewerVR.cpp
@@ -4,3 +4,5 @@
 #include "Modules/ModuleManager.h"
 
 IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, DomeViewerVR, "DomeViewerVR" );
+
+DEFINE_LOG_CATEGORY(DomeViewer);
diff --git a/Source/DomeViewerVR/DomeViewerVR.h b/Source/DomeViewerVR/DomeViewerVR.h
index 90aad9e7e22f143662bdcb74de4ca59ffc4f7321..e991e40bbd7ca2fa24463fdfb1615101be3131ab 100644
--- a/Source/DomeViewerVR/DomeViewerVR.h
+++ b/Source/DomeViewerVR/DomeViewerVR.h
@@ -4,3 +4,4 @@
 
 #include "CoreMinimal.h"
 
+DECLARE_LOG_CATEGORY_EXTERN(DomeViewer, Verbose, All);
diff --git a/Source/DomeViewerVR/Private/DomeDisplayComponent.cpp b/Source/DomeViewerVR/Private/DomeDisplayComponent.cpp
index 2437c1d827cf4f490b6c67d87b5513c762ff3922..f5645e0ecc6117f319ad65177cb612bcba23f2c7 100644
--- a/Source/DomeViewerVR/Private/DomeDisplayComponent.cpp
+++ b/Source/DomeViewerVR/Private/DomeDisplayComponent.cpp
@@ -1,5 +1,155 @@
-// Fill out your copyright notice in the Description page of Project Settings.
+// Copyright 2019 Patric Ljung
+// Linkoping University, Media and Information Technology, Visualization Center C
+// License: BSD-3-Clause (https://opensource.org/licenses/BSD-3-Clause)
 
 
 #include "DomeDisplayComponent.h"
+#include "Math/UnrealMath.h"
+#include "DomeViewerVR.h" // For the log category
 
+//UDomeDisplayComponent::UDomeDisplayComponent(const FObjectInitializer & ObjectInitializer)
+//: Super(ObjectInitializer)
+//{
+//    Radius = 750.0f;
+//    TiltAngle = 27.0f;
+//    HemisphereDegrees = 170.0f;
+//    MeshEdgeDegrees = 3.6f;
+//    Material = nullptr;
+//
+//    BuildDomeMesh();
+//
+//    bUseComplexAsSimpleCollision = true; // Since it is concave
+//
+//    CreateMeshSection(0, MeshVerts, MeshTris, MeshNormals, MeshUVs, MeshColors, MeshTangents, true);
+//}
+
+UDomeDisplayComponent::UDomeDisplayComponent()
+{
+    Radius = 750.0f;
+    TiltAngle = 27.0f;
+    HemisphereDegrees = 170.0f;
+    MeshEdgeDegrees = 3.6f;
+    Material = nullptr;
+    
+    DomeMesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("DomeMesh"));
+    DomeMesh->SetupAttachment(this);
+
+    //BuildDomeMesh();
+    
+    //bUseComplexAsSimpleCollision = true; // Since it is concave
+    
+    //CreateMeshSection(0, MeshVerts, MeshTris, MeshNormals, MeshUVs, MeshColors, MeshTangents, true);
+}
+
+UDomeDisplayComponent::~UDomeDisplayComponent()
+{
+    Material = nullptr;
+}
+
+#define PI_2 (2.0f * PI)
+
+void UDomeDisplayComponent::BuildDomeMesh()
+{
+    int numLatSections = 1 + int(HemisphereDegrees / MeshEdgeDegrees / 2.0f);
+    int numLonSections = 1 + int(360.0f / MeshEdgeDegrees);
+    
+    // DEBUG: Just make it simpler for debugging
+    //numLatSections = 2;
+    
+    UE_LOG(DomeViewer, Display, TEXT("BuildDomeMesh: LatSections %d, LonSections: %d"), numLatSections, numLonSections);
+
+    const FVector forward = FVector(1.0f, 0.0f, 0.0f);
+    const FVector right = FVector(0.0f, 1.0f, 0.0f);
+    const FVector up = FVector(0.0f, 0.0f, 1.0f);
+    
+    int numVerts = 1 + numLatSections * numLonSections;
+    MeshVerts.Reserve(numVerts);
+    MeshUVs.Reserve(numVerts);
+    MeshTris.Reserve(3*numVerts); // TODO: Resolve real number of triangles
+    
+    const float deltaLatRads = (PI * HemisphereDegrees / 360.0f) / float(numLatSections - 1);
+    const float deltaLonRads = PI_2 / float(numLonSections);
+    
+    // Compute the vertices, starting at top
+    MeshVerts.Add(up * Radius);
+    MeshNormals.Add(-up);
+    //MeshTangents.Add(right);
+
+    for (int latIdx = 1; latIdx < numLatSections; ++latIdx)
+    {
+        float latAngle = latIdx * deltaLatRads;
+        float latSin = sin(latAngle);
+        float latCos = cos(latAngle);
+        FVector upLoc = up * latCos;
+        
+        for (int lonIdx = 0; lonIdx < numLonSections; ++lonIdx)
+        {
+            float lonSin = sin(lonIdx * PI_2 / numLonSections);
+            float lonCos = cos(lonIdx * PI_2 / numLonSections);
+            FVector unitDir(forward * (latSin * lonCos) +
+                            right * (latSin * lonSin) + upLoc);
+            MeshVerts.Add(unitDir * Radius);
+            MeshNormals.Add(-unitDir);
+        }
+    }
+    
+    // Compute mesh UVs, starting at the center
+    const FVector2D uvCenter(0.5f, 0.5f);
+    MeshUVs.Add(uvCenter);
+    
+    for (int latIdx = 1; latIdx < numLatSections; ++latIdx)
+    {
+        float uvRadius = 0.5f * float(latIdx) / float(numLatSections - 1);
+
+        for (int lonIdx = 0; lonIdx < numLonSections; ++lonIdx)
+        {
+            float lonAngle = lonIdx * deltaLonRads;
+            MeshUVs.Add(uvCenter + uvRadius * FVector2D(sin(lonAngle), cos(lonAngle)));
+        }
+    }
+
+    // Compute the triangle indices
+    // ... first the cap
+    for (int lonIdx = 0; lonIdx < numLonSections; ++lonIdx)
+    {
+        // Counter clock-wise, triangle fan
+        MeshTris.Add(1 + lonIdx);
+        MeshTris.Add(1 + ((lonIdx + 1) % numLonSections));
+        MeshTris.Add(0);
+    }
+    // ... then the rest
+    for (int latIdx = 1; latIdx < numLatSections - 1; ++latIdx)
+    {
+        int32 topBase = 1 + (latIdx - 1) * numLonSections;
+        int32 bottomBase = 1 + latIdx * numLonSections;
+
+        for (int lonIdx = 0; lonIdx < numLonSections; ++lonIdx)
+        {
+            // Make quads, two triangles
+            // Counter clock-wise
+            MeshTris.Add(bottomBase + lonIdx);
+            MeshTris.Add(bottomBase + (lonIdx + 1) % numLonSections);
+            MeshTris.Add(topBase + lonIdx);
+
+            MeshTris.Add(bottomBase + (lonIdx + 1) % numLonSections);
+            MeshTris.Add(topBase + (lonIdx + 1) % numLonSections);
+            MeshTris.Add(topBase + lonIdx);
+        }
+    }
+}
+
+bool UDomeDisplayComponent::UpdateDomeMesh()
+{
+    BuildDomeMesh();
+
+    DomeMesh->CreateMeshSection(0, MeshVerts, MeshTris, MeshNormals, MeshUVs, MeshColors, MeshTangents, false);
+
+    if (Material != nullptr)
+    {
+        DomeMesh->SetMaterial(0, Material);
+    }
+
+    DomeMesh->SetRelativeRotation(FRotator(-TiltAngle, 0.0f, 0.0f));
+
+    return true;
+}
diff --git a/Source/DomeViewerVR/Public/DomeDisplayComponent.h b/Source/DomeViewerVR/Public/DomeDisplayComponent.h
index 0b9a05a817a7412d5d9308a0a408271c375c5df4..818b226b54f442cca67ddef92a2c619a1fd4c002 100644
--- a/Source/DomeViewerVR/Public/DomeDisplayComponent.h
+++ b/Source/DomeViewerVR/Public/DomeDisplayComponent.h
@@ -1,17 +1,69 @@
-// Fill out your copyright notice in the Description page of Project Settings.
+// Copyright 2019 Patric Ljung
+// Linkoping University, Media and Information Technology, Visualization Center C
+// License: BSD-3-Clause (https://opensource.org/licenses/BSD-3-Clause)
 
 #pragma once
 
 #include "CoreMinimal.h"
 #include "ProceduralMeshComponent.h"
+// TODO: Move to .cpp file and provide forward declaration here instead
+#include "Materials/MaterialInterface.h"
+
 #include "DomeDisplayComponent.generated.h"
 
 /**
  * 
  */
-UCLASS()
-class DOMEVIEWERVR_API UDomeDisplayComponent : public UProceduralMeshComponent
+UCLASS(BlueprintType, Category = "Dome",
+       Meta = (BlueprintSpawnableComponent, Tooltip = "A component that dynamically creates a UV-mapped dome hemisphere mesh"))
+class DOMEVIEWERVR_API UDomeDisplayComponent : public USceneComponent
 {
 	GENERATED_BODY()
 	
+public:
+    UDomeDisplayComponent();
+    ~UDomeDisplayComponent();
+
+    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dome",
+              Meta = (Tooltip = "The radius of the dome"))
+    float Radius;
+    
+    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dome",
+              Meta = (Tooltip = "How many degrees is the dome tilted forward"))
+    float TiltAngle;
+
+    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dome",
+              Meta = (Tooltip = "How many degrees the hemisphere spans, 180 degrees makes it a full hemishphere"))
+    float HemisphereDegrees;
+
+    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dome",
+              Meta = (Tooltip = "Mesh resolution, degrees per bottom edge"))
+    float MeshEdgeDegrees;
+
+    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dome",
+              Meta = (Tooltip = "Dome display mesh material"))
+    UMaterialInterface * Material;
+
+//    UPROPERTY(EditAnywhere, BlueprintRead, Category = "Dome",
+//              Meta = (Tooltip = "Dome display mesh material"))
+    UPROPERTY()
+    UProceduralMeshComponent * DomeMesh;
+
+public:
+    UFUNCTION(BlueprintCallable, Category = "Dome",
+              Meta = (Tooltip = "Update the dome mesh using current settings"))
+    bool UpdateDomeMesh();
+    
+protected:
+    // TODO: Add method to capture editor changes and call BuildDomeMesh
+
+    void BuildDomeMesh();
+
+    TArray<FVector>     MeshVerts;
+    TArray<int32>       MeshTris;
+    TArray<FVector>     MeshNormals;
+    TArray<FVector2D>   MeshUVs;
+    TArray<FColor>      MeshColors;
+    TArray<FProcMeshTangent> MeshTangents;
+
 };