diff --git a/tests/test_utilities/dummy_material_generator.cpp b/library/phx/resources/loaders/generic_material_loader.cpp
similarity index 56%
rename from tests/test_utilities/dummy_material_generator.cpp
rename to library/phx/resources/loaders/generic_material_loader.cpp
index 4dcf8e004a7d1bd854f0f734247ece4c1d28d155..425dedc7d4253d45cffa63f30e48f14a7382a7db 100644
--- a/tests/test_utilities/dummy_material_generator.cpp
+++ b/library/phx/resources/loaders/generic_material_loader.cpp
@@ -20,32 +20,32 @@
 // limitations under the License.
 //------------------------------------------------------------------------------
 
-#include "dummy_material_generator.hpp"
+#include "phx/resources/loaders/generic_material_loader.hpp"
 
 #include <memory>
-#include <utility>
 #include <vector>
 
 #include "phx/resources/types/material.hpp"
 
 namespace phx {
+std::unique_ptr<Resource> GenericMaterialLoader::Load(
+    const ResourceDeclaration& declaration) {
+  auto resource = std::make_unique<phx::Material>();
 
-DummyMaterialGenerator::DummyMaterialGenerator(glm::vec3 diffuse_color,
-                                               glm::vec3 specular_color,
-                                               glm::vec3 ambient_color,
-                                               float shininess)
-    : material_{std::make_unique<phx::Material>()} {
-  material_->SetAmbientColor(ambient_color);
-  material_->SetDiffuseColor(diffuse_color);
-  material_->SetSpecularColor(specular_color);
-  material_->SetShininess(shininess);
-}
+  resource->SetName(declaration["material_name"]);
 
-std::unique_ptr<phx::Resource> DummyMaterialGenerator::Load(
-    const ResourceDeclaration&) {
-  auto new_material = std::make_unique<phx::Material>();
-  *new_material = *material_;
-  return new_material;
-}
+  std::vector<float> diffuseColor = declaration["diffuse_color"];
+  resource->SetDiffuseColor(
+      glm::vec3(diffuseColor[0], diffuseColor[1], diffuseColor[2]));
+  std::vector<float> specularColor = declaration["specular_color"];
+  resource->SetSpecularColor(
+      glm::vec3(specularColor[0], specularColor[1], specularColor[2]));
+  std::vector<float> ambientColor = declaration["ambient_color"];
+  resource->SetAmbientColor(
+      glm::vec3(ambientColor[0], ambientColor[1], ambientColor[2]));
+  float shininess = declaration["shininess"];
+  resource->SetShininess(shininess);
 
+  return resource;
+}
 }  // namespace phx
diff --git a/tests/test_utilities/dummy_material_generator.hpp b/library/phx/resources/loaders/generic_material_loader.hpp
similarity index 55%
rename from tests/test_utilities/dummy_material_generator.hpp
rename to library/phx/resources/loaders/generic_material_loader.hpp
index 41c449a466ce608d850c1f03d82a321cfb823c3e..408f868ea43769429985fd10e136c8a3ec809446 100644
--- a/tests/test_utilities/dummy_material_generator.hpp
+++ b/library/phx/resources/loaders/generic_material_loader.hpp
@@ -20,43 +20,27 @@
 // limitations under the License.
 //------------------------------------------------------------------------------
 
-#ifndef TESTS_TEST_UTILITIES_DUMMY_MATERIAL_GENERATOR_HPP_
-#define TESTS_TEST_UTILITIES_DUMMY_MATERIAL_GENERATOR_HPP_
+#ifndef LIBRARY_PHX_RESOURCES_LOADERS_GENERIC_MATERIAL_LOADER_HPP_
+#define LIBRARY_PHX_RESOURCES_LOADERS_GENERIC_MATERIAL_LOADER_HPP_
 
 #include <memory>
-#include <utility>
-#include <vector>
-
-#include "phx/suppress_warnings.hpp"
-
-SUPPRESS_WARNINGS_BEGIN
-#include "glm/vec3.hpp"
-SUPPRESS_WARNINGS_END
 
 #include "phx/resources/resource_load_strategy.hpp"
 
 namespace phx {
-class Material;
-
-class DummyMaterialGenerator : public ResourceLoadStrategy {
+class GenericMaterialLoader final : public ResourceLoadStrategy {
  public:
-  DummyMaterialGenerator() = delete;
-  DummyMaterialGenerator(glm::vec3 diffuse_color, glm::vec3 specular_color,
-                         glm::vec3 ambient_color, float shininess);
-  DummyMaterialGenerator(const DummyMaterialGenerator &) = default;
-  DummyMaterialGenerator(DummyMaterialGenerator &&) = default;
-  ~DummyMaterialGenerator() override = default;
+  GenericMaterialLoader() = default;
+  GenericMaterialLoader(const GenericMaterialLoader &) = delete;
+  GenericMaterialLoader(GenericMaterialLoader &&) = delete;
+  ~GenericMaterialLoader() = default;
 
-  DummyMaterialGenerator &operator=(const DummyMaterialGenerator &) = default;
-  DummyMaterialGenerator &operator=(DummyMaterialGenerator &&) = default;
+  GenericMaterialLoader &operator=(const GenericMaterialLoader &) = delete;
+  GenericMaterialLoader &operator=(GenericMaterialLoader &&) = delete;
 
   std::unique_ptr<Resource> Load(
       const ResourceDeclaration &declaration) override;
-
- protected:
- private:
-  std::unique_ptr<phx::Material> material_;
 };
 }  // namespace phx
 
-#endif  // TESTS_TEST_UTILITIES_DUMMY_MATERIAL_GENERATOR_HPP_
+#endif  // LIBRARY_PHX_RESOURCES_LOADERS_GENERIC_MATERIAL_LOADER_HPP_
diff --git a/library/phx/resources/resource_manager.cpp b/library/phx/resources/resource_manager.cpp
index 938b6dd7f128ea37b08cc1566d7ea94697f9bc35..34702a628db713a454f71cef47de4e4339b0e058 100644
--- a/library/phx/resources/resource_manager.cpp
+++ b/library/phx/resources/resource_manager.cpp
@@ -27,6 +27,7 @@
 #include <utility>
 
 #include "phx/resources/loaders/assimp_model_loader.hpp"
+#include "phx/resources/loaders/generic_material_loader.hpp"
 #include "phx/resources/loaders/image_loader.hpp"
 #include "phx/resources/loaders/shader_loader.hpp"
 
@@ -37,6 +38,7 @@ ResourceManager::ResourceManager() {
   this->RegisterMeshResourceExtensions();
   this->RegisterShaderResourceExtensions();
   this->RegisterImageResourceExtensions();
+  this->RegisterResourceGenerators();
 }
 
 void ResourceManager::RegisterResourceType(
@@ -91,4 +93,9 @@ void ResourceManager::RegisterImageResourceExtensions() {
   this->RegisterResourceType(".png", std::make_unique<ImageLoader>());
 }
 
+void ResourceManager::RegisterResourceGenerators() {
+  this->RegisterResourceType("GEN_MATERIAL",
+                             std::make_unique<GenericMaterialLoader>());
+}
+
 }  // namespace phx
diff --git a/library/phx/resources/resource_manager.hpp b/library/phx/resources/resource_manager.hpp
index 54cf258ca1a0b8cc9eb1c0c6ded2134152216a6f..a701b0673af3d49084b99ac3f27b6c6674ed61b6 100644
--- a/library/phx/resources/resource_manager.hpp
+++ b/library/phx/resources/resource_manager.hpp
@@ -28,12 +28,12 @@
 #include <string>
 
 #include "phx/core/logger.hpp"
+#include "phx/export.hpp"
 #include "phx/resources/resource_declaration.hpp"
 #include "phx/resources/resource_load_strategy.hpp"
 #include "phx/resources/resource_pointer.hpp"
 #include "phx/resources/resource_proxy.hpp"
 #include "phx/utility/aspects/singleton.hpp"
-#include "phx/export.hpp"
 
 namespace phx {
 /**
@@ -73,6 +73,8 @@ class PHOENIX_EXPORT ResourceManager final : public singleton<ResourceManager> {
   void RegisterMeshResourceExtensions();
   void RegisterImageResourceExtensions();
 
+  void RegisterResourceGenerators();
+
   std::map<std::string, std::unique_ptr<ResourceLoadStrategy>> loaders_by_type_;
   std::map<std::size_t, std::unique_ptr<ResourceProxy>> resources_;
 };
diff --git a/library/phx/resources/resource_utils.cpp b/library/phx/resources/resource_utils.cpp
index 3804fae89b37f689c34763a38e47933942da29df..f79aefd817b2b90614cd941e4d88dbbb7ffb6351 100644
--- a/library/phx/resources/resource_utils.cpp
+++ b/library/phx/resources/resource_utils.cpp
@@ -42,6 +42,22 @@ std::vector<std::string> default_resource_search_paths = {
 std::vector<std::string> ResourceUtils::resource_search_paths_{
     default_resource_search_paths};
 
+ResourceDeclaration ResourceUtils::GenericMaterialDeclaration(
+    const std::string& material_name, glm::vec3 diffuse_color,
+    glm::vec3 specular_color, glm::vec3 ambient_color, float shininess) {
+  ResourceDeclaration declaration = {{"TYPE", "GEN_MATERIAL"}};
+  declaration["material_name"] = material_name;
+
+  declaration["diffuse_color"] = {diffuse_color[0], diffuse_color[1],
+                                  diffuse_color[2]};
+  declaration["specular_color"] = {specular_color[0], specular_color[1],
+                                   specular_color[2]};
+  declaration["ambient_color"] = {ambient_color[0], ambient_color[1],
+                                  ambient_color[2]};
+  declaration["shininess"] = shininess;
+  return declaration;
+}
+
 void ResourceUtils::AddResourceSearchPath(const std::string& path_to_add) {
   assert(!path_to_add.empty());
   auto p = (path_to_add.back() == '/' ? path_to_add
@@ -72,6 +88,7 @@ ResourceDeclaration ResourceUtils::DeclarationFromFile(
   }
   return declaration;
 }
+
 std::string ResourceUtils::ExtractFileExtension(const std::string& file_name) {
   std::string extension = file_name.substr(file_name.rfind('.'));
   std::transform(extension.begin(), extension.end(), extension.begin(),
@@ -80,6 +97,18 @@ std::string ResourceUtils::ExtractFileExtension(const std::string& file_name) {
   return extension;
 }
 
+ResourcePointer<Material> ResourceUtils::LoadGenericMaterial(
+    const std::string& material_name, glm::vec3 diffuse_color,
+    glm::vec3 specular_color /*= Material::GetDefault()->GetSpecularColor()*/,
+    glm::vec3 ambient_color /*= Material::GetDefault()->GetAmbientColor()*/,
+    float shininess /*= Material::GetDefault()->GetShininess()*/) {
+  auto res_ptr = phx::ResourceManager::instance().DeclareResource<Material>(
+      GenericMaterialDeclaration(material_name, diffuse_color, specular_color,
+                                 ambient_color, shininess));
+  res_ptr.Load();
+  return res_ptr;
+}
+
 std::string ResourceUtils::FindFileInSearchPath(const std::string& file_name) {
   for (auto& entry : resource_search_paths_) {
     auto full_name = entry + file_name;
diff --git a/library/phx/resources/resource_utils.hpp b/library/phx/resources/resource_utils.hpp
index 95cba49f82f2601230288d4e65a948b376d436f0..06d925854fe6c76ac45f36469e476a742b5510c8 100644
--- a/library/phx/resources/resource_utils.hpp
+++ b/library/phx/resources/resource_utils.hpp
@@ -36,6 +36,7 @@
 #include "phx/resources/resource_load_strategy.hpp"
 #include "phx/resources/resource_manager.hpp"
 #include "phx/resources/resource_pointer.hpp"
+#include "phx/resources/types/material.hpp"
 #include "phx/utility/aspects/singleton.hpp"
 
 namespace phx {
@@ -49,6 +50,10 @@ namespace phx {
  */
 class PHOENIX_EXPORT ResourceUtils final {
  public:
+  static ResourceDeclaration GenericMaterialDeclaration(
+      const std::string& material_name, glm::vec3 diffuse_color,
+      glm::vec3 specular_color, glm::vec3 ambient_color, float shininess);
+
   static void AddResourceSearchPath(const std::string& path_to_add);
   static void ResetResourceSearchPath();
   static std::vector<std::string> GetResourceSearchPath();
@@ -59,6 +64,12 @@ class PHOENIX_EXPORT ResourceUtils final {
       const std::string& file_name, nlohmann::json additional_info = {},
       bool absolute_path = false);
 
+  static ResourcePointer<Material> LoadGenericMaterial(
+      const std::string& material_name, glm::vec3 diffuse_color,
+      glm::vec3 specular_color = Material::GetDefault()->GetSpecularColor(),
+      glm::vec3 ambient_color = Material::GetDefault()->GetAmbientColor(),
+      float shininess = Material::GetDefault()->GetShininess());
+
   template <class ResourceType>
   static ResourcePointer<ResourceType> LoadResourceFromFile(
       const std::string& file_name, nlohmann::json additional_info = {},
@@ -72,7 +83,6 @@ class PHOENIX_EXPORT ResourceUtils final {
 
  private:
   static std::string FindFileInSearchPath(const std::string& file_name);
-
   static std::vector<std::string> resource_search_paths_;
 };
 
diff --git a/tests/src/integration_test_opengl_buffer_data_download.cpp b/tests/src/integration_test_opengl_buffer_data_download.cpp
index 459f99ba1b3fc4785de28aaf5e70ce816e3a9bd6..237f49bd5455d3867d9fa9feb85596c1429f7193 100644
--- a/tests/src/integration_test_opengl_buffer_data_download.cpp
+++ b/tests/src/integration_test_opengl_buffer_data_download.cpp
@@ -46,7 +46,6 @@ SUPPRESS_WARNINGS_BEGIN
 #include "mocks/openvr_mock.hpp"
 SUPPRESS_WARNINGS_END
 
-#include "test_utilities/dummy_material_generator.hpp"
 #include "test_utilities/dummy_mesh_generator.hpp"
 #include "test_utilities/opengl_buffer_data_comparison.hpp"
 
@@ -91,14 +90,9 @@ class SceneSetupSimple {
     phx::Entity* triangle = scene->CreateEntity();
     triangle->AddComponent<phx::Transform>();
 
-    phx::ResourceManager::instance().RegisterResourceType(
-        "custommaterial",
-        std::make_unique<phx::DummyMaterialGenerator>(
-            glm::vec3(), glm::vec3(), glm::vec3(1.f, 0.5f, 0.25f), 500.0f));
-    auto material =
-        phx::ResourceManager::instance().DeclareResource<phx::Material>(
-            {{"TYPE", "custommaterial"}});
-    material.Load();
+    auto material = phx::ResourceUtils::LoadGenericMaterial(
+        "custommaterial", glm::vec3(), glm::vec3(), glm::vec3(1.f, 0.5f, 0.25f),
+        500.f);
 
     phx::MaterialHandle* material_handle =
         triangle->AddComponent<phx::MaterialHandle>();
diff --git a/tests/src/integration_test_rendering.cpp b/tests/src/integration_test_rendering.cpp
index dc65452c9256e81044b58ec3bb43507187e28de0..607b588d92db7d83bddd3a4933033188cafcdcac 100644
--- a/tests/src/integration_test_rendering.cpp
+++ b/tests/src/integration_test_rendering.cpp
@@ -43,7 +43,6 @@ SUPPRESS_WARNINGS_BEGIN
 #include "mocks/openvr_mock.hpp"
 SUPPRESS_WARNINGS_END
 
-#include "test_utilities/dummy_material_generator.hpp"
 #include "test_utilities/dummy_mesh_generator.hpp"
 #include "test_utilities/opengl_buffer_data_comparison.hpp"
 
@@ -108,14 +107,9 @@ SCENARIO("We can render a simple triangle", "[phx][phx::Rendering]") {
     phx::Entity* triangle = scene->CreateEntity();
     CreateTestTriangleComponent(triangle);
 
-    phx::ResourceManager::instance().RegisterResourceType(
-        "custommaterial", std::make_unique<phx::DummyMaterialGenerator>(
-                              glm::vec3(0.2f, 0.2f, 1.0f), glm::vec3(1, 1, 1),
-                              glm::vec3(), 500.0f));
-    auto material =
-        phx::ResourceManager::instance().DeclareResource<phx::Material>(
-            {{"TYPE", "custommaterial"}});
-    material.Load();
+    auto material = phx::ResourceUtils::LoadGenericMaterial(
+        "custommaterial", glm::vec3(0.2f, 0.2f, 1.0f), glm::vec3(1, 1, 1),
+        glm::vec3(), 500.0f);
 
     triangle->AddComponent<phx::Transform>();
     phx::MaterialHandle* material_handle =
diff --git a/tests/src/test_generic_material_loader.cpp b/tests/src/test_generic_material_loader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f602a4536aa89ca09ec477224c1e5a13cce51729
--- /dev/null
+++ b/tests/src/test_generic_material_loader.cpp
@@ -0,0 +1,90 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#include "catch/catch.hpp"
+
+#include "phx/resources/resource_utils.hpp"
+#include "phx/resources/types/material.hpp"
+
+#include "test_utilities/glm_vec3.hpp"
+
+SCENARIO("The Generic Material Loader can create Generic materials.",
+         "[phx][phx::GenericMaterialLoader]") {
+  GIVEN("A plain Generic Material Loader") {
+    WHEN("We load a red material") {
+      auto materialResource = phx::ResourceUtils::LoadGenericMaterial(
+          "generic_material", glm::vec3(1.f, 0.f, 0.f));
+
+      THEN("We have a material with the given name") {
+        REQUIRE(materialResource != nullptr);
+        REQUIRE(materialResource->GetName() == "generic_material");
+      }
+
+      THEN(
+          "The material is red, and specular color, ambient color and "
+          "shininess are set to default values.") {
+        auto diffuseColor = materialResource->GetDiffuseColor();
+        REQUIRE(diffuseColor == glm::vec3(1.0, 0.0, 0.0));
+
+        auto specularColor = materialResource->GetSpecularColor();
+        auto specularColorDefault =
+            phx::Material::GetDefault()->GetSpecularColor();
+        REQUIRE(specularColor == specularColorDefault);
+
+        auto ambientColor = materialResource->GetAmbientColor();
+        auto ambientColorDefault =
+            phx::Material::GetDefault()->GetAmbientColor();
+        REQUIRE(ambientColor == ambientColorDefault);
+
+        float shininess = materialResource->GetShininess();
+        REQUIRE(shininess == 64.0f);  //  default shininess value
+      }
+    }
+
+    WHEN(
+        "We load a different, more exotic material with some arbitrary "
+        "values") {
+      auto secondMaterial = phx::ResourceUtils::LoadGenericMaterial(
+          "generic_material_2", glm::vec3(0.4f, 0.3f, 0.55f),
+          glm::vec3(0.48f, 0.42f, 0.88f), glm::vec3(0.11f, 0.94f, 0.73f), 40.f);
+
+      THEN("We still get a material with the given name") {
+        REQUIRE(secondMaterial != nullptr);
+        REQUIRE(secondMaterial->GetName() == "generic_material_2");
+      }
+
+      THEN("All the values in the material are set to the right value.") {
+        auto diffuseColor = secondMaterial->GetDiffuseColor();
+        REQUIRE(diffuseColor == glm::vec3(0.4f, 0.3f, 0.55f));
+
+        auto specularColor = secondMaterial->GetSpecularColor();
+        REQUIRE(specularColor == glm::vec3(0.48f, 0.42f, 0.88f));
+
+        auto ambientColor = secondMaterial->GetAmbientColor();
+        REQUIRE(ambientColor == glm::vec3(0.11f, 0.94f, 0.73f));
+
+        float shininess = secondMaterial->GetShininess();
+        REQUIRE(shininess == 40.f);
+      }
+    }
+  }
+}