add MSAA, renderer2D, boundingbox

This commit is contained in:
2025-12-01 22:14:22 +08:00
parent 0d4024be39
commit c96eb34af5
44 changed files with 1185 additions and 289 deletions

View File

@ -4,6 +4,8 @@
#include "EditorLayer.h"
#include "ImGuizmo.h"
#include "Prism/Core/Input.h"
#include "Prism/Renderer/Renderer2D.h"
namespace Prism
{
@ -12,16 +14,18 @@ namespace Prism
None = 0, ColorProperty = 1
};
void Property(const std::string& name, bool& value)
bool Property(const std::string& name, bool& value)
{
ImGui::Text(name.c_str());
ImGui::NextColumn();
ImGui::PushItemWidth(-1);
std::string id = "##" + name;
ImGui::Checkbox(id.c_str(), &value);
const std::string id = "##" + name;
const bool result = ImGui::Checkbox(id.c_str(), &value);
ImGui::PopItemWidth();
ImGui::NextColumn();
return result;
}
void Property(const std::string& name, float& value, float min = -1.0f, float max = 1.0f,
@ -137,14 +141,16 @@ namespace Prism
m_Scene->SetEnvironment(environment);
m_MeshEntity = m_Scene->CreateEntity();
const auto mesh = CreateRef<Mesh>("assets/models/m1911/m1911.fbx");
//auto mesh = CreateRef<Mesh>("assets/meshes/cerberus/CerberusMaterials.fbx");
// auto mesh = CreateRef<Mesh>("assets/models/m1911/M1911Materials.fbx");
m_MeshEntity = m_Scene->CreateEntity("test Entity");
auto mesh = CreateRef<Mesh>("assets/meshes/TestScene.fbx");
m_MeshEntity->SetMesh(mesh);
m_MeshMaterial = mesh->GetMaterial();
auto secondEntity = m_Scene->CreateEntity("Gun Entity");
secondEntity->Transform() = glm::translate(glm::mat4(1.0f), { 5, 5, 5 }) * glm::scale(glm::mat4(1.0f), {10, 10, 10});
mesh = CreateRef<Mesh>("assets/models/m1911/m1911.fbx");
secondEntity->SetMesh(mesh);
}
// Sphere Scene
@ -213,43 +219,55 @@ namespace Prism
void EditorLayer::OnUpdate(const TimeStep deltaTime)
{
// THINGS TO LOOK AT:
// - BRDF LUT
// - Tonemapping and proper HDR pipeline
using namespace Prism;
using namespace glm;
m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value);
m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value);
m_MeshMaterial->Set("lights", m_Light);
m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
m_SphereBaseMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
m_SphereBaseMaterial->Set("lights", m_Light);
m_SphereBaseMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
if (m_AlbedoInput.TextureMap)
m_MeshMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap);
if (m_NormalInput.TextureMap)
m_MeshMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap);
if (m_MetalnessInput.TextureMap)
m_MeshMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap);
if (m_RoughnessInput.TextureMap)
m_MeshMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap);
if (m_AllowViewportCameraEvents)
m_Scene->GetCamera().OnUpdate(deltaTime);
m_ActiveScene->OnUpdate(deltaTime);
if (m_DrawOnTopBoundingBoxes)
{
// THINGS TO LOOK AT:
// - BRDF LUT
// - Tonemapping and proper HDR pipeline
using namespace Prism;
using namespace glm;
m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value);
m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value);
m_MeshMaterial->Set("lights", m_Light);
m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
m_SphereBaseMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
m_SphereBaseMaterial->Set("lights", m_Light);
m_SphereBaseMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
m_SphereBaseMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
if (m_AlbedoInput.TextureMap)
m_MeshMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap);
if (m_NormalInput.TextureMap)
m_MeshMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap);
if (m_MetalnessInput.TextureMap)
m_MeshMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap);
if (m_RoughnessInput.TextureMap)
m_MeshMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap);
m_ActiveScene->OnUpdate(deltaTime);
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
auto viewProj = m_Scene->GetCamera().GetViewProjection();
Renderer2D::BeginScene(viewProj, false);
// Prism::Renderer2D::DrawQuad({ 0, 0, 0 }, { 4.0f, 5.0f }, { 1.0f, 1.0f, 0.5f, 1.0f });
Renderer::DrawAABB(m_MeshEntity->GetMesh());
Renderer2D::EndScene();
Renderer::EndRenderPass();
}
}
@ -431,6 +449,11 @@ namespace Prism
Property("Radiance Prefiltering", m_RadiancePrefilter);
Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
if (Property("Show Bounding Boxes", m_UIShowBoundingBoxes))
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
if (m_UIShowBoundingBoxes && Property("On Top", m_UIShowBoundingBoxesOnTop))
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
ImGui::Columns(1);
ImGui::End();
@ -620,12 +643,17 @@ namespace Prism
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::Begin("Viewport");
auto viewportSize = ImGui::GetContentRegionAvail();
SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_ActiveScene->GetCamera().SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
m_ActiveScene->GetCamera().SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
auto windowSize = ImGui::GetWindowSize();
ImVec2 minBound = ImGui::GetWindowPos();
ImVec2 maxBound = { minBound.x + windowSize.x, minBound.y + windowSize.y };
m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound);
// ImGuizmo
if (m_GizmoType != -1)
{
@ -645,8 +673,11 @@ namespace Prism
void EditorLayer::OnEvent(Event& e)
{
if (m_AllowViewportCameraEvents)
m_Scene->GetCamera().OnEvent(e);
EventDispatcher dispatcher(e);
dispatcher.Dispatch<KeyPressedEvent>(HZ_BIND_EVENT_FN(EditorLayer::OnKeyPressedEvent));
dispatcher.Dispatch<KeyPressedEvent>(PM_BIND_EVENT_FN(EditorLayer::OnKeyPressedEvent));
}
bool EditorLayer::OnKeyPressedEvent(KeyPressedEvent& e)
@ -665,7 +696,27 @@ namespace Prism
case PM_KEY_R:
m_GizmoType = ImGuizmo::OPERATION::SCALE;
break;
case PM_KEY_G:
// Toggle grid
if (Input::IsKeyPressed(PM_KEY_LEFT_CONTROL))
SceneRenderer::GetOptions().ShowGrid = !SceneRenderer::GetOptions().ShowGrid;
break;
case PM_KEY_B:
// Toggle bounding boxes
if (Input::IsKeyPressed(PM_KEY_LEFT_CONTROL))
{
m_UIShowBoundingBoxes = !m_UIShowBoundingBoxes;
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
}
break;
}
return false;
}
void EditorLayer::ShowBoundingBoxes(bool show, bool onTop)
{
SceneRenderer::GetOptions().ShowBoundingBoxes = show && !onTop;
m_DrawOnTopBoundingBoxes = show && onTop;
}
}

View File

@ -25,6 +25,8 @@ namespace Prism
private:
bool OnKeyPressedEvent(KeyPressedEvent& e);
void ShowBoundingBoxes(bool show, bool onTop = false);
private:
Scope<SceneHierarchyPanel> m_SceneHierarchyPanel;
@ -54,6 +56,13 @@ namespace Prism
// Imguizmo
int m_GizmoType = -1; // -1 = no gizmo
// configure button
bool m_AllowViewportCameraEvents = false;
bool m_DrawOnTopBoundingBoxes = false;
bool m_UIShowBoundingBoxes = false;
bool m_UIShowBoundingBoxesOnTop = false;
struct AlbedoInput
{

Binary file not shown.

View File

@ -34,7 +34,7 @@ out VertexOutput
void main()
{
vs_Output.WorldPosition = vec3(u_Transform * vec4(a_Position, 1.0));
vs_Output.Normal = a_Normal;
vs_Output.Normal = mat3(u_Transform) * a_Normal;
vs_Output.TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y);
vs_Output.WorldNormals = mat3(u_Transform) * mat3(a_Tangent, a_Binormal, a_Normal);
vs_Output.WorldTransform = mat3(u_Transform);
@ -271,7 +271,8 @@ vec3 Lighting(vec3 F0)
vec3 IBL(vec3 F0, vec3 Lr)
{
vec3 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb;
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
// vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
vec3 F = fresnelSchlick(F0, m_Params.NdotV);
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
vec3 diffuseIBL = m_Params.Albedo * irradiance;
@ -316,4 +317,5 @@ void main()
vec3 iblContribution = IBL(F0, Lr);
color = vec4(lightContribution + iblContribution, 1.0);
color = vec4(iblContribution, 1.0);
}

View File

@ -0,0 +1,43 @@
// Basic Texture Shader
#type vertex
#version 430 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec4 a_Color;
layout(location = 2) in vec2 a_TexCoord;
layout(location = 3) in float a_TexIndex;
layout(location = 4) in float a_TilingFactor;
uniform mat4 u_ViewProjection;
out vec4 v_Color;
out vec2 v_TexCoord;
out float v_TexIndex;
out float v_TilingFactor;
void main()
{
v_Color = a_Color;
v_TexCoord = a_TexCoord;
v_TexIndex = a_TexIndex;
v_TilingFactor = a_TilingFactor;
gl_Position = u_ViewProjection * vec4(a_Position, 1.0);
}
#type fragment
#version 430 core
layout(location = 0) out vec4 color;
in vec4 v_Color;
in vec2 v_TexCoord;
in float v_TexIndex;
in float v_TilingFactor;
uniform sampler2D u_Textures[32];
void main()
{
color = texture(u_Textures[int(v_TexIndex)], v_TexCoord * v_TilingFactor) * v_Color;
}

View File

@ -0,0 +1,29 @@
// Basic Texture Shader
#type vertex
#version 430 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec4 a_Color;
uniform mat4 u_ViewProjection;
out vec4 v_Color;
void main()
{
v_Color = a_Color;
gl_Position = u_ViewProjection * vec4(a_Position, 1.0);
}
#type fragment
#version 430 core
layout(location = 0) out vec4 color;
in vec4 v_Color;
void main()
{
color = v_Color;
}

View File

@ -16,20 +16,34 @@ void main()
#type fragment
#version 430
layout(location = 0) out vec4 o_Color;
in vec2 v_TexCoord;
uniform sampler2D u_Texture;
layout(location=0) out vec4 outColor;
uniform sampler2DMS u_Texture;
uniform float u_Exposure;
uniform int u_TextureSamples;
vec4 MultiSampleTexture(sampler2DMS tex, ivec2 texCoord, int samples)
{
vec4 result = vec4(0.0);
for (int i = 0; i < samples; i++)
result += texelFetch(tex, texCoord, i);
result /= float(samples);
return result;
}
void main()
{
const float gamma = 2.2;
const float pureWhite = 1.0;
vec3 color = texture(u_Texture, v_TexCoord).rgb * u_Exposure;
ivec2 texSize = textureSize(u_Texture);
ivec2 texCoord = ivec2(v_TexCoord * texSize);
vec4 msColor = MultiSampleTexture(u_Texture, texCoord, u_TextureSamples);
vec3 color = msColor.rgb * u_Exposure;//texture(u_Texture, v_TexCoord).rgb * u_Exposure;
// Reinhard tonemapping operator.
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
@ -39,5 +53,5 @@ void main()
vec3 mappedColor = (mappedLuminance / luminance) * color;
// Gamma correction.
outColor = vec4(pow(mappedColor, vec3(1.0/gamma)), 1.0);
o_Color = vec4(pow(mappedColor, vec3(1.0 / gamma)), 1.0);
}

View File

@ -83,6 +83,7 @@ set(STATIC_LIBRARY ${PROJECT_NAME}-static)
add_library(${STATIC_LIBRARY} STATIC ${SRC_SOURCE})
target_compile_definitions(${STATIC_LIBRARY} PRIVATE
PUBLIC
${DEBUG_DEFINITIONS}
INTERFACE
PRISM_STATIC

View File

@ -69,9 +69,9 @@ namespace Prism
}
#ifdef _MSC_VER
#define HZ_BIND_EVENT_FN(fn) std::bind(&##fn, this, std::placeholders::_1)
#define PM_BIND_EVENT_FN(fn) std::bind(&##fn, this, std::placeholders::_1)
#else
#define HZ_BIND_EVENT_FN(fn) std::bind(&fn, this, std::placeholders::_1)
#define PM_BIND_EVENT_FN(fn) std::bind(&fn, this, std::placeholders::_1)
#endif
#endif //APPLICATION_H

View File

@ -50,7 +50,7 @@ namespace Prism
memset(Data, 0, Size);
}
void Write(const byte* data, const uint32_t size, const uint32_t offset = 0) const
void Write(const void* data, const uint32_t size, const uint32_t offset = 0) const
{
PM_CORE_ASSERT(offset + size <= Size, "Buffer overflow!");
memcpy(Data + offset, data, size);

View File

@ -29,18 +29,11 @@ namespace Prism
{
ImGui::Begin("Scene Hierarchy");
uint32_t entityCount = 0, meshCount = 0;
auto& sceneEntities = m_Context->m_Entities;
for (Entity* entity : sceneEntities)
for (const auto& entity : sceneEntities)
{
auto mesh = entity->GetMesh();
auto material = entity->GetMaterial();
const auto& transform = entity->GetTransform();
if (mesh)
{
DrawMeshNode(mesh);
}
DrawEntityNode(entity, entityCount, meshCount);
}
ImGui::End();
@ -89,7 +82,26 @@ namespace Prism
}
static std::tuple<glm::vec3, glm::quat, glm::vec3> GetTransformDecomposition(const glm::mat4& transform)
void SceneHierarchyPanel::DrawEntityNode(Entity* entity, uint32_t& imguiEntityID, uint32_t& imguiMeshID)
{
const char* name = entity->GetName().c_str();
static char imguiName[128];
memset(imguiName, 0, 128);
sprintf(imguiName, "%s##%d", name, imguiEntityID++);
if (ImGui::TreeNode(imguiName))
{
auto mesh = entity->GetMesh();
auto material = entity->GetMaterial();
const auto& transform = entity->GetTransform();
if (mesh)
DrawMeshNode(mesh, imguiMeshID);
ImGui::TreePop();
}
}
static std::tuple<glm::vec3, glm::quat, glm::vec3> GetTransformDecomposition(const glm::mat4& transform)
{
glm::vec3 scale, translation, skew;
glm::vec4 perspective;
@ -99,13 +111,23 @@ namespace Prism
return { translation, orientation, scale };
}
void SceneHierarchyPanel::DrawMeshNode(const Ref<Mesh>& mesh)
void SceneHierarchyPanel::DrawMeshNode(const Ref<Mesh>& mesh, uint32_t& imguiMeshID)
{
auto rootNode = mesh->m_Scene->mRootNode;
MeshNodeHierarchy(mesh, rootNode);
static char imguiName[128];
memset(imguiName, 0, 128);
sprintf(imguiName, "Mesh##%d", imguiMeshID++);
// Mesh Hierarchy
if (ImGui::TreeNode(imguiName))
{
auto rootNode = mesh->m_Scene->mRootNode;
MeshNodeHierarchy(mesh, rootNode);
ImGui::TreePop();
}
}
void SceneHierarchyPanel::MeshNodeHierarchy(const Ref<Mesh>& mesh, aiNode* node, const glm::mat4& parentTransform, uint32_t level)
{
glm::mat4 localTransform = Mat4FromAssimpMat4(node->mTransformation);

View File

@ -18,7 +18,8 @@ namespace Prism
void OnImGuiRender();
private:
void DrawMeshNode(const Ref<Mesh>& mesh);
void DrawEntityNode(Entity* entity, uint32_t& imguiEntityID, uint32_t& imguiMeshID);
void DrawMeshNode(const Ref<Mesh>& mesh, uint32_t& imguiMeshID);
void MeshNodeHierarchy(const Ref<Mesh>& mesh, aiNode* node, const glm::mat4& parentTransform = glm::mat4(1.0f), uint32_t level = 0);
private:
Ref<Scene> m_Context;

View File

@ -26,7 +26,7 @@ namespace Prism
void OpenGLFrameBuffer::Bind() const
{
Renderer::Submit([this](){
Renderer::Submit([=](){
glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID);
glViewport(0, 0, m_Specification.Width, m_Specification.Height);
});
@ -34,66 +34,116 @@ namespace Prism
void OpenGLFrameBuffer::Unbind() const
{
Renderer::Submit([this](){
Renderer::Submit([=](){
glBindFramebuffer(GL_FRAMEBUFFER, 0);
});
}
void OpenGLFrameBuffer::Resize(const uint32_t width, const uint32_t height)
{
if (m_RendererID && m_Specification.Width == width && m_Specification.Height == height)
return;
if (m_Specification.Width == width && m_Specification.Height == height)
return;
m_Specification.Width = width;
m_Specification.Height = height;
Renderer::Submit([this](){
if (m_RendererID)
{
glDeleteFramebuffers(1, &m_RendererID);
glDeleteTextures(1, &m_ColorAttachment);
glDeleteTextures(1, &m_DepthAttachment);
}
m_Specification.Width = width;
m_Specification.Height = height;
Renderer::Submit([this]()
{
if (m_RendererID)
{
glDeleteFramebuffers(1, &m_RendererID);
glDeleteTextures(1, &m_ColorAttachment);
glDeleteTextures(1, &m_DepthAttachment);
}
glGenFramebuffers(1, &m_RendererID);
glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID);
glGenFramebuffers(1, &m_RendererID);
glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID);
glGenTextures(1, &m_ColorAttachment);
glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
bool multisample = m_Specification.Samples > 1;
if (multisample)
{
glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &m_ColorAttachment);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment);
// TODO: Create Hazel texture object based on format here
if (m_Specification.Format == FramebufferFormat::RGBA16F)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_FLOAT, nullptr);
}
else if (m_Specification.Format == FramebufferFormat::RGBA8)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_ColorAttachment, 0);
// TODO: Create Hazel texture object based on format here
if (m_Specification.Format == FramebufferFormat::RGBA16F)
{
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA16F, m_Specification.Width, m_Specification.Height, GL_FALSE);
//glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA16F, m_Specification.Width, m_Specification.Height, GL_FALSE);
}
else if (m_Specification.Format == FramebufferFormat::RGBA8)
{
// glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGBA8, m_Specification.Width, m_Specification.Height, GL_TRUE);
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_RGBA8, m_Specification.Width, m_Specification.Height, GL_FALSE);
}
// glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment, 0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
}
else
{
glCreateTextures(GL_TEXTURE_2D, 1, &m_ColorAttachment);
glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
glGenTextures(1, &m_DepthAttachment);
glBindTexture(GL_TEXTURE_2D, m_DepthAttachment);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL
);
// TODO: Create Hazel texture object based on format here
if (m_Specification.Format == FramebufferFormat::RGBA16F)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_FLOAT, nullptr);
}
else if (m_Specification.Format == FramebufferFormat::RGBA8)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_ColorAttachment, 0);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthAttachment, 0);
if (multisample)
{
glCreateTextures(GL_TEXTURE_2D_MULTISAMPLE, 1, &m_DepthAttachment);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_DepthAttachment);
// glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, GL_TRUE);
glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_Specification.Samples, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, GL_FALSE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
// glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, m_DepthAttachment, 0);
}
else
{
glCreateTextures(GL_TEXTURE_2D, 1, &m_DepthAttachment);
glBindTexture(GL_TEXTURE_2D, m_DepthAttachment);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL
);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthAttachment, 0);
}
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
PM_CORE_ERROR("Framebuffer is incomplete!");
// glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_ColorAttachment, 0);
if (multisample)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment, 0);
else
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_ColorAttachment, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, m_DepthAttachment, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
});
PM_CORE_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Framebuffer is incomplete!");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
});
}
void OpenGLFrameBuffer::BindTexture(uint32_t slot) const
void OpenGLFrameBuffer::BindTexture(const uint32_t slot) const
{
Renderer::Submit([this, slot](){
Renderer::Submit([=](){
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
if (m_Specification.Samples > 1) {
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_ColorAttachment);
} else {
glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
}
// glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
});
}
}

View File

@ -12,17 +12,6 @@ namespace Prism
{
static void OpenGLLogMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
/*
if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
{
PM_CORE_ERROR("{0}", message);
PM_CORE_ASSERT(false, "");
}else
{
PM_CORE_TRACE("{0}", message);
}
*/
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
{
@ -81,11 +70,10 @@ namespace Prism
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH:
PM_CORE_ERROR("[OpenGL HIGH] Source: {0}, Type: {1}, ID: {2}\nMessage: {3}",
sourceStr, typeStr, id, message);
if (type == GL_DEBUG_TYPE_ERROR)
PM_CORE_ERROR("[OpenGL HIGH] Source: {0}, Type: {1}, ID: {2}\nMessage: {3}", sourceStr, typeStr, id, message);
if(type == GL_DEBUG_TYPE_ERROR)
{
PM_CORE_ASSERT(false, "OpenGL严重错误");
PM_CORE_ASSERT(false, "ERROR");
}
break;
@ -134,6 +122,7 @@ namespace Prism
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_MULTISAMPLE);
auto& caps = GetCapabilities();
@ -143,6 +132,7 @@ namespace Prism
glGetIntegerv(GL_MAX_SAMPLES, &caps.MaxSamples);
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &caps.MaxAnisotropy);
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &caps.MaxTextureUnits);
GLenum error = glGetError();
@ -168,14 +158,30 @@ namespace Prism
glClearColor(r, g, b, a);
}
void RendererAPI::DrawIndexed(const unsigned int count, const bool depthTest)
void RendererAPI::DrawIndexed(uint32_t count, PrimitiveType type, bool depthTest)
{
if (!depthTest)
glDisable(GL_DEPTH_TEST);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
GLenum glPrimitiveType = 0;
switch (type)
{
case PrimitiveType::Triangles:
glPrimitiveType = GL_TRIANGLES;
break;
case PrimitiveType::Lines:
glPrimitiveType = GL_LINES;
break;
}
glDrawElements(glPrimitiveType, count, GL_UNSIGNED_INT, nullptr);
if (!depthTest)
glEnable(GL_DEPTH_TEST);
}
void RendererAPI::SetLineThickness(const float thickness)
{
glLineWidth(thickness);
}
}

View File

@ -40,7 +40,7 @@ namespace Prism
if (!m_IsCompute)
Parse();
Renderer::Submit([this](){
Renderer::Submit([=](){
auto &a = m_RendererID;
if (m_RendererID)
glDeleteProgram(m_RendererID);
@ -125,6 +125,13 @@ namespace Prism
});
}
void OpenGLShader::SetInt(const std::string& name, int value)
{
Renderer::Submit([=]() {
UploadUniformInt(name, value);
});
}
void OpenGLShader::SetMat4(const std::string& name, const glm::mat4& value)
{
Renderer::Submit([=]() {
@ -132,6 +139,13 @@ namespace Prism
});
}
void OpenGLShader::SetIntArray(const std::string& name, int* values, uint32_t size)
{
Renderer::Submit([=]() {
UploadUniformIntArray(name, values, size);
});
}
void OpenGLShader::SetVSMaterialUniformBuffer(Buffer buffer)
{
Renderer::Submit([this, buffer]() {
@ -351,6 +365,7 @@ namespace Prism
static bool IsTypeStringResource(const std::string& type)
{
if (type == "sampler2D") return true;
if (type == "sampler2DMS") return true;
if (type == "samplerCube") return true;
if (type == "sampler2DShadow") return true;
return false;
@ -371,7 +386,7 @@ namespace Prism
{
int32_t result = glGetUniformLocation(m_RendererID, name.c_str());
if (result == -1)
PM_CORE_WARN("Could not find uniform '{0}' in shader", name);
PM_CORE_WARN("Could not find uniform '{0}' in shader: {1}", name, m_Name);
return result;
}
@ -932,7 +947,7 @@ namespace Prism
}
}
void OpenGLShader::UploadUniformIntArray(const std::string& name, const int32_t* values, const int32_t count) const
void OpenGLShader::UploadUniformIntArray(const std::string& name, const int32_t* values, const uint32_t count) const
{
int32_t location = GetUniformLocation(name);
glUniform1iv(location, count, values);

View File

@ -28,8 +28,11 @@ namespace Prism
virtual void AddShaderReloadedCallback(const ShaderReloadedCallback& callback) override;
virtual void SetFloat(const std::string& name, float value) override;
virtual void SetInt(const std::string& name, int value) override;
virtual void SetMat4(const std::string& name, const glm::mat4& value) override;
virtual void SetIntArray(const std::string& name, int* values, uint32_t size) override;
virtual void SetVSMaterialUniformBuffer(Buffer buffer) override;
virtual void SetPSMaterialUniformBuffer(Buffer buffer) override;
@ -81,7 +84,7 @@ namespace Prism
void UploadUniformMat4Array(uint32_t location, const glm::mat4& values, uint32_t count);
void UploadUniformStruct(const OpenGLShaderUniformDeclaration* uniform, byte* buffer, uint32_t offset);
void UploadUniformIntArray(const std::string& name, const int32_t* values, int32_t count) const;
void UploadUniformIntArray(const std::string& name, const int32_t* values, uint32_t count) const;
virtual const ShaderUniformBufferList& GetVSRendererUniforms() const override { return m_VSRendererUniformBuffers; }
virtual const ShaderUniformBufferList& GetPSRendererUniforms() const override { return m_PSRendererUniformBuffers; }

View File

@ -48,6 +48,7 @@ namespace Prism
OpenGLShaderUniformDeclaration::Type OpenGLShaderUniformDeclaration::StringToType(const std::string& type)
{
if (type == "int") return Type::INT32;
if (type == "int32") return Type::INT32;
if (type == "float") return Type::FLOAT32;
if (type == "vec2") return Type::VEC2;
@ -112,6 +113,7 @@ namespace Prism
OpenGLShaderResourceDeclaration::Type OpenGLShaderResourceDeclaration::StringToType(const std::string& type)
{
if (type == "sampler2D") return Type::TEXTURE2D;
if (type == "sampler2DMS") return Type::TEXTURE2D;
if (type == "samplerCube") return Type::TEXTURECUBE;
return Type::NONE;
@ -121,7 +123,7 @@ namespace Prism
{
switch (type)
{
case Type::TEXTURE2D: return "sampler2D";
case Type::TEXTURE2D: return "sampler2D";
case Type::TEXTURECUBE: return "samplerCube";
}
return "Invalid Type";

View File

@ -70,7 +70,7 @@ namespace Prism
int32_t GetLocation() const { return m_Location; }
inline Type GetType() const { return m_Type; }
inline bool IsArray() const { return m_Count > 1; }
inline const ShaderStruct& GetShaderUniformStruct() const { PM_CORE_ASSERT(m_Struct, ""); return *m_Struct; }
inline const ShaderStruct& GetShaderUniformStruct() const { PM_CORE_ASSERT(m_Struct); return *m_Struct; }
protected:
void SetOffset(uint32_t offset) override;
public:

View File

@ -42,11 +42,12 @@ namespace Prism
glTextureParameterf(m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(m_Format), (GLint)m_Width, (GLint)m_Height, 0, Prism::PrismToOpenGLTextureFormat(m_Format), GL_UNSIGNED_BYTE, nullptr);
glGenerateMipmap(GL_TEXTURE_2D);
// glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
});
m_ImageData.Allocate(width * height * GetBPP(m_Format));
}

View File

@ -38,6 +38,11 @@ namespace Prism
virtual const std::string& GetPath() const override { return m_FilePath; }
virtual RendererID GetRendererID() const override { return m_RendererID; }
virtual bool operator==(const Texture& other) const override
{
return m_RendererID == ((OpenGLTexture2D&)other).m_RendererID;
}
private:
RendererID m_RendererID;
TextureFormat m_Format;
@ -73,6 +78,10 @@ namespace Prism
virtual RendererID GetRendererID() const override { return m_RendererID; }
virtual bool operator==(const Texture& other) const override
{
return m_RendererID == ((OpenGLTextureCube&)other).m_RendererID;
}
private:
RendererID m_RendererID;
TextureFormat m_Format;

View File

@ -21,8 +21,9 @@ namespace Prism
virtual void AddVertexBuffer(const Ref<VertexBuffer>& vertexBuffer) override;
virtual void SetIndexBuffer(const Ref<IndexBuffer>& indexBuffer) override;
virtual const std::vector<Ref<VertexBuffer>>& GetVertexBuffers() const { return m_VertexBuffers; }
virtual const Ref<IndexBuffer>& GetIndexBuffer() const { return m_IndexBuffer; }
virtual const std::vector<Ref<VertexBuffer>>& GetVertexBuffers() const override { return m_VertexBuffers; }
virtual const Ref<IndexBuffer>& GetIndexBuffer() const override { return m_IndexBuffer; }
virtual RendererID GetRendererID() const override { return m_RendererID; }
private:
RendererID m_RendererID = 0;
uint32_t m_VertexBufferIndex = 0;

View File

@ -10,7 +10,9 @@
#include "glm/gtc/quaternion.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include "glm/gtx/quaternion.hpp"
#include "Prism/Core/Application.h"
#include "Prism/Core/Input.h"
#include "Prism/Core/Events/MouseEvent.h"
#ifndef M_PI
#define M_PI 3.1415926f
@ -36,7 +38,7 @@ namespace Prism
{
}
void Camera::Update(TimeStep deltaTime)
void Camera::OnUpdate(TimeStep deltaTime)
{
if (Input::IsKeyPressed(GLFW_KEY_LEFT_ALT))
{
@ -63,6 +65,12 @@ namespace Prism
m_ViewMatrix = glm::inverse(m_ViewMatrix);
}
void Camera::OnEvent(Event& e)
{
EventDispatcher dispatcher(e);
dispatcher.Dispatch<MouseScrolledEvent>(PM_BIND_EVENT_FN(Camera::OnMouseScroll));
}
glm::vec3 Camera::GetUpDirection()
{
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 1.0f, 0.0f));
@ -78,6 +86,13 @@ namespace Prism
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 0.0f, -1.0f));
}
bool Camera::OnMouseScroll(MouseScrolledEvent& e)
{
const float delta = e.GetOffsetY() * 0.1f;
MouseZoom(delta);
return false;
}
void Camera::MousePan(const glm::vec2& delta)
{
auto [xSpeed, ySpeed] = PanSpeed();

View File

@ -6,11 +6,12 @@
#define CAMERA_H
#include <glm/glm.hpp>
#include "Prism/Core/TimeStep.h"
namespace Prism
{
class MouseScrolledEvent;
class Event;
class PRISM_API Camera
{
@ -19,7 +20,8 @@ namespace Prism
Camera(const glm::mat4& projectionMatrix);
void Focus();
void Update(TimeStep deltaTime);
void OnUpdate(TimeStep deltaTime);
void OnEvent(Event& e);
inline float GetDistance() const { return m_Distance; }
inline void SetDistance(float distance) { m_Distance = distance; }
@ -28,6 +30,7 @@ namespace Prism
const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; }
const glm::mat4& GetViewMatrix() const { return m_ViewMatrix; }
glm::mat4 GetViewProjection() const { return m_ProjectionMatrix * m_ViewMatrix; }
glm::vec3 GetUpDirection();
glm::vec3 GetRightDirection();
@ -40,6 +43,7 @@ namespace Prism
public:
inline void SetViewportSize(const uint32_t width, const uint32_t height) { m_ViewportWidth = width; m_ViewportHeight = height; }
private:
bool OnMouseScroll(MouseScrolledEvent& e);
void MousePan(const glm::vec2& delta);
void MouseRotate(const glm::vec2& delta);
void MouseZoom(float delta);

View File

@ -23,6 +23,7 @@ namespace Prism
uint32_t Height = 720;
glm::vec4 ClearColor;
FramebufferFormat Format;
uint32_t Samples = 1;
// SwapChainTarget = screen buffer (i.e. no framebuffer)
bool SwapChainTarget = false;

View File

@ -45,6 +45,7 @@ namespace Prism
void Material::OnShaderReloaded()
{
return;
AllocateStorage();
for (auto mi : m_MaterialInstances)

View File

@ -98,7 +98,7 @@ namespace Prism
const auto decl = m_Material->FindUniformDeclaration(name);
if (!decl) PM_CORE_WARN("Could not find uniform with name {0}", name);
auto& buffer = GetUniformBufferTarget(decl);
buffer.Write((byte*)& value, decl->GetSize(), decl->GetOffset());
buffer.Write(&value, decl->GetSize(), decl->GetOffset());
m_OverriddenValues.insert(name);
}
@ -152,7 +152,7 @@ namespace Prism
// HZ_CORE_ASSERT(decl, "Could not find uniform with name '{0}'", name);
PM_CORE_ASSERT(decl, "Could not find uniform with name 'x'");
auto& buffer = GetUniformBufferTarget(decl);
buffer.Write((byte*)&value, decl->GetSize(), decl->GetOffset());
buffer.Write(&value, decl->GetSize(), decl->GetOffset());
for (auto mi : m_MaterialInstances)
mi->OnMaterialValueUpdated(decl);

View File

@ -155,12 +155,23 @@ namespace Prism
}
}else
{
for (size_t i = 0; i < mesh->mNumVertices; i++)
submesh.Min = { FLT_MAX, FLT_MAX, FLT_MAX };
submesh.Max = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
for (size_t i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
vertex.Position = { mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z };
vertex.Normal = { mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z };
submesh.Min.x = glm::min(vertex.Position.x, submesh.Min.x);
submesh.Min.y = glm::min(vertex.Position.y, submesh.Min.y);
submesh.Min.z = glm::min(vertex.Position.z, submesh.Min.z);
submesh.Max.x = glm::max(vertex.Position.x, submesh.Max.x);
submesh.Max.y = glm::max(vertex.Position.y, submesh.Max.y);
submesh.Max.z = glm::max(vertex.Position.z, submesh.Max.z);
if (mesh->HasTangentsAndBitangents())
{
vertex.Tangent = { mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z };
@ -273,8 +284,97 @@ namespace Prism
{
mi->Set("u_AlbedoTexToggle", 0.0f);
mi->Set("u_AlbedoColor", glm::vec3 { aiColor.r, aiColor.g, aiColor.b });
PM_CORE_INFO("Mesh has no albedo map");
}
// Normal Maps
mi->Set("u_NormalTexToggle", 0.0f);
if (aiMaterial->GetTexture(aiTextureType_NORMALS, 0, &aiTexPath) == AI_SUCCESS)
{
// TODO: Temp - this should be handled by Hazel's filesystem
std::filesystem::path path = filename;
auto parentPath = path.parent_path();
parentPath /= std::string(aiTexPath.data);
std::string texturePath = parentPath.string();
auto texture = Texture2D::Create(texturePath);
if (texture->Loaded())
{
PM_CORE_TRACE(" Normal map path = {0}", texturePath);
mi->Set("u_NormalTexture", texture);
mi->Set("u_NormalTexToggle", 1.0f);
}
else
{
PM_CORE_ERROR("Could not load texture: {0}", texturePath);
}
}
else
{
PM_CORE_TRACE("Mesh has no normal map");
}
// Roughness map
// mi->Set("u_Roughness", 1.0f);
// mi->Set("u_RoughnessTexToggle", 0.0f);
if (aiMaterial->GetTexture(aiTextureType_SHININESS, 0, &aiTexPath) == AI_SUCCESS)
{
// TODO: Temp - this should be handled by Hazel's filesystem
std::filesystem::path path = filename;
auto parentPath = path.parent_path();
parentPath /= std::string(aiTexPath.data);
std::string texturePath = parentPath.string();
auto texture = Texture2D::Create(texturePath);
if (texture->Loaded())
{
PM_CORE_TRACE(" Roughness map path = {0}", texturePath);
mi->Set("u_RoughnessTexture", texture);
mi->Set("u_RoughnessTexToggle", 1.0f);
}
else
{
PM_CORE_ERROR("Could not load texture: {0}", texturePath);
}
}
else
{
PM_CORE_TRACE("Mesh has no roughness texture");
}
// Metalness map
// mi->Set("u_Metalness", 0.0f);
// mi->Set("u_MetalnessTexToggle", 0.0f);
if (aiMaterial->Get("$raw.ReflectionFactor|file", aiPTI_String, 0, aiTexPath) == AI_SUCCESS)
{
// TODO: Temp - this should be handled by Hazel's filesystem
std::filesystem::path path = filename;
auto parentPath = path.parent_path();
parentPath /= std::string(aiTexPath.data);
std::string texturePath = parentPath.string();
auto texture = Texture2D::Create(texturePath);
if (texture->Loaded())
{
PM_CORE_TRACE(" Metalness map path = {0}", texturePath);
mi->Set("u_MetalnessTexture", texture);
mi->Set("u_MetalnessTexToggle", 1.0f);
}
else
{
PM_CORE_ERROR("Could not load texture: {0}", texturePath);
}
}
else
{
PM_CORE_TRACE("Mesh has no metalness texture");
}
continue;
for (uint32_t i = 0; i < aiMaterial->mNumProperties; i++)
{
auto prop = aiMaterial->mProperties[i];
@ -357,6 +457,7 @@ namespace Prism
}
/*
// Normal maps
if (aiMaterial->GetTexture(aiTextureType_NORMALS, 0, &aiTexPath) == AI_SUCCESS)
{
@ -428,6 +529,8 @@ namespace Prism
mi->Set("u_MetalnessTexToggle", 1.0f);
}
}
*/
}
}

View File

@ -87,6 +87,7 @@ namespace Prism
uint32_t IndexCount;
glm::mat4 Transform;
glm::vec3 Min, Max; //TODO: AABB
};
class PRISM_API Mesh

View File

@ -4,6 +4,7 @@
#include "Renderer.h"
#include "Renderer2D.h"
#include "RendererAPI.h"
#include "SceneRenderer.h"
#include "glad/glad.h"
@ -35,10 +36,10 @@ namespace Prism
// FullScreen Quad
static float fullScreenQuadVertex[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f
-1.0f, -1.0f, 0.1f, 0.0f, 0.0f,
1.0f, -1.0f, 0.1f, 1.0f, 0.0f,
1.0f, 1.0f, 0.1f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.1f, 0.0f, 1.0f
};
static uint32_t fullScreenQuadIndices[] = {
0, 1, 2, 2, 3, 0
@ -55,6 +56,7 @@ namespace Prism
s_Data.m_FullscreenQuadVertexArray->AddVertexBuffer(quadVB);
s_Data.m_FullscreenQuadVertexArray->SetIndexBuffer(quadIB);
Renderer2D::Init();
}
void Renderer::Clear()
@ -76,10 +78,10 @@ namespace Prism
{
}
void Renderer::DrawIndexed(uint32_t count, bool depthTest)
void Renderer::DrawIndexed(const uint32_t count, const PrimitiveType type, const bool depthTest)
{
Submit([=]() {
RendererAPI::DrawIndexed(count, depthTest);
RendererAPI::DrawIndexed(count, type, depthTest);
});
}
@ -90,12 +92,19 @@ namespace Prism
return s_Data.m_ShaderLibrary;
}
void Renderer::SetLineThickness(const float thickness)
{
Submit([=]() {
RendererAPI::SetLineThickness(thickness);
});
}
void Renderer::WaitAndRender()
{
s_Data.m_CommandQueue.Execute();
}
void Renderer::BeginRenderPass(const Ref<RenderPass>& renderPass)
void Renderer::BeginRenderPass(const Ref<RenderPass>& renderPass, bool clear)
{
PM_CORE_ASSERT(renderPass, "Render pass cannot be null!");
@ -103,10 +112,14 @@ namespace Prism
s_Data.m_ActiveRenderPass = renderPass;
renderPass->GetSpecification().TargetFramebuffer->Bind();
const glm::vec4& clearColor = renderPass->GetSpecification().TargetFramebuffer->GetSpecification().ClearColor;
Renderer::Submit([=]() {
RendererAPI::Clear(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
});
if (clear)
{
const glm::vec4& clearColor = renderPass->GetSpecification().TargetFramebuffer->GetSpecification().ClearColor;
Submit([=]() {
RendererAPI::Clear(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
});
}
}
void Renderer::EndRenderPass()
@ -129,7 +142,7 @@ namespace Prism
}
s_Data.m_FullscreenQuadVertexArray->Bind();
Renderer::DrawIndexed(6, depthTest);
Renderer::DrawIndexed(6, PrimitiveType::Triangles, depthTest);
}
void Renderer::SubmitFullscreenQuad(const Ref<MaterialInstance>& material)
@ -142,7 +155,7 @@ namespace Prism
}
s_Data.m_FullscreenQuadVertexArray->Bind();
Renderer::DrawIndexed(6, depthTest);
Renderer::DrawIndexed(6, PrimitiveType::Triangles, depthTest);
}
void Renderer::SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial)
@ -182,6 +195,36 @@ namespace Prism
}
}
void Renderer::DrawAABB(const Ref<Mesh>& mesh, const glm::vec4& color)
{
for (Submesh& submesh : mesh->m_Submeshes)
{
const auto& transform = submesh.Transform;
const glm::vec4 corners[8] =
{
transform * glm::vec4 { submesh.Min.x, submesh.Min.y, submesh.Max.z, 1.0f },
transform * glm::vec4 { submesh.Min.x, submesh.Max.y, submesh.Max.z, 1.0f },
transform * glm::vec4 { submesh.Max.x, submesh.Max.y, submesh.Max.z, 1.0f },
transform * glm::vec4 { submesh.Max.x, submesh.Min.y, submesh.Max.z, 1.0f },
transform * glm::vec4 { submesh.Min.x, submesh.Min.y, submesh.Min.z, 1.0f },
transform * glm::vec4 { submesh.Min.x, submesh.Max.y, submesh.Min.z, 1.0f },
transform * glm::vec4 { submesh.Max.x, submesh.Max.y, submesh.Min.z, 1.0f },
transform * glm::vec4 { submesh.Max.x, submesh.Min.y, submesh.Min.z, 1.0f }
};
for (uint32_t i = 0; i < 4; i++)
Renderer2D::DrawLine(corners[i], corners[(i + 1) % 4], color);
for (uint32_t i = 0; i < 4; i++)
Renderer2D::DrawLine(corners[i + 4], corners[((i + 1) % 4) + 4], color);
for (uint32_t i = 0; i < 4; i++)
Renderer2D::DrawLine(corners[i], corners[i + 4], color);
}
}
RenderCommandQueue& Renderer::GetRenderCommandQueue()
{
return s_Data.m_CommandQueue;

View File

@ -22,11 +22,13 @@ namespace Prism
static void Clear();
static void Clear(float r, float g, float b, float a = 1.0f);
static void SetClearColor(float r, float g, float b, float a);
static void DrawIndexed(uint32_t count, bool depthTest = true);
static const Scope<ShaderLibrary>& GetShaderLibrary();
static void DrawIndexed(uint32_t count, PrimitiveType type, bool depthTest = true);
// For OpenGL
static void SetLineThickness(float thickness);
template<typename FuncT>
static void Submit(FuncT&& func)
{
@ -47,13 +49,14 @@ namespace Prism
public:
static void BeginRenderPass(const Ref<RenderPass>& renderPass);
static void BeginRenderPass(const Ref<RenderPass>& renderPass, bool clear = true);
static void EndRenderPass();
static void SubmitQuad(const Ref<MaterialInstance>& material, const glm::mat4& transform = glm::mat4(1.0f));
static void SubmitFullscreenQuad(const Ref<MaterialInstance>& material);
static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial = nullptr);
static void DrawAABB(const Ref<Mesh>& mesh, const glm::vec4& color = glm::vec4(1.0f));
private:
static RenderCommandQueue& GetRenderCommandQueue();
};

View File

@ -0,0 +1,418 @@
//
// Created by sfd on 25-12-1.
//
#include "Renderer2D.h"
#include "Renderer.h"
#include "Shader.h"
#include "VertexArray.h"
namespace Prism
{
struct QuadVertex
{
glm::vec3 Position;
glm::vec4 Color;
glm::vec2 TexCoord;
float TexIndex;
float TilingFactor;
};
struct LineVertex
{
glm::vec3 Position;
glm::vec4 Color;
};
struct Renderer2DData
{
static constexpr uint32_t MaxQuads = 20000;
static constexpr uint32_t MaxVertices = MaxQuads * 4;
static constexpr uint32_t MaxIndices = MaxQuads * 6;
static constexpr uint32_t MaxTextureSlots = 32; // TODO: RenderCaps
static constexpr uint32_t MaxLines = 10000;
static constexpr uint32_t MaxLineVertices = MaxLines * 2;
static constexpr uint32_t MaxLineIndices = MaxLines * 6;
// Quad
Ref<VertexArray> QuadVertexArray;
Ref<VertexBuffer> QuadVertexBuffer;
Ref<Shader> TextureShader;
Ref<Texture2D> WhiteTexture;
uint32_t QuadIndexCount = 0;
QuadVertex* QuadVertexBufferBase = nullptr;
QuadVertex* QuadVertexBufferPtr = nullptr;
std::array<Ref<Texture2D>, MaxTextureSlots> TextureSlots;
uint32_t TextureSlotIndex = 1; // 0 = white texture
glm::vec4 QuadVertexPositions[4];
// Lines
Ref<VertexArray> LineVertexArray;
Ref<VertexBuffer> LineVertexBuffer;
Ref<Shader> LineShader;
uint32_t LineIndexCount = 0;
LineVertex* LineVertexBufferBase = nullptr;
LineVertex* LineVertexBufferPtr = nullptr;
glm::mat4 CameraViewProj;
bool DepthTest = true;
Renderer2D::Statistics Stats;
};
static Renderer2DData s_Data;
static glm::vec2 defaultTexCoords[] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
void Renderer2D::Init()
{
s_Data.QuadVertexArray = VertexArray::Create();
s_Data.QuadVertexBuffer = VertexBuffer::Create(s_Data.MaxVertices * sizeof(QuadVertex));
s_Data.QuadVertexBuffer->SetLayout({
{ ShaderDataType::Float3, "a_Position" },
{ ShaderDataType::Float4, "a_Color" },
{ ShaderDataType::Float2, "a_TexCoord" },
{ ShaderDataType::Float, "a_TexIndex" },
{ ShaderDataType::Float, "a_TilingFactor" }
});
s_Data.QuadVertexArray->AddVertexBuffer(s_Data.QuadVertexBuffer);
s_Data.QuadVertexBufferBase = new QuadVertex[s_Data.MaxVertices];
uint32_t* quadIndices = new uint32_t[s_Data.MaxIndices];
uint32_t offset = 0;
for (uint32_t i = 0; i < s_Data.MaxIndices; i += 6)
{
quadIndices[i + 0] = offset + 0;
quadIndices[i + 1] = offset + 1;
quadIndices[i + 2] = offset + 2;
quadIndices[i + 3] = offset + 2;
quadIndices[i + 4] = offset + 3;
quadIndices[i + 5] = offset + 0;
offset += 4;
}
Ref<IndexBuffer> quadIB = IndexBuffer::Create(quadIndices, s_Data.MaxIndices);
s_Data.QuadVertexArray->SetIndexBuffer(quadIB);
delete[] quadIndices;
s_Data.WhiteTexture = Texture2D::Create(TextureFormat::RGBA, 1, 1);
uint32_t whiteTextureData = 0xffffffff;
s_Data.WhiteTexture->Lock();
s_Data.WhiteTexture->GetWriteableBuffer().Write(&whiteTextureData, sizeof(uint32_t));
s_Data.WhiteTexture->Unlock();
s_Data.TextureShader = Shader::Create("assets/shaders/Renderer2D.glsl");
// Set all texture slots to 0
s_Data.TextureSlots[0] = s_Data.WhiteTexture;
s_Data.QuadVertexPositions[0] = { -0.5f, -0.5f, 0.0f, 1.0f };
s_Data.QuadVertexPositions[1] = { 0.5f, -0.5f, 0.0f, 1.0f };
s_Data.QuadVertexPositions[2] = { 0.5f, 0.5f, 0.0f, 1.0f };
s_Data.QuadVertexPositions[3] = { -0.5f, 0.5f, 0.0f, 1.0f };
// Lines
s_Data.LineShader = Shader::Create("assets/shaders/Renderer2D_Line.glsl");
s_Data.LineVertexArray = VertexArray::Create();
s_Data.LineVertexBuffer = VertexBuffer::Create(s_Data.MaxLineVertices * sizeof(LineVertex));
s_Data.LineVertexBuffer->SetLayout({
{ ShaderDataType::Float3, "a_Position" },
{ ShaderDataType::Float4, "a_Color" }
});
s_Data.LineVertexArray->AddVertexBuffer(s_Data.LineVertexBuffer);
s_Data.LineVertexBufferBase = new LineVertex[s_Data.MaxLineVertices];
uint32_t* lineIndices = new uint32_t[s_Data.MaxLineIndices];
for (uint32_t i = 0; i < s_Data.MaxLineIndices; i++)
lineIndices[i] = i;
Ref<IndexBuffer> lineIB = IndexBuffer::Create(lineIndices, s_Data.MaxLineIndices);
s_Data.LineVertexArray->SetIndexBuffer(lineIB);
delete[] lineIndices;
}
void Renderer2D::Shutdown()
{
}
void Renderer2D::BeginScene(const glm::mat4& viewProj, bool depthTest)
{
s_Data.CameraViewProj = viewProj;
s_Data.DepthTest = depthTest;
s_Data.TextureShader->Bind();
s_Data.TextureShader->SetMat4("u_ViewProjection", viewProj);
s_Data.QuadIndexCount = 0;
s_Data.QuadVertexBufferPtr = s_Data.QuadVertexBufferBase;
s_Data.LineIndexCount = 0;
s_Data.LineVertexBufferPtr = s_Data.LineVertexBufferBase;
s_Data.TextureSlotIndex = 1;
}
void Renderer2D::EndScene()
{
uint32_t dataSize = (uint8_t*)s_Data.QuadVertexBufferPtr - (uint8_t*)s_Data.QuadVertexBufferBase;
if (dataSize)
{
s_Data.QuadVertexBuffer->SetData(s_Data.QuadVertexBufferBase, dataSize);
s_Data.TextureShader->Bind();
s_Data.TextureShader->SetMat4("u_ViewProjection", s_Data.CameraViewProj);
for (uint32_t i = 0; i < s_Data.TextureSlotIndex; i++)
s_Data.TextureSlots[i]->Bind(i);
s_Data.QuadVertexArray->Bind();
Renderer::DrawIndexed(s_Data.QuadIndexCount, PrimitiveType::Triangles, s_Data.DepthTest);
s_Data.Stats.DrawCalls++;
}
dataSize = (uint8_t*)s_Data.LineVertexBufferPtr - (uint8_t*)s_Data.LineVertexBufferBase;
if (dataSize)
{
s_Data.LineVertexBuffer->SetData(s_Data.LineVertexBufferBase, dataSize);
s_Data.LineShader->Bind();
s_Data.LineShader->SetMat4("u_ViewProjection", s_Data.CameraViewProj);
s_Data.LineVertexArray->Bind();
Renderer::SetLineThickness(2.0f);
Renderer::DrawIndexed(s_Data.LineIndexCount, PrimitiveType::Lines, s_Data.DepthTest);
s_Data.Stats.DrawCalls++;
}
#if OLD
Flush();
#endif
}
void Renderer2D::Flush()
{
#if OLD
// Bind textures
for (uint32_t i = 0; i < s_Data.TextureSlotIndex; i++)
s_Data.TextureSlots[i]->Bind(i);
s_Data.QuadVertexArray->Bind();
Renderer::DrawIndexed(s_Data.QuadIndexCount, false);
s_Data.Stats.DrawCalls++;
#endif
}
void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color)
{
DrawQuad({ position.x, position.y, 0.0f }, size, color);
}
void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color)
{
if (s_Data.QuadIndexCount >= Renderer2DData::MaxIndices)
FlushAndReset();
const float textureIndex = 0.0f; // White Texture
const float tilingFactor = 1.0f;
glm::mat4 transform = glm::translate(glm::mat4(1.0f), position)
* glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f });
for (uint32_t i = 0; i < 4; i++)
{
s_Data.QuadVertexBufferPtr->Position = transform * s_Data.QuadVertexPositions[i];
s_Data.QuadVertexBufferPtr->Color = color;
s_Data.QuadVertexBufferPtr->TexCoord = defaultTexCoords[i];
s_Data.QuadVertexBufferPtr->TexIndex = textureIndex;
s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
s_Data.QuadVertexBufferPtr++;
}
s_Data.QuadIndexCount += 6;
s_Data.Stats.QuadCount++;
}
void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref<Texture2D>& texture, float tilingFactor, const glm::vec4& tintColor)
{
DrawQuad({ position.x, position.y, 0.0f }, size, texture, tilingFactor, tintColor);
}
void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref<Texture2D>& texture, float tilingFactor, const glm::vec4& tintColor)
{
if (s_Data.QuadIndexCount >= Renderer2DData::MaxIndices)
FlushAndReset();
constexpr glm::vec4 color = { 1.0f, 1.0f, 1.0f, 1.0f };
float textureIndex = 0.0f;
for (uint32_t i = 1; i < s_Data.TextureSlotIndex; i++)
{
if (*s_Data.TextureSlots[i].get() == *texture.get())
{
textureIndex = (float)i;
break;
}
}
if (textureIndex == 0.0f)
{
textureIndex = (float)s_Data.TextureSlotIndex;
s_Data.TextureSlots[s_Data.TextureSlotIndex] = texture;
s_Data.TextureSlotIndex++;
}
glm::mat4 transform = glm::translate(glm::mat4(1.0f), position)
* glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f });
for (uint32_t i = 0; i < 4; i++)
{
s_Data.QuadVertexBufferPtr->Position = transform * s_Data.QuadVertexPositions[i];
s_Data.QuadVertexBufferPtr->Color = color;
s_Data.QuadVertexBufferPtr->TexCoord = defaultTexCoords[i];
s_Data.QuadVertexBufferPtr->TexIndex = textureIndex;
s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
s_Data.QuadVertexBufferPtr++;
}
s_Data.QuadIndexCount += 6;
s_Data.Stats.QuadCount++;
}
void Renderer2D::DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const glm::vec4& color)
{
DrawRotatedQuad({ position.x, position.y, 0.0f }, size, rotation, color);
}
void Renderer2D::DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const glm::vec4& color)
{
if (s_Data.QuadIndexCount >= Renderer2DData::MaxIndices)
FlushAndReset();
const float textureIndex = 0.0f; // White Texture
const float tilingFactor = 1.0f;
glm::mat4 transform = glm::translate(glm::mat4(1.0f), position)
* glm::rotate(glm::mat4(1.0f), glm::radians(rotation), { 0.0f, 0.0f, 1.0f })
* glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f });
for (uint32_t i = 1; i < 4; i++)
{
s_Data.QuadVertexBufferPtr->Position = transform * s_Data.QuadVertexPositions[i];
s_Data.QuadVertexBufferPtr->Color = color;
s_Data.QuadVertexBufferPtr->TexCoord = defaultTexCoords[i];
s_Data.QuadVertexBufferPtr->TexIndex = textureIndex;
s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
s_Data.QuadVertexBufferPtr++;
}
s_Data.QuadIndexCount += 6;
s_Data.Stats.QuadCount++;
}
void Renderer2D::DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const Ref<Texture2D>& texture, float tilingFactor, const glm::vec4& tintColor)
{
DrawRotatedQuad({ position.x, position.y, 0.0f }, size, rotation, texture, tilingFactor, tintColor);
}
void Renderer2D::DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const Ref<Texture2D>& texture, float tilingFactor, const glm::vec4& tintColor)
{
if (s_Data.QuadIndexCount >= Renderer2DData::MaxIndices)
FlushAndReset();
constexpr glm::vec4 color = { 1.0f, 1.0f, 1.0f, 1.0f };
float textureIndex = 0.0f;
for (uint32_t i = 1; i < s_Data.TextureSlotIndex; i++)
{
if (*s_Data.TextureSlots[i].get() == *texture.get())
{
textureIndex = (float)i;
break;
}
}
if (textureIndex == 0.0f)
{
textureIndex = (float)s_Data.TextureSlotIndex;
s_Data.TextureSlots[s_Data.TextureSlotIndex] = texture;
s_Data.TextureSlotIndex++;
}
glm::mat4 transform = glm::translate(glm::mat4(1.0f), position)
* glm::rotate(glm::mat4(1.0f), glm::radians(rotation), { 0.0f, 0.0f, 1.0f })
* glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f });
for (uint32_t i = 1; i < 4; i++)
{
s_Data.QuadVertexBufferPtr->Position = transform * s_Data.QuadVertexPositions[i];
s_Data.QuadVertexBufferPtr->Color = color;
s_Data.QuadVertexBufferPtr->TexCoord = defaultTexCoords[i];
s_Data.QuadVertexBufferPtr->TexIndex = textureIndex;
s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
s_Data.QuadVertexBufferPtr++;
}
s_Data.QuadIndexCount += 6;
s_Data.Stats.QuadCount++;
}
void Renderer2D::DrawLine(const glm::vec3& p0, const glm::vec3& p1, const glm::vec4& color)
{
if (s_Data.LineIndexCount >= Renderer2DData::MaxLineIndices)
FlushAndResetLines();
s_Data.LineVertexBufferPtr->Position = p0;
s_Data.LineVertexBufferPtr->Color = color;
s_Data.LineVertexBufferPtr++;
s_Data.LineVertexBufferPtr->Position = p1;
s_Data.LineVertexBufferPtr->Color = color;
s_Data.LineVertexBufferPtr++;
s_Data.LineIndexCount += 2;
s_Data.Stats.LineCount++;
}
void Renderer2D::ResetStats()
{
memset(&s_Data.Stats, 0, sizeof(Statistics));
}
Renderer2D::Statistics Renderer2D::GetStats()
{
return s_Data.Stats;
}
void Renderer2D::FlushAndReset()
{
EndScene();
s_Data.QuadIndexCount = 0;
s_Data.QuadVertexBufferPtr = s_Data.QuadVertexBufferBase;
s_Data.TextureSlotIndex = 1;
}
void Renderer2D::FlushAndResetLines()
{
}
}

View File

@ -0,0 +1,57 @@
//
// Created by sfd on 25-12-1.
//
#ifndef RENDERER2D_H
#define RENDERER2D_H
#include <glm/glm.hpp>
#include "Texture.h"
namespace Prism
{
class PRISM_API Renderer2D
{
public:
static void Init();
static void Shutdown();
static void BeginScene(const glm::mat4& viewProj, bool depthTest = true);
static void EndScene();
static void Flush();
// Primitives
static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color);
static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color);
static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref<Texture2D>& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f));
static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref<Texture2D>& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f));
static void DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const glm::vec4& color);
static void DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const glm::vec4& color);
static void DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const Ref<Texture2D>& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f));
static void DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const Ref<Texture2D>& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f));
static void DrawLine(const glm::vec3& p0, const glm::vec3& p1, const glm::vec4& color = glm::vec4(1.0f));
// Stats
struct Statistics
{
uint32_t DrawCalls = 0;
uint32_t QuadCount = 0;
uint32_t LineCount = 0;
uint32_t GetTotalVertexCount() { return QuadCount * 4 + LineCount * 2; }
uint32_t GetTotalIndexCount() { return QuadCount * 6 + LineCount * 2; }
};
static void ResetStats();
static Statistics GetStats();
private:
static void FlushAndReset();
static void FlushAndResetLines();
};
}
#endif //RENDERER2D_H

View File

@ -16,14 +16,21 @@ namespace Prism
OpenGL
};
// TODO: move into separate header
enum class PrimitiveType
{
None = 0, Triangles, Lines
};
struct RenderAPICapabilities
{
std::string Vendor;
std::string Renderer;
std::string Version;
int MaxSamples;
float MaxAnisotropy;
int MaxSamples = 0;
float MaxAnisotropy = 0.0f;
int MaxTextureUnits = 0;
};
class RendererAPI
@ -35,7 +42,8 @@ namespace Prism
static void Clear(float r, float g, float b, float a);
static void SetClearColor(float r, float g, float b, float a);
static void DrawIndexed(unsigned int count, bool depthTest = true);
static void DrawIndexed(uint32_t count,PrimitiveType type, bool depthTest = true);
static void SetLineThickness(float thickness);
static RendererAPIType Current() { return s_CurrentRendererAPI; }
static RenderAPICapabilities& GetCapabilities()

View File

@ -9,6 +9,7 @@
#include "Material.h"
#include "Mesh.h"
#include "Renderer.h"
#include "Renderer2D.h"
#include "RenderPass.h"
#include "glad/glad.h"
@ -42,6 +43,8 @@ namespace Prism
// Grid
Ref<MaterialInstance> GridMaterial;
SceneRendererOptions Options;
};
static SceneRendererData s_Data;
@ -52,6 +55,7 @@ namespace Prism
geoFramebufferSpec.Width = 1280;
geoFramebufferSpec.Height = 720;
geoFramebufferSpec.Format = FramebufferFormat::RGBA16F;
geoFramebufferSpec.Samples = 8;
geoFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
RenderPassSpecification geoRenderPassSpec;
@ -68,7 +72,8 @@ namespace Prism
compRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(compFramebufferSpec);
s_Data.CompositePass = RenderPass::Create(compRenderPassSpec);
s_Data.CompositeShader = Shader::Create("assets/shaders/hdr.glsl");
s_Data.CompositeShader = Shader::Create("assets/shaders/SceneComposite.glsl");
// s_Data.CompositeShader = Shader::Create("assets/shaders/hdr.glsl");
s_Data.BRDFLUT = Texture2D::Create("assets/textures/BRDF_LUT.tga");
@ -178,11 +183,17 @@ namespace Prism
{
glBindImageTexture(0, irradianceMap->GetRendererID(), 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA16F);
glDispatchCompute(irradianceMap->GetWidth() / 32, irradianceMap->GetHeight() / 32, 6);
glGenerateTextureMipmap(irradianceMap->GetRendererID());
});
return { envFiltered, irradianceMap };
}
Ref<RenderPass> SceneRenderer::GetFinalRenderPass()
{
return s_Data.CompositePass;
}
Ref<Texture2D> SceneRenderer::GetFinalColorBuffer()
{
PM_CORE_ASSERT(false, "Not implemented");
@ -194,6 +205,11 @@ namespace Prism
return s_Data.CompositePass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
}
SceneRendererOptions& SceneRenderer::GetOptions()
{
return s_Data.Options;
}
void SceneRenderer::FlushDrawList()
{
PM_CORE_ASSERT(!s_Data.ActiveScene);
@ -209,7 +225,7 @@ namespace Prism
{
Renderer::BeginRenderPass(s_Data.GeoPass);
auto viewProjection = s_Data.SceneData.SceneCamera.GetProjectionMatrix() * s_Data.SceneData.SceneCamera.GetViewMatrix();
const auto viewProjection = s_Data.SceneData.SceneCamera.GetViewProjection();
// Skybox
auto skyboxShader = s_Data.SceneData.SkyboxMaterial->GetShader();
@ -234,8 +250,20 @@ namespace Prism
}
// Grid
s_Data.GridMaterial->Set("u_ViewProjection", viewProjection);
Renderer::SubmitQuad(s_Data.GridMaterial, glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)) * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f)));
const auto option = GetOptions();
if (option.ShowGrid)
{
s_Data.GridMaterial->Set("u_ViewProjection", viewProjection);
Renderer::SubmitQuad(s_Data.GridMaterial, glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)) * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f)));
}
if (option.ShowBoundingBoxes)
{
Renderer2D::BeginScene(viewProjection);
for (auto& dc : s_Data.DrawList)
Renderer::DrawAABB(dc.mesh);
Renderer2D::EndScene();
}
Renderer::EndRenderPass();
}
@ -245,6 +273,7 @@ namespace Prism
Renderer::BeginRenderPass(s_Data.CompositePass);
s_Data.CompositeShader->Bind();
s_Data.CompositeShader->SetFloat("u_Exposure", s_Data.SceneData.SceneCamera.GetExposure());
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();

View File

@ -4,12 +4,19 @@
#ifndef SCENERENDERER_H
#define SCENERENDERER_H
#include "RenderPass.h"
#include "Texture.h"
#include "Prism/Scene/Scene.h"
namespace Prism
{
struct SceneRendererOptions
{
bool ShowGrid = true;
bool ShowBoundingBoxes = false;
};
class PRISM_API SceneRenderer
{
public:
@ -24,11 +31,14 @@ namespace Prism
static std::pair<Ref<TextureCube>, Ref<TextureCube>> CreateEnvironmentMap(const std::string& filepath);
static Ref<RenderPass> GetFinalRenderPass();
static Ref<Texture2D> GetFinalColorBuffer();
// TODO: Temp
static uint32_t GetFinalColorBufferRendererID();
static SceneRendererOptions& GetOptions();
private:
static void FlushDrawList();
static void GeometryPass();

View File

@ -110,9 +110,12 @@ namespace Prism
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) = 0;
virtual void SetFloat(const std::string& name, float value) = 0;
virtual void SetInt(const std::string& name, int value) = 0;
virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0;
virtual void SetMat4FromRenderThread(const std::string& name, const glm::mat4& value, bool bind = true) = 0;
virtual void SetIntArray(const std::string& name, int* values, uint32_t size) = 0;
virtual const std::string& GetName() const = 0;
virtual void SetVSMaterialUniformBuffer(Buffer buffer) = 0;

View File

@ -43,6 +43,8 @@ namespace Prism
static uint32_t GetBPP(TextureFormat format);
static uint32_t CalculateMipMapCount(uint32_t width, uint32_t height);
virtual bool operator==(const Texture& other) const = 0;
};
class PRISM_API Texture2D : public Texture

View File

@ -25,6 +25,7 @@ namespace Prism
virtual const std::vector<Ref<VertexBuffer>>& GetVertexBuffers() const = 0;
virtual const Ref<IndexBuffer>& GetIndexBuffer() const = 0;
virtual RendererID GetRendererID() const = 0;
};
}

View File

@ -6,12 +6,12 @@
namespace Prism
{
Entity::Entity()
: m_Transform(glm::mat4(1.0f))
{
}
Entity::~Entity()
{
}
Entity::Entity(const std::string& name)
: m_Name(name), m_Transform(glm::mat4(1.0f))
{
}
}

View File

@ -13,7 +13,6 @@ namespace Prism
class PRISM_API Entity
{
public:
Entity();
~Entity();
// TODO: Move to Component
@ -25,12 +24,21 @@ namespace Prism
const glm::mat4& GetTransform() const { return m_Transform; }
glm::mat4& Transform() { return m_Transform; }
const std::string& GetName() const { return m_Name; }
private:
Entity(const std::string& name);
private:
std::string m_Name;
glm::mat4 m_Transform;
// TODO: Temp
Ref<Mesh> m_Mesh;
Ref<MaterialInstance> m_Material;
private:
friend class Scene;
};
}

View File

@ -35,8 +35,6 @@ namespace Prism
void Scene::OnUpdate(TimeStep ts)
{
m_Camera.Update(ts);
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
// Update all entities
@ -59,6 +57,11 @@ namespace Prism
SceneRenderer::EndScene();
}
void Scene::OnEvent(Event& e)
{
m_Camera.OnEvent(e);
}
void Scene::SetCamera(const Camera& camera)
{
m_Camera = camera;
@ -81,9 +84,12 @@ namespace Prism
m_Entities.push_back(entity);
}
Entity* Scene::CreateEntity()
static const std::string DefaultEntityName = "Entity";
Entity* Scene::CreateEntity(const std::string& name)
{
const auto entity = new Entity();
const std::string& entityName = name.empty() ? DefaultEntityName : name;
const auto entity = new Entity(entityName);
AddEntity(entity);
return entity;
}

View File

@ -5,6 +5,7 @@
#ifndef SCENE_H
#define SCENE_H
#include "Entity.h"
#include "Prism/Core/Events/Event.h"
#include "Prism/Renderer/Camera.h"
#include "Prism/Renderer/Material.h"
@ -28,6 +29,7 @@ namespace Prism
void Init();
void OnUpdate(TimeStep ts);
void OnEvent(Event& e);
void SetCamera(const Camera& camera);
Camera& GetCamera() { return m_Camera; }
@ -38,7 +40,7 @@ namespace Prism
float& GetSkyboxLod() { return m_SkyboxLod; }
void AddEntity(Entity* entity);
Entity* CreateEntity();
Entity* CreateEntity(const std::string& name = "");
private:
std::string m_DebugName;

View File

@ -142,68 +142,24 @@ static void EnableDockSpace(const bool enable)
TestLayer::TestLayer()
:m_Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 1000.0f))
{
}
void TestLayer::OnAttach()
{
Prism::FramebufferSpecification geoFramebufferspec;
geoFramebufferspec.Width = 1280;
geoFramebufferspec.Height = 720;
geoFramebufferspec.Format = Prism::FramebufferFormat::RGBA16F;
geoFramebufferspec.ClearColor = {0.1f, 0.1f, 0.1f, 1.0f};
auto environment = Prism::Environment::Load("assets/env/birchwood_4k.hdr");
{
m_Scene = Prism::CreateRef<Prism::Scene>("test Scene");
m_Scene->SetCamera(Prism::Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f)));
m_Scene->SetEnvironment(environment);
Prism::RenderPassSpecification geoRenderPass;
geoRenderPass.TargetFramebuffer = Prism::FrameBuffer::Create(geoFramebufferspec);
m_GeoPass = Prism::RenderPass::Create(geoRenderPass);
m_MeshEntity = m_Scene->CreateEntity("test Entity");
Prism::FramebufferSpecification finalFramebufferspec;
finalFramebufferspec.Width = 1280;
finalFramebufferspec.Height = 720;
finalFramebufferspec.Format = Prism::FramebufferFormat::RGBA8;
finalFramebufferspec.ClearColor = {0.1f, 0.1f, 0.1f, 1.0f};
m_MeshEntity->SetMesh(Prism::CreateRef<Prism::Mesh>("assets/meshes/TestScene.fbx"));
m_MeshMaterial = m_MeshEntity->GetMesh()->GetMaterial();
Prism::RenderPassSpecification finalRenderPass;
finalRenderPass.TargetFramebuffer = Prism::FrameBuffer::Create(finalFramebufferspec);
m_FinalPass = Prism::RenderPass::Create(finalRenderPass);
}
static float QuadVertex[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
static uint32_t QuadIndices[] = {
0, 1, 2, 2, 3, 0
};
m_VertexArray = Prism::VertexArray::Create();
auto quadVB = Prism::VertexBuffer::Create(QuadVertex, sizeof(QuadVertex) * sizeof(float));
quadVB->SetLayout({
{ Prism::ShaderDataType::Float3, "a_Position" },
{ Prism::ShaderDataType::Float2, "a_TexCoord" }
});
m_VertexArray->AddVertexBuffer(quadVB);
auto ib = Prism::IndexBuffer::Create(QuadIndices, 6 * sizeof(uint32_t));
m_VertexArray->SetIndexBuffer(ib);
m_SkyBoxTextureCube.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Radiance.tga"));
m_EnvironmentIrradiance.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Irradiance.tga"));
m_SkyBoxShader = Prism::Shader::Create("assets/shaders/quad.glsl");
m_HDRShader = Prism::Shader::Create("assets/shaders/hdr.glsl");
m_Mesh = std::make_unique<Prism::Mesh>("assets/models/m1911/m1911.fbx");
m_MeshMaterial = Prism::CreateRef<Prism::MaterialInstance>(m_Mesh->GetMaterial());
m_BRDFLUT.reset(Prism::Texture2D::Create("assets/textures/BRDF_LUT.tga"));
m_Light.Direction = {-0.5f, -0.5f, 1.0f};
m_Light.Radiance = {1.0f, 1.0f, 1.0f};
}
void TestLayer::OnDetach()
@ -213,78 +169,48 @@ void TestLayer::OnDetach()
void TestLayer::OnUpdate(Prism::TimeStep deltaTime)
{
m_Camera.Update(deltaTime);
auto viewProjection = m_Camera.GetProjectionMatrix() * m_Camera.GetViewMatrix();
Prism::Renderer::BeginRenderPass(m_GeoPass);
Prism::Renderer::Clear(m_clearColor[0], m_clearColor[1], m_clearColor[2], m_clearColor[3]);
// SkyBox
m_SkyBoxShader->Bind();
m_SkyBoxShader->SetMat4("u_InverseVP", inverse(viewProjection));
m_SkyBoxTextureCube->Bind(0);
m_VertexArray->Bind();
Prism::Renderer::DrawIndexed(m_VertexArray->GetIndexBuffer()->GetCount(), false);
m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value);
m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value);
m_MeshMaterial->Set("u_ViewProjectionMatrix", viewProjection);
m_MeshMaterial->Set("u_ModelMatrix", glm::scale(glm::mat4(1.0f), glm::vec3(m_MeshScale)));
m_MeshMaterial->Set("lights", m_Light);
m_MeshMaterial->Set("u_CameraPosition", m_Camera.GetPosition());
m_MeshMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
m_MeshMaterial->Set("u_EnvRadianceTex", m_SkyBoxTextureCube);
m_MeshMaterial->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance);
m_MeshMaterial->Set("u_BRDFLUTTexture", m_BRDFLUT);
m_Mesh->Render(deltaTime, glm::mat4(1.0f), m_MeshMaterial);
if (m_AllowViewportCameraEvents)
m_Scene->GetCamera().OnUpdate(deltaTime);
Prism::Renderer::EndRenderPass();
// HDR
Prism::Renderer::BeginRenderPass(m_FinalPass);
m_HDRShader->Bind();
m_HDRShader->SetFloat("u_Exposure", m_Exposure);
m_GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
m_VertexArray->Bind();
Prism::Renderer::DrawIndexed(m_VertexArray->GetIndexBuffer()->GetCount(), false);
Prism::Renderer::EndRenderPass();
m_Scene->OnUpdate(deltaTime);
}
void TestLayer::OnImGuiRender()
{
EnableDockSpace(true);
ImGui::Begin("Settings");
ImGui::ColorEdit4("ClearColor", glm::value_ptr(m_clearColor));
ImGui::ColorEdit4("TriangleClearColor", glm::value_ptr(m_TriangleColor));
ImGui::DragFloat("Exposure", &m_Exposure, 0.01f, 0.0f);
const auto& position = m_Camera.GetPosition();
ImGui::Text("Camera: (%.2f, %.2f, %.2f)", position.x, position.y, position.z);
ImGui::End();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::Begin("Viewport");
auto viewportSize = ImGui::GetContentRegionAvail();
m_GeoPass->GetSpecification().TargetFramebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_FinalPass->GetSpecification().TargetFramebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_Camera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
ImGui::Image((ImTextureRef)m_FinalPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID(), viewportSize, {0, 1}, {1, 0});
Prism::SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_Scene->GetCamera().SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
m_Scene->GetCamera().SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
ImGui::Image((ImTextureRef)Prism::SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
auto windowSize = ImGui::GetWindowSize();
ImVec2 minBound = ImGui::GetWindowPos();
ImVec2 maxBound = { minBound.x + windowSize.x, minBound.y + windowSize.y };
m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound);
ImGui::End();
ImGui::PopStyleVar();
}
void TestLayer::OnEvent(Prism::Event& e)
{
if (m_AllowViewportCameraEvents)
m_Scene->GetCamera().OnEvent(e);
}

View File

@ -13,6 +13,7 @@
#include "Prism/Renderer/RenderPass.h"
#include "Prism/Renderer/Shader.h"
#include "Prism/Renderer/Texture.h"
#include "Prism/Scene/Scene.h"
class TestLayer : public Prism::Layer
@ -29,16 +30,11 @@ private:
glm::vec4 m_clearColor = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f);
glm::vec4 m_TriangleColor = glm::vec4(1.0f);
Prism::Ref<Prism::RenderPass> m_GeoPass, m_FinalPass;
Prism::Ref<Prism::Scene> m_Scene;
Prism::Entity* m_MeshEntity;
Prism::Ref<Prism::Material> m_MeshMaterial;
Prism::Ref<Prism::VertexArray> m_VertexArray;
Prism::Ref<Prism::TextureCube> m_SkyBoxTextureCube, m_EnvironmentIrradiance;
Prism::Ref<Prism::Shader> m_HDRShader, m_SkyBoxShader;
Prism::Ref<Prism::Mesh> m_Mesh;
Prism::Ref<Prism::MaterialInstance> m_MeshMaterial;
Prism::Ref<Prism::Texture2D> m_BRDFLUT;
Prism::Camera m_Camera;
bool m_AllowViewportCameraEvents = false;
float m_Exposure = 1.0f;