diff --git a/README.md b/README.md
index 96d15eafc..22de73638 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
MxEngine is an educational modern-C++ general-purpose 3D game engine.
-Right now MxEngine is developed only by me, [#Momo](https://github.com/MomoDeve), but any contributions are welcome and will be reviewed.
+Right now MxEngine is developed only by me, [#Momo](https://github.com/MomoDeve) and [#Lucas](https://github.com/fall2019) contributing some features from time to time. Any contributions are welcome and will be reviewed.
Fow now MxEngine supports OpenGL as graphic API and targets x64 only. I develop the project in my free time, so updates may be not so frequent!
***Note:** MxEngine is currently being ported to new Vulkan rendering backend. Development progress of the rendering library can be found here: [VulkanAbstractionLayer](https://github.com/asc-community/VulkanAbstractionLayer)*
@@ -292,9 +292,8 @@ If you are interesed in libraries MxEngine depend on, consider reading [dependen
shadow casting from dynamic lights, screen-space reflections
-## Special thanks
-#### God Ray Effect by [#Fall2019](https://github.com/fall2019)
+god ray effect
## Projects based on MxEngine
diff --git a/src/Core/Components/Camera/CameraController.cpp b/src/Core/Components/Camera/CameraController.cpp
index ab0229f9a..5c766c64d 100644
--- a/src/Core/Components/Camera/CameraController.cpp
+++ b/src/Core/Components/Camera/CameraController.cpp
@@ -27,6 +27,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "CameraController.h"
+#include "Utilities/Format/Format.h"
#include "Core/Events/WindowResizeEvent.h"
#include "Core/Config/GlobalConfig.h"
#include "Core/Application/Event.h"
@@ -425,11 +426,26 @@ namespace MxEngine
return this->renderBuffers->Material;
}
+ TextureHandle CameraController::GetSSRMask()const
+ {
+ return this->renderBuffers->SSRMask;
+ }
+
TextureHandle CameraController::GetDepthTexture() const
{
return this->renderBuffers->Depth;
}
+ const MxVector& CameraController::GetHiZ() const
+ {
+ return this->renderBuffers->HiZ;
+ }
+
+ const TextureHandle& CameraController::GetPackedDepth() const
+ {
+ return this->renderBuffers->PackedDepthMap;
+ }
+
TextureHandle CameraController::GetAverageWhiteTexture() const
{
return this->renderBuffers->AverageWhite;
@@ -456,23 +472,28 @@ namespace MxEngine
this->Albedo = Factory::Create();
this->Normal = Factory::Create();
this->Material = Factory::Create();
+ this->SSRMask = Factory::Create();
this->Depth = Factory::Create();
this->AverageWhite = Factory::Create();
this->HDR = Factory::Create();
this->SwapHDR1 = Factory::Create();
this->SwapHDR2 = Factory::Create();
+ for (int i = 0; i < 4; i++) this->HiZ.emplace_back(Factory::Create());
+ this->PackedDepthMap = Factory::Create();
this->Resize(width, height);
this->GBuffer->AttachTexture(this->Albedo, Attachment::COLOR_ATTACHMENT0);
this->GBuffer->AttachTextureExtra(this->Normal, Attachment::COLOR_ATTACHMENT1);
this->GBuffer->AttachTextureExtra(this->Material, Attachment::COLOR_ATTACHMENT2);
+ this->GBuffer->AttachTextureExtra(this->SSRMask, Attachment::COLOR_ATTACHMENT3);
this->GBuffer->AttachTextureExtra(this->Depth, Attachment::DEPTH_ATTACHMENT);
std::array attachments = {
Attachment::COLOR_ATTACHMENT0,
Attachment::COLOR_ATTACHMENT1,
Attachment::COLOR_ATTACHMENT2,
+ Attachment::COLOR_ATTACHMENT3
};
this->GBuffer->UseDrawBuffers(attachments);
this->GBuffer->Validate();
@@ -493,10 +514,29 @@ namespace MxEngine
this->Material->SetInternalEngineTag(MXENGINE_MAKE_INTERNAL_TAG("camera material"));
this->Material->SetWrapType(TextureWrap::CLAMP_TO_EDGE);
+ this->SSRMask->Load(nullptr, width, height, 1, false, TextureFormat::R32F);
+ this->SSRMask->SetInternalEngineTag(MXENGINE_MAKE_INTERNAL_TAG("ssr mask"));
+ this->SSRMask->SetWrapType(TextureWrap::CLAMP_TO_EDGE);
+
this->Depth->LoadDepth(width, height, TextureFormat::DEPTH32F);
this->Depth->SetInternalEngineTag(MXENGINE_MAKE_INTERNAL_TAG("camera depth"));
this->Depth->SetWrapType(TextureWrap::CLAMP_TO_EDGE);
+ for (int i = 0; i < this->HiZ.size(); i++)
+ {
+ int scale = 1 << (i + 1);
+ MxString tag = MxFormat("!camera depth lv{}", i + 1);
+ int w = width / scale;
+ int h = height / scale;
+ this->HiZ[i]->Load(nullptr, w, h, 1, false, TextureFormat::R32F);
+ this->HiZ[i]->SetInternalEngineTag(tag);
+ this->HiZ[i]->SetWrapType(TextureWrap::CLAMP_TO_EDGE);
+ }
+
+ this->PackedDepthMap->Load(nullptr, width, height * 1.5, 1, false, TextureFormat::R32F);
+ this->PackedDepthMap->SetInternalEngineTag(MXENGINE_MAKE_INTERNAL_TAG("packed depth map"));
+ this->PackedDepthMap->SetWrapType(TextureWrap::CLAMP_TO_EDGE);
+
this->AverageWhite->Load(nullptr, 1, 1, 3, false, TextureFormat::RGBA16F);
this->AverageWhite->SetInternalEngineTag(MXENGINE_MAKE_INTERNAL_TAG("camera white"));
this->AverageWhite->SetWrapType(TextureWrap::CLAMP_TO_EDGE);
@@ -520,10 +560,14 @@ namespace MxEngine
Factory::Destroy(this->Albedo);
Factory::Destroy(this->Normal);
Factory::Destroy(this->Material);
+ Factory::Destroy(this->SSRMask);
Factory::Destroy(this->Depth);
Factory::Destroy(this->HDR);
Factory::Destroy(this->SwapHDR1);
Factory::Destroy(this->SwapHDR2);
+ for (auto& it : this->HiZ)
+ Factory::Destroy(it);
+ Factory::Destroy(this->PackedDepthMap);
}
MXENGINE_REFLECT_TYPE
diff --git a/src/Core/Components/Camera/CameraController.h b/src/Core/Components/Camera/CameraController.h
index 73b885e33..8e198fd11 100644
--- a/src/Core/Components/Camera/CameraController.h
+++ b/src/Core/Components/Camera/CameraController.h
@@ -49,6 +49,9 @@ namespace MxEngine
TextureHandle Normal;
TextureHandle Material;
TextureHandle Depth;
+ TextureHandle SSRMask;
+ MxVector HiZ;
+ TextureHandle PackedDepthMap;
TextureHandle AverageWhite;
TextureHandle HDR;
TextureHandle SwapHDR1;
@@ -130,7 +133,10 @@ namespace MxEngine
TextureHandle GetAlbedoTexture() const;
TextureHandle GetNormalTexture() const;
TextureHandle GetMaterialTexture() const;
+ TextureHandle GetSSRMask()const;
TextureHandle GetDepthTexture() const;
+ const MxVector& GetHiZ() const;
+ const TextureHandle& GetPackedDepth() const;
TextureHandle GetAverageWhiteTexture() const;
TextureHandle GetHDRTexture() const;
TextureHandle GetSwapHDRTexture1() const;
diff --git a/src/Core/Components/Camera/CameraSSR.cpp b/src/Core/Components/Camera/CameraSSR.cpp
index 99ccf69bf..31c2e698b 100644
--- a/src/Core/Components/Camera/CameraSSR.cpp
+++ b/src/Core/Components/Camera/CameraSSR.cpp
@@ -37,31 +37,31 @@ namespace MxEngine
return this->thickness;
}
- size_t CameraSSR::GetSteps() const
+ void CameraSSR::SetThickness(float thickness)
{
- return this->steps;
+ this->thickness = Max(thickness, 1.0f);
}
- float CameraSSR::GetStartDistance() const
+ int CameraSSR::GetMaxLevel() const
{
- return this->startDistance;
+ return this->maxLevel;
}
- void CameraSSR::SetThickness(float thickness)
+ void CameraSSR::SetMaxLevel(int level)
{
- this->thickness = Max(thickness, 0.0f);
+ this->maxLevel = Clamp(level,1,4);
}
- void CameraSSR::SetSteps(size_t steps)
+ int CameraSSR::GetMaxStep()const
{
- this->steps = steps;
+ return this->maxStep;
}
- void CameraSSR::SetStartDistance(float distance)
+ void CameraSSR::SetMaxStep(int step)
{
- this->startDistance = Max(distance, 0.0f);
+ this->maxStep = Clamp(step,150,255);
}
-
+
MXENGINE_REFLECT_TYPE
{
rttr::registration::class_("CameraSSR")
@@ -72,19 +72,19 @@ namespace MxEngine
.property("thickness", &CameraSSR::GetThickness, &CameraSSR::SetThickness)
(
rttr::metadata(MetaInfo::FLAGS, MetaInfo::SERIALIZABLE | MetaInfo::EDITABLE),
- rttr::metadata(EditorInfo::EDIT_RANGE, Range { 0.0f, 10000.0f }),
+ rttr::metadata(EditorInfo::EDIT_RANGE, Range { 0.5f, 20.0f }),
rttr::metadata(EditorInfo::EDIT_PRECISION, 0.01f)
)
- .property("steps", &CameraSSR::GetSteps, &CameraSSR::SetSteps)
+ .property("max level", &CameraSSR::GetMaxLevel, &CameraSSR::SetMaxLevel)
(
rttr::metadata(MetaInfo::FLAGS, MetaInfo::SERIALIZABLE | MetaInfo::EDITABLE),
- rttr::metadata(EditorInfo::EDIT_RANGE, Range { 0.0f, 128.0f }),
- rttr::metadata(EditorInfo::EDIT_PRECISION, 0.1f)
+ rttr::metadata(EditorInfo::EDIT_RANGE, Range { 1, 4 }),
+ rttr::metadata(EditorInfo::EDIT_PRECISION, 1)
)
- .property("start distance", &CameraSSR::GetStartDistance, &CameraSSR::SetStartDistance)
+ .property("maxStep", &CameraSSR::GetMaxStep, &CameraSSR::SetMaxStep)
(
rttr::metadata(MetaInfo::FLAGS, MetaInfo::SERIALIZABLE | MetaInfo::EDITABLE),
- rttr::metadata(EditorInfo::EDIT_RANGE, Range { 0.0f, 10000000.0f }),
+ rttr::metadata(EditorInfo::EDIT_RANGE, Range { 150, 255 }),
rttr::metadata(EditorInfo::EDIT_PRECISION, 0.01f)
);
}
diff --git a/src/Core/Components/Camera/CameraSSR.h b/src/Core/Components/Camera/CameraSSR.h
index ff5d75a7b..09d5ea80f 100644
--- a/src/Core/Components/Camera/CameraSSR.h
+++ b/src/Core/Components/Camera/CameraSSR.h
@@ -36,18 +36,20 @@ namespace MxEngine
{
MAKE_COMPONENT(CameraSSR);
- float thickness = 0.5f;
- size_t steps = 10;
- float startDistance = 2.0f;
+ float thickness = 1.5f;
+ int maxLevel = 2;
+ int maxStep = 150;
+
public:
CameraSSR() = default;
float GetThickness() const;
- size_t GetSteps() const;
- float GetStartDistance() const;
+ int GetMaxLevel()const;
+ int GetMaxStep()const;
void SetThickness(float thickness);
- void SetSteps(size_t steps);
- void SetStartDistance(float distance);
+ void SetMaxLevel(int level);
+ void SetMaxStep(int step);
+
};
}
\ No newline at end of file
diff --git a/src/Core/Rendering/RenderAdaptor.cpp b/src/Core/Rendering/RenderAdaptor.cpp
index 78ef8b50f..29ba68bcb 100644
--- a/src/Core/Rendering/RenderAdaptor.cpp
+++ b/src/Core/Rendering/RenderAdaptor.cpp
@@ -143,6 +143,11 @@ namespace MxEngine
shaderFolder / "gbuffer_fragment.glsl"
);
+ environment.Shaders["HIZ"_id] = AssetManager::LoadShader(
+ shaderFolder / "rect_vertex.glsl",
+ shaderFolder / "hierarchical_depth_buffer_generator.glsl"
+ );
+
environment.Shaders["GBufferMask"_id] = AssetManager::LoadShader(
shaderFolder / "gbuffer_vertex.glsl",
shaderFolder / "gbuffer_mask_fragment.glsl"
diff --git a/src/Core/Rendering/RenderController.cpp b/src/Core/Rendering/RenderController.cpp
index 79a0fb3fb..dcb3d7ce9 100644
--- a/src/Core/Rendering/RenderController.cpp
+++ b/src/Core/Rendering/RenderController.cpp
@@ -79,11 +79,11 @@ namespace MxEngine
);
generatorMasked.GenerateFor(
*this->Pipeline.Environment.Shaders["DirLightMaskDepthMap"_id],
- this->Pipeline.Lighting.DirectionalLights,
+ this->Pipeline.Lighting.DirectionalLights,
ShadowMapGenerator::LoadStoreOptions::LOAD
);
}
-
+
if (hasSpotLights)
{
MAKE_RENDER_PASS_SCOPE("RenderController::PrepareSpotLightMaps()");
@@ -91,13 +91,13 @@ namespace MxEngine
*this->Pipeline.Environment.Shaders["SpotLightDepthMap"_id],
this->Pipeline.Lighting.SpotLights,
ShadowMapGenerator::LoadStoreOptions::CLEAR
- );
+ );
generatorMasked.GenerateFor(
*this->Pipeline.Environment.Shaders["SpotLightMaskDepthMap"_id],
this->Pipeline.Lighting.SpotLights,
ShadowMapGenerator::LoadStoreOptions::LOAD
- );
- }
+ );
+ }
if (hasPointLights)
{
@@ -223,6 +223,9 @@ namespace MxEngine
shader.IgnoreNonExistingUniform("camera.position");
shader.IgnoreNonExistingUniform("camera.invViewProjMatrix");
shader.IgnoreNonExistingUniform("material.transparency");
+ shader.IgnoreNonExistingUniform("camera.viewMatrix");
+ shader.IgnoreNonExistingUniform("camera.projectionMatrix");
+ shader.IgnoreNonExistingUniform("camera.invProjectionMatrix");
this->BindCameraInformation(camera, shader);
shader.SetUniform("gamma", camera.Gamma);
@@ -277,6 +280,8 @@ namespace MxEngine
shader.SetUniform("parentModel", unit.ModelMatrix); //-V807
shader.SetUniform("parentNormal", unit.NormalMatrix);
shader.SetUniform("parentColor", material.BaseColor);
+
+ shader.SetUniform("receiveSSR", static_cast(material.ReceiveSSR));
this->DrawIndices(RenderPrimitive::TRIANGLES, unit.IndexCount, unit.IndexOffset, unit.VertexOffset, instanceCount, baseInstance);
}
@@ -322,6 +327,9 @@ namespace MxEngine
ssaoShader->IgnoreNonExistingUniform("materialTex");
ssaoShader->IgnoreNonExistingUniform("albedoTex");
ssaoShader->IgnoreNonExistingUniform("camera.position");
+ ssaoShader->IgnoreNonExistingUniform("camera.viewMatrix");
+ ssaoShader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ ssaoShader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
Texture::TextureBindId textureId = 0;
this->BindGBuffer(camera, *ssaoShader, textureId);
@@ -352,11 +360,41 @@ namespace MxEngine
std::swap(input, output);
}
- void RenderController::GenerateDepthPyramid(TextureHandle& depth)
+ void RenderController::GenerateDepthPyramid(CameraUnit& camera)
{
MAKE_RENDER_PASS_SCOPE("RenderController::GenerateDepthPyramid()");
- // generate depth texture mipmaps for post-processing algorithms. Replace later with hierarhical depth map
- depth->GenerateMipmaps();
+ auto& shader = this->Pipeline.Environment.Shaders["HIZ"_id];
+ auto& zBuffer = camera.DepthTexture;
+ auto& HiZ = camera.HiZ;
+
+ auto fGetTex = [&zBuffer, &HiZ](int layer)->TextureHandle&
+ {
+ if (layer == 0)
+ return zBuffer;
+ else
+ return HiZ[layer - 1];
+ };
+
+ int w = zBuffer->GetWidth();
+ int h = zBuffer->GetHeight();
+ Texture::Copy(zBuffer->GetNativeHandle(), camera.PackedDepth->GetNativeHandle(), 0, 0, w, h);
+ w = h = 0;
+ camera.PackedDepthOrigins[0] = { 0.0,0.0 };
+ for (int i = 0; i < HiZ.size(); i++)
+ {
+ shader->Bind();
+ auto& inputTex = fGetTex(i);
+ inputTex->Bind(0);
+ auto& outputTex = fGetTex(i + 1);
+ shader->SetUniform("uPreviousLevelRes", VectorInt2(outputTex->GetWidth(), outputTex->GetHeight()));
+ this->RenderToTexture(outputTex, shader);
+ if (i & 1)
+ w += inputTex->GetWidth();
+ else
+ h += inputTex->GetHeight();
+ camera.PackedDepthOrigins[i + 1] = { w,h };
+ Texture::Copy(outputTex->GetNativeHandle(), camera.PackedDepth->GetNativeHandle(), w, h, outputTex->GetWidth(), outputTex->GetHeight());
+ }
}
TextureHandle RenderController::ComputeAverageWhite(CameraUnit& camera)
@@ -433,6 +471,9 @@ namespace MxEngine
shader->IgnoreNonExistingUniform("camera.viewProjMatrix");
shader->IgnoreNonExistingUniform("camera.position");
+ shader->IgnoreNonExistingUniform("camera.viewMatrix");
+ shader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ shader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
shader->IgnoreNonExistingUniform("albedoTex");
shader->IgnoreNonExistingUniform("materialTex");
@@ -518,6 +559,9 @@ namespace MxEngine
auto shader = this->Pipeline.Environment.Shaders["IBL"_id];
shader->Bind();
shader->IgnoreNonExistingUniform("camera.viewProjMatrix");
+ shader->IgnoreNonExistingUniform("camera.viewMatrix");
+ shader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ shader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
Texture::TextureBindId textureId = 0;
this->BindGBuffer(camera, *shader, textureId);
@@ -570,6 +614,9 @@ namespace MxEngine
auto godRayShader = this->Pipeline.Environment.Shaders["GodRay"_id];
godRayShader->Bind();
godRayShader->IgnoreNonExistingUniform("camera.viewProjMatrix");
+ godRayShader->IgnoreNonExistingUniform("camera.viewMatrix");
+ godRayShader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ godRayShader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
godRayShader->IgnoreNonExistingUniform("normalTex");
godRayShader->IgnoreNonExistingUniform("albedoTex");
godRayShader->IgnoreNonExistingUniform("materialTex");
@@ -607,6 +654,9 @@ namespace MxEngine
auto fogShader = this->Pipeline.Environment.Shaders["Fog"_id];
fogShader->Bind();
fogShader->IgnoreNonExistingUniform("camera.viewProjMatrix");
+ fogShader->IgnoreNonExistingUniform("camera.viewMatrix");
+ fogShader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ fogShader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
fogShader->IgnoreNonExistingUniform("normalTex");
fogShader->IgnoreNonExistingUniform("albedoTex");
fogShader->IgnoreNonExistingUniform("materialTex");
@@ -643,23 +693,33 @@ namespace MxEngine
std::swap(input, output);
}
+
void RenderController::ApplySSR(CameraUnit& camera, TextureHandle& input, TextureHandle& temporary, TextureHandle& output)
{
- if (camera.SSR == nullptr || camera.SSR->GetSteps() == 0) return;
- MAKE_RENDER_PASS_SCOPE("RenderController::ApplySSR()");
-
- auto& SSRShader = this->Pipeline.Environment.Shaders["SSR"_id];
- SSRShader->Bind();
+ if (camera.SSR == nullptr ) return;
+
+ int level = camera.SSR->GetMaxLevel();
+#if defined(MXENGINE_PROFILING_ENABLED)
+ auto profilerTitle = MxFormat("RenderController::ApplySSR(level={})", level);
+ MAKE_RENDER_PASS_SCOPE(profilerTitle.c_str());
+#endif
+ auto& SSRShader = this->Pipeline.Environment.Shaders["SSR"_id];
+ SSRShader->Bind();
SSRShader->IgnoreNonExistingUniform("albedoTex");
SSRShader->IgnoreNonExistingUniform("materialTex");
+ SSRShader->IgnoreNonExistingUniform("camera.viewProjMatrix");
Texture::TextureBindId textureId = 0;
this->BindGBuffer(camera, *SSRShader, textureId);
this->BindCameraInformation(camera, *SSRShader);
+ SSRShader->SetUniform("ssrMask", camera.SSRMaskTexture->GetBoundId());
+ camera.SSRMaskTexture->Bind(textureId++);
+ this->BindHiZ(camera, *SSRShader, textureId);
SSRShader->SetUniform("thickness", camera.SSR->GetThickness());
- SSRShader->SetUniform("startDistance", camera.SSR->GetStartDistance());
- SSRShader->SetUniform("steps", (int)camera.SSR->GetSteps());
+ SSRShader->SetUniform("screenResolution", Vector2(camera.HDRTexture->GetWidth(), camera.HDRTexture->GetHeight()));
+ SSRShader->SetUniform("maxLevel", level);
+ SSRShader->SetUniform("maxStep", camera.SSR->GetMaxStep());
this->RenderToTexture(temporary, SSRShader);
@@ -692,6 +752,9 @@ namespace MxEngine
SSGIShader->IgnoreNonExistingUniform("normalTex");
SSGIShader->IgnoreNonExistingUniform("materialTex");
SSGIShader->IgnoreNonExistingUniform("camera.position");
+ SSGIShader->IgnoreNonExistingUniform("camera.viewMatrix");
+ SSGIShader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ SSGIShader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
Texture::TextureBindId textureId = 0;
this->BindGBuffer(camera, *SSGIShader, textureId);
@@ -738,6 +801,9 @@ namespace MxEngine
auto cocShader = this->Pipeline.Environment.Shaders["COC"_id];
cocShader->Bind();
+ cocShader->IgnoreNonExistingUniform("camera.viewMatrix");
+ cocShader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ cocShader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
cocShader->IgnoreNonExistingUniform("camera.viewProjMatrix");
cocShader->IgnoreNonExistingUniform("normalTex");
cocShader->IgnoreNonExistingUniform("albedoTex");
@@ -855,6 +921,9 @@ namespace MxEngine
auto shader = this->Pipeline.Environment.Shaders["SpotLightShadow"_id];
shader->Bind();
shader->IgnoreNonExistingUniform("camera.position");
+ shader->IgnoreNonExistingUniform("camera.viewMatrix");
+ shader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ shader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
shader->IgnoreNonExistingUniform("albedoTex");
shader->IgnoreNonExistingUniform("materialTex");
@@ -898,6 +967,9 @@ namespace MxEngine
auto shader = this->Pipeline.Environment.Shaders["PointLightShadow"_id];
shader->Bind();
shader->IgnoreNonExistingUniform("camera.position");
+ shader->IgnoreNonExistingUniform("camera.viewMatrix");
+ shader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ shader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
shader->IgnoreNonExistingUniform("albedoTex");
shader->IgnoreNonExistingUniform("materialTex");
@@ -938,6 +1010,9 @@ namespace MxEngine
auto shader = this->Pipeline.Environment.Shaders["PointLightNonShadow"_id];
shader->Bind();
shader->IgnoreNonExistingUniform("camera.position");
+ shader->IgnoreNonExistingUniform("camera.viewMatrix");
+ shader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ shader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
shader->IgnoreNonExistingUniform("albedoTex");
shader->IgnoreNonExistingUniform("materialTex");
auto viewportSize = MakeVector2((float)camera.OutputTexture->GetWidth(), (float)camera.OutputTexture->GetHeight());
@@ -968,6 +1043,9 @@ namespace MxEngine
auto shader = this->Pipeline.Environment.Shaders["SpotLightNonShadow"_id];
shader->Bind();
+ shader->IgnoreNonExistingUniform("camera.viewMatrix");
+ shader->IgnoreNonExistingUniform("camera.projectionMatrix");
+ shader->IgnoreNonExistingUniform("camera.invProjectionMatrix");
shader->IgnoreNonExistingUniform("camera.position");
shader->IgnoreNonExistingUniform("albedoTex");
shader->IgnoreNonExistingUniform("materialTex");
@@ -1029,11 +1107,13 @@ namespace MxEngine
shader.SetUniform("camera.position", camera.ViewportPosition);
shader.SetUniform("camera.viewProjMatrix", camera.ViewProjectionMatrix);
shader.SetUniform("camera.invViewProjMatrix", camera.InverseViewProjMatrix);
+ shader.SetUniform("camera.viewMatrix", camera.ViewMatrix);
+ shader.SetUniform("camera.projectionMatrix", camera.ProjectionMatrix);
+ shader.SetUniform("camera.invProjectionMatrix", Inverse(camera.ProjectionMatrix));
}
-
void RenderController::BindGBuffer(const CameraUnit& camera, const Shader& shader, Texture::TextureBindId& startId)
{
- camera.AlbedoTexture->Bind(startId++);
+ camera.AlbedoTexture->Bind(startId++);
camera.NormalTexture->Bind(startId++);
camera.MaterialTexture->Bind(startId++);
camera.DepthTexture->Bind(startId++);
@@ -1044,8 +1124,17 @@ namespace MxEngine
shader.SetUniform("depthTex", camera.DepthTexture->GetBoundId());
}
- const Renderer& RenderController::GetRenderEngine() const
+ void RenderController::BindHiZ(const CameraUnit& camera, const Shader& shader, Texture::TextureBindId& startId)
{
+ camera.PackedDepth->Bind(startId++);
+ shader.SetUniform("depthPyramid", camera.PackedDepth->GetBoundId());
+
+ for (int i = 0; i < camera.PackedDepthOrigins.size(); i++)
+ shader.SetUniform(MxFormat("basePositions[{}]", i), camera.PackedDepthOrigins[i]);
+ }
+
+ const Renderer& RenderController::GetRenderEngine() const
+ {
return this->renderer;
}
@@ -1443,7 +1532,7 @@ namespace MxEngine
}
void RenderController::SubmitCamera(
- const CameraController& controller,
+ const CameraController& cameraController,
const Transform& parentTransform,
const Skybox* skybox,
const CameraEffects* effects,
@@ -1455,28 +1544,33 @@ namespace MxEngine
{
auto& camera = this->Pipeline.Cameras.emplace_back();
- bool isPerspective = controller.GetCameraType() == CameraType::PERSPECTIVE;
+ bool isPerspective = cameraController.GetCameraType() == CameraType::PERSPECTIVE;
bool hasSkybox = skybox != nullptr;
bool hasToneMapping = toneMapping != nullptr;
camera.ViewportPosition = parentTransform.GetPosition();
- camera.AspectRatio = controller.Camera.GetAspectRatio();
- camera.StaticViewProjectionMatrix = controller.GetMatrix(MakeVector3(0.0f));
- camera.ViewProjectionMatrix = controller.GetMatrix(parentTransform.GetPosition());
+ camera.AspectRatio = cameraController.Camera.GetAspectRatio();
+ camera.StaticViewProjectionMatrix = cameraController.GetMatrix(MakeVector3(0.0f));
+ camera.ViewMatrix = cameraController.GetViewMatrix(parentTransform.GetPosition());
+ camera.ProjectionMatrix = cameraController.GetProjectionMatrix();
+ camera.ViewProjectionMatrix = cameraController.GetMatrix(parentTransform.GetPosition());
camera.InverseViewProjMatrix = Inverse(camera.ViewProjectionMatrix);
- camera.Culler = controller.GetFrustrumCuller();
- camera.IsPerspective = controller.GetCameraType() == CameraType::PERSPECTIVE;
- camera.GBuffer = controller.GetGBuffer();
- camera.AlbedoTexture = controller.GetAlbedoTexture();
- camera.NormalTexture = controller.GetNormalTexture();
- camera.MaterialTexture = controller.GetMaterialTexture();
- camera.DepthTexture = controller.GetDepthTexture();
- camera.AverageWhiteTexture = controller.GetAverageWhiteTexture();
- camera.HDRTexture = controller.GetHDRTexture();
- camera.SwapTexture1 = controller.GetSwapHDRTexture1();
- camera.SwapTexture2 = controller.GetSwapHDRTexture2();
- camera.OutputTexture = controller.GetRenderTexture();
- camera.RenderToTexture = controller.IsRendering();
+ camera.Culler = cameraController.GetFrustrumCuller();
+ camera.IsPerspective = cameraController.GetCameraType() == CameraType::PERSPECTIVE;
+ camera.GBuffer = cameraController.GetGBuffer();
+ camera.AlbedoTexture = cameraController.GetAlbedoTexture();
+ camera.NormalTexture = cameraController.GetNormalTexture();
+ camera.MaterialTexture = cameraController.GetMaterialTexture();
+ camera.SSRMaskTexture = cameraController.GetSSRMask();
+ camera.DepthTexture = cameraController.GetDepthTexture();
+ camera.HiZ = cameraController.GetHiZ();
+ camera.PackedDepth = cameraController.GetPackedDepth();
+ camera.AverageWhiteTexture = cameraController.GetAverageWhiteTexture();
+ camera.HDRTexture = cameraController.GetHDRTexture();
+ camera.SwapTexture1 = cameraController.GetSwapHDRTexture1();
+ camera.SwapTexture2 = cameraController.GetSwapHDRTexture2();
+ camera.OutputTexture = cameraController.GetRenderTexture();
+ camera.RenderToTexture = cameraController.IsRendering();
camera.SkyboxTexture = hasSkybox && skybox->CubeMap.IsValid() ? skybox->CubeMap : this->Pipeline.Environment.DefaultSkybox;
camera.IrradianceTexture = hasSkybox && skybox->Irradiance.IsValid() ? skybox->Irradiance : camera.SkyboxTexture;
camera.SkyboxIntensity = hasSkybox ? skybox->GetIntensity() : Skybox::DefaultIntensity;
@@ -1626,7 +1720,7 @@ namespace MxEngine
this->DrawObjects(camera, *this->Pipeline.Environment.Shaders["GBuffer"_id], this->Pipeline.OpaqueObjects);
this->DrawObjects(camera, *this->Pipeline.Environment.Shaders["GBufferMask"_id], this->Pipeline.MaskedObjects);
- this->GenerateDepthPyramid(camera.DepthTexture);
+ this->GenerateDepthPyramid(camera);
this->DrawParticles(camera, this->Pipeline.OpaqueParticleSystems, *this->Pipeline.Environment.Shaders["ParticleOpaque"_id]);
diff --git a/src/Core/Rendering/RenderController.h b/src/Core/Rendering/RenderController.h
index 2aa40502c..190dd0efd 100644
--- a/src/Core/Rendering/RenderController.h
+++ b/src/Core/Rendering/RenderController.h
@@ -62,7 +62,7 @@ namespace MxEngine
void DrawObject(const RenderUnit& unit, size_t instanceCount, size_t baseInstance, const Shader& shader);
void ComputeBloomEffect(CameraUnit& camera, const TextureHandle& output);
TextureHandle ComputeAverageWhite(CameraUnit& camera);
- void GenerateDepthPyramid(TextureHandle& depth);
+ void GenerateDepthPyramid(CameraUnit& camera);
void PerformPostProcessing(CameraUnit& camera);
void PerformLightPass(CameraUnit& camera);
void DrawTransparentObjects(CameraUnit& camera);
@@ -86,6 +86,7 @@ namespace MxEngine
void SubmitInstancedLights();
void SubmitDirectionalLightInformation(ShaderHandle& shader, Texture::TextureBindId textureId);
void BindGBuffer(const CameraUnit& camera, const Shader& shader, Texture::TextureBindId& startId);
+ void BindHiZ(const CameraUnit& camera, const Shader& shader, Texture::TextureBindId& startId);
void BindSkyboxInformation(const CameraUnit& camera, const Shader& shader, Texture::TextureBindId& startId);
void BindCameraInformation(const CameraUnit& camera, const Shader& shader);
void BindFogInformation(const CameraUnit& camera, const Shader& shader);
diff --git a/src/Core/Rendering/RenderPipeline.h b/src/Core/Rendering/RenderPipeline.h
index 8b7b3c701..918a84a45 100644
--- a/src/Core/Rendering/RenderPipeline.h
+++ b/src/Core/Rendering/RenderPipeline.h
@@ -62,6 +62,10 @@ namespace MxEngine
TextureHandle NormalTexture;
TextureHandle MaterialTexture;
TextureHandle DepthTexture;
+ TextureHandle SSRMaskTexture;
+ MxVector< TextureHandle> HiZ;
+ TextureHandle PackedDepth;
+ std::array PackedDepthOrigins;
TextureHandle AverageWhiteTexture;
TextureHandle HDRTexture;
TextureHandle SwapTexture1;
@@ -70,6 +74,8 @@ namespace MxEngine
FrustrumCuller Culler;
Matrix4x4 InverseViewProjMatrix;
Matrix4x4 ViewProjectionMatrix;
+ Matrix4x4 ViewMatrix;
+ Matrix4x4 ProjectionMatrix;
Matrix4x4 StaticViewProjectionMatrix;
TextureHandle OutputTexture;
diff --git a/src/Core/Resources/Material.cpp b/src/Core/Resources/Material.cpp
index 2df5459ab..a7b6ebf94 100644
--- a/src/Core/Resources/Material.cpp
+++ b/src/Core/Resources/Material.cpp
@@ -57,6 +57,10 @@ namespace MxEngine
(
rttr::metadata(MetaInfo::FLAGS, MetaInfo::SERIALIZABLE | MetaInfo::EDITABLE)
)
+ .property("receive SSR", &Material::ReceiveSSR)
+ (
+ rttr::metadata(MetaInfo::FLAGS, MetaInfo::SERIALIZABLE | MetaInfo::EDITABLE)
+ )
.property("normal map", &Material::NormalMap)
(
rttr::metadata(MetaInfo::FLAGS, MetaInfo::SERIALIZABLE | MetaInfo::EDITABLE)
diff --git a/src/Core/Resources/Material.h b/src/Core/Resources/Material.h
index 00ae21025..b98735f61 100644
--- a/src/Core/Resources/Material.h
+++ b/src/Core/Resources/Material.h
@@ -59,6 +59,7 @@ namespace MxEngine
float RoughnessFactor = 0.75f;
float MetallicFactor = 0.0f;
+ bool ReceiveSSR = false;
Vector3 BaseColor{ 1.0f };
Vector2 UVMultipliers{ 1.0f };
AlphaModeGroup AlphaMode = AlphaModeGroup::OPAQUE;
diff --git a/src/Platform/OpenGL/Shaders/Library/common_utils.glsl b/src/Platform/OpenGL/Shaders/Library/common_utils.glsl
index abd47b755..fd02a9660 100644
--- a/src/Platform/OpenGL/Shaders/Library/common_utils.glsl
+++ b/src/Platform/OpenGL/Shaders/Library/common_utils.glsl
@@ -3,6 +3,9 @@ struct Camera
vec3 position;
mat4 viewProjMatrix;
mat4 invViewProjMatrix;
+ mat4 viewMatrix;
+ mat4 projectionMatrix;
+ mat4 invProjectionMatrix;
};
vec3 reconstructWorldPosition(float depth, vec2 texcoord, mat4 invViewProjMatrix)
{
diff --git a/src/Platform/OpenGL/Shaders/gbuffer_fragment.glsl b/src/Platform/OpenGL/Shaders/gbuffer_fragment.glsl
index 712e5450e..9497c8013 100644
--- a/src/Platform/OpenGL/Shaders/gbuffer_fragment.glsl
+++ b/src/Platform/OpenGL/Shaders/gbuffer_fragment.glsl
@@ -13,6 +13,7 @@ in VSout
layout(location = 0) out vec4 OutAlbedo;
layout(location = 1) out vec4 OutNormal;
layout(location = 2) out vec4 OutMaterial;
+layout(location = 3) out vec4 OutSSRMask;
struct Material
{
@@ -34,6 +35,7 @@ uniform vec2 uvMultipliers;
uniform float displacement;
uniform float gamma;
uniform Camera camera;
+uniform float receiveSSR;
vec3 calcNormal(vec2 texcoord, mat3 TBN, sampler2D normalMap)
{
@@ -68,4 +70,5 @@ void main()
OutAlbedo = vec4(fsin.RenderColor * albedo, emmisive / (emmisive + 1.0f));
OutNormal = vec4(0.5f * normal + 0.5f, 1.0f);
OutMaterial = vec4(parallaxOcclusion * occlusion, roughness, metallic, 1.0f);
+ OutSSRMask = vec4(receiveSSR, vec3(1.0));
}
\ No newline at end of file
diff --git a/src/Platform/OpenGL/Shaders/hierarchical_depth_buffer_generator.glsl b/src/Platform/OpenGL/Shaders/hierarchical_depth_buffer_generator.glsl
new file mode 100644
index 000000000..62dbc8065
--- /dev/null
+++ b/src/Platform/OpenGL/Shaders/hierarchical_depth_buffer_generator.glsl
@@ -0,0 +1,46 @@
+layout(binding = 0) uniform sampler2D depthBuffer;
+uniform ivec2 uPreviousLevelRes;
+
+out vec4 OutColor;
+
+void main()
+{
+ ivec2 currentTexCoord = ivec2(gl_FragCoord);
+ ivec2 lastTexCoord = 2 * currentTexCoord;
+
+ vec4 depth;
+ depth.x = texelFetch(depthBuffer, lastTexCoord, 0).r;
+ depth.y = texelFetch(depthBuffer, lastTexCoord + ivec2(1, 0), 0).r;
+ depth.z = texelFetch(depthBuffer, lastTexCoord + ivec2(1, 1),0).r;
+ depth.w = texelFetch(depthBuffer, lastTexCoord + ivec2(0, 1), 0).r;
+
+ //Depth is reversed.The closer to the object the higher depth we get.
+ //So instead of min pooling we perform max pooling.
+ float maxDepth = max( max(depth.x, depth.y),
+ max(depth.z, depth.w));
+
+ bool extraCol = ((uPreviousLevelRes.x & 1) != 0);
+ bool extraRow = ((uPreviousLevelRes.y & 1) != 0);
+ if (extraCol)
+ {
+ vec2 col;
+ col.x = texelFetch(depthBuffer, lastTexCoord + ivec2(2, 0), 0).r;
+ col.y = texelFetch(depthBuffer, lastTexCoord + ivec2(2, 1), 0).r;
+
+ if (extraRow)
+ {
+ float corner = texelFetch(depthBuffer, lastTexCoord + ivec2(2, 2), 0).r;
+ maxDepth = max(maxDepth, corner);
+ }
+ maxDepth = max(maxDepth, max(col.x, col.y));
+ }
+ if (extraRow)
+ {
+ vec2 row;
+ row.x = texelFetch(depthBuffer, lastTexCoord + ivec2(0, 2), 0).r;
+ row.y = texelFetch(depthBuffer, lastTexCoord + ivec2(1, 2), 0).r;
+ maxDepth = max(maxDepth, max(row.x, row.y));
+ }
+
+ OutColor = vec4(maxDepth, 0.0, 0.0, 1.0);
+}
diff --git a/src/Platform/OpenGL/Shaders/ssr_fragment.glsl b/src/Platform/OpenGL/Shaders/ssr_fragment.glsl
index bb354b28b..4d6d41030 100644
--- a/src/Platform/OpenGL/Shaders/ssr_fragment.glsl
+++ b/src/Platform/OpenGL/Shaders/ssr_fragment.glsl
@@ -7,55 +7,164 @@ uniform sampler2D albedoTex;
uniform sampler2D normalTex;
uniform sampler2D materialTex;
uniform sampler2D depthTex;
+uniform sampler2D ssrMask;
uniform sampler2D HDRTex;
+uniform sampler2D depthPyramid;
uniform Camera camera;
uniform EnvironmentInfo environment;
-uniform int steps;
uniform float thickness;
-uniform float startDistance;
+uniform vec2 screenResolution;
+uniform int maxLevel;
+uniform int maxStep;
-void main()
+uniform ivec2 basePositions[5];
+float sampleDepth(ivec2 uv, int level)
+{
+ ivec2 div = ivec2(1 << level);
+ ivec2 base = basePositions[level];
+ return texelFetch(depthPyramid, base + uv / div, 0).r;
+}
+
+vec3 transform(mat4 m, vec3 p)
{
- FragmentInfo fragment = getFragmentInfo(TexCoord, albedoTex, normalTex, materialTex, depthTex, camera.invViewProjMatrix);
+ vec4 temp = m * vec4(p, 1.0);
+ return temp.xyz;
+}
+vec4 transform(mat4 m, vec4 p)
+{
+ return m * p;
+}
+
+void swapComp(inout vec2 v)
+{
+ v = v.yx;
+}
+
+#define TRACE_RAY(stp) \
+ do {\
+ scr0 += dScr * stp;\
+ vpProj0.z += dVpProj.z * stp;\
+ w0 += dw * stp;\
+ } while(false);
+
+void main()
+{
+ if (texelFetch(ssrMask, ivec2(gl_FragCoord.xy), 0).r < 0.5)
+ {
+ OutColor = vec4(0.0);
+ return;
+ }
+ FragmentInfo fragment = getFragmentInfo(
+ TexCoord, albedoTex, normalTex, materialTex, depthTex, camera.invViewProjMatrix);
+ float rayLength = 4000.f;
+
vec3 viewDistance = camera.position - fragment.position;
vec3 viewDirection = normalize(viewDistance);
+ vec3 reflectDirection = normalize(reflect(-viewDirection, fragment.normal));
+
+ //0:start 1:end
+ vec3 wp0 = fragment.position;
+ vec3 wp1 = fragment.position + reflectDirection * rayLength;
+
+ vec3 vp0 = transform(camera.viewMatrix, wp0);
+ vec3 vp1 = transform(camera.viewMatrix, wp1);
+
+ vec4 ho0 = transform(camera.projectionMatrix, vec4(vp0, 1.0));
+ vec4 ho1 = transform(camera.projectionMatrix, vec4(vp1, 1.0));
+
+ float w0 = 1.0 / ho0.w;
+ float w1 = 1.0 / ho1.w;
+ //to avoid nonlinearity,project to view space
+ vec3 vpProj0 = vp0 * w0;
+ vec3 vpProj1 = vp1 * w1;
- vec3 pivot = normalize(reflect(-viewDirection, fragment.normal));
- vec3 startPos = fragment.position + (pivot * 0.0001);
+ vec2 ndc0 = ho0.xy * w0;
+ vec2 ndc1 = ho1.xy * w1;
- float currentLength = min(length(viewDistance) / steps, startDistance);
- float bestDepth = 10000.0;
- vec2 bestUV = vec2(0.0);
+ vec2 scr0 = (ndc0 + 1.0) / 2.0 * screenResolution;
+ vec2 scr1 = (ndc1 + 1.0) / 2.0 * screenResolution;
- for (int i = 0; i < steps; i++)
+ scr1 += distance(scr0, scr1) < 0.01 ? 0.01 : 0.0;
+ //Using Line Generation Algorithm
+ //https://en.wikipedia.org/wiki/Digital_differential_analyzer_(graphics_algorithm)
+ vec2 delta = scr1 - scr0;
+ bool permute = false;
+ if (abs(delta.x) < abs(delta.y))
{
- vec3 currentPosition = startPos + pivot * currentLength;
- vec4 projectedPosition = worldToFragSpace(currentPosition, camera.viewProjMatrix);
- vec2 currentUV = projectedPosition.xy;
- float projectedDepth = projectedPosition.z;
+ permute = true;
+ swapComp(delta);
+ swapComp(scr0);
+ swapComp(scr1);
+ }
+ float stepDir = sign(delta.x);
+ float invDx = stepDir / delta.x;
+
+ vec3 dVpProj = (vpProj1 - vpProj0) * invDx;
+ float dw = (w1 - w0) * invDx;
+ vec2 dScr = vec2(stepDir, delta.y * invDx);
- if (currentUV.x > 1.0 || currentUV.y > 1.0 ||
- currentUV.x < 0.0 || currentUV.y < 0.0) break;
+ //Start position
+ scr0 += dScr;
+ vpProj0 += dVpProj;
+ w0 += dw;
- float currentFragDepth = texture(depthTex, currentUV).r;
- float depthDiff = abs(1.0 / projectedDepth - 1.0 / currentFragDepth);
- if (depthDiff < bestDepth)
+ float lastZmax = vp0.z;
+ vec2 result;
+ bool isHit = false;
+ bool checkthickness = false;
+ int level = 0;
+ //Todo: /(ãoã)/~~ Handle diffuse lobe. Sampling more rays or using cone tracing when the BRDF lobe is fat.
+ for (int curStep = 0; curStep < maxStep; curStep++)
+ {
+ //reconstruct camera space ray depth
+ result.xy = permute ? scr0.yx : scr0;
+ vec2 depths;
+ depths.x = lastZmax;
+ depths.y = (dVpProj.z * 0.5 + vpProj0.z) / (dw * 0.5 + w0);
+ lastZmax = depths.y;
+ //check direction
+ if (depths.x < depths.y)
+ swapComp(depths);
+ //check boundary
+ if (result.x > screenResolution.x || result.x < 0 ||
+ result.y > screenResolution.y || result.y < 0)
+ break;
+ //reconstruct in cam space
+ float d = sampleDepth(ivec2(result), level);
+ vec4 normPosition = vec4(2.0f * result - vec2(1.0f), d, 1.0f);
+ vec4 vpos = transform(camera.invProjectionMatrix, normPosition);
+ vpos /= vpos.w;
+ float sceneDepth = vpos.z;
+ //check if near the start point
+ if (!checkthickness && (depths.y - sceneDepth > thickness))
+ checkthickness = true;
+ //check hit & switch depth layer
+ float curDiff = sceneDepth - depths.y;
+ int stp = 1 << level;
+ if (checkthickness && curDiff >= thickness)
{
- bestUV = currentUV;
- bestDepth = depthDiff;
- if (depthDiff < thickness)
+ if (level == 0)
+ {
+ isHit = true;
break;
+ }
+ //stepping back
+ TRACE_RAY(-stp);
+ level = 0;
}
else
{
- vec3 newPosition = reconstructWorldPosition(currentFragDepth, currentUV, camera.invViewProjMatrix);
- currentLength = length(startPos - newPosition);
+ level = min(maxLevel, level + 1);
+ //stepping forward
+ TRACE_RAY(stp);
}
}
-
- vec3 reflection = bestUV != vec2(0.0) ? texture(HDRTex, bestUV).rgb : vec3(0.0);
- OutColor = vec4(reflection, 1.0);
+
+ if (isHit)
+ OutColor = vec4(texelFetch(HDRTex, ivec2(result), 0).rgb, 1.0);
+ else
+ OutColor = vec4(0.0);
}
\ No newline at end of file
diff --git a/src/Platform/OpenGL/Texture.cpp b/src/Platform/OpenGL/Texture.cpp
index 8bed20146..82ac81c87 100644
--- a/src/Platform/OpenGL/Texture.cpp
+++ b/src/Platform/OpenGL/Texture.cpp
@@ -43,7 +43,7 @@ namespace MxEngine
GL_RG8,
GL_RG16,
GL_R16F,
- GL_R32F,
+ GL_R32F_EXT,//cannot use GL_R32F. Why?
GL_RG16F,
GL_RG32F,
GL_RGB,
@@ -205,7 +205,7 @@ namespace MxEngine
switch (channels)
{
case 1:
- dataChannels = GL_RED;
+ dataChannels = (format == TextureFormat::R32F) ? GL_RED_EXT : GL_RED;
break;
case 2:
dataChannels = GL_RG;
@@ -240,6 +240,12 @@ namespace MxEngine
this->Load(image.GetRawData(), (int)image.GetWidth(), (int)image.GetHeight(), (int)image.GetChannelCount(), image.IsFloatingPoint(), format);
}
+ void Texture::Copy(TextureBindId src, TextureBindId dst, int x, int y, int w, int h)
+ {
+ GLCALL(glCopyImageSubData(src, GL_TEXTURE_2D, 0, 0, 0, 0,
+ dst, GL_TEXTURE_2D, 0, x, y, 0, w, h, 1));
+ }
+
void Texture::LoadDepth(int width, int height, TextureFormat format)
{
this->filepath = MXENGINE_MAKE_INTERNAL_TAG("depth");
diff --git a/src/Platform/OpenGL/Texture.h b/src/Platform/OpenGL/Texture.h
index 0602fe4ce..b9e03ff06 100644
--- a/src/Platform/OpenGL/Texture.h
+++ b/src/Platform/OpenGL/Texture.h
@@ -110,6 +110,7 @@ namespace MxEngine
void Load(RawDataPointer data, int width, int height, int channels, bool isFloating, TextureFormat format = TextureFormat::RGB);
void Load(const Image& image, TextureFormat format = TextureFormat::RGB);
+ static void Copy(TextureBindId src, TextureBindId dst, int x, int y, int w, int h);
void LoadDepth(int width, int height, TextureFormat format = TextureFormat::DEPTH);
void SetMaxLOD(size_t lod);
void SetMinLOD(size_t lod);