add AnimationComponent, Skeleton, AnimationClip; add single Renderer3D class, remove some useless code; problem now renderer2D cannot blend with Renderer3D

This commit is contained in:
2026-03-11 09:19:05 +08:00
parent eb0a463370
commit a265e71e1a
29 changed files with 2278 additions and 1466 deletions

View File

@ -76,16 +76,6 @@ namespace Prism
m_EditorScene->OnRenderEditor(deltaTime, m_EditorCamera);
if (m_DrawOnTopBoundingBoxes)
{
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
const auto viewProj = m_EditorCamera.GetViewProjection();
Renderer2D::BeginScene(viewProj, false);
// TODO: Renderer::DrawAABB(m_MeshEntity.GetComponent<MeshComponent>(), m_MeshEntity.GetComponent<TransformComponent>());
Renderer2D::EndScene();
Renderer::EndRenderPass();
}
if (!m_SelectionContext.empty() && false)
{
auto& selection = m_SelectionContext[0];
@ -530,10 +520,7 @@ namespace Prism
}
}
if (UI::Property("Show Bounding Boxes", m_UIShowBoundingBoxes))
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
if (m_UIShowBoundingBoxes && UI::Property("On Top", m_UIShowBoundingBoxesOnTop))
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
UI::Property("Show Bounding Boxes", m_UIShowBoundingBoxes);
const char* label = m_SelectionMode == SelectionMode::Entity ? "Entity" : "Mesh";
if (ImGui::Button(label))
@ -903,7 +890,7 @@ namespace Prism
bool EditorLayer::OnKeyPressedEvent(KeyPressedEvent& e)
{
if (m_ViewportPanelFocused)
if (m_ViewportPanelFocused || m_ViewportPanelHovered)
{
switch (e.GetKeyCode())
{
@ -921,7 +908,7 @@ namespace Prism
break;
case KeyCode::F:
{
if (m_SelectionContext.size() == 0)
if (m_SelectionContext.empty())
break;
Entity selectedEntity = m_SelectionContext[0].Entity;
@ -964,7 +951,7 @@ namespace Prism
case KeyCode::B:
// Toggle bounding boxes
m_UIShowBoundingBoxes = !m_UIShowBoundingBoxes;
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
ShowBoundingBoxes(m_UIShowBoundingBoxes,false);
break;
case KeyCode::D:
if (m_SelectionContext.size())
@ -1053,7 +1040,21 @@ namespace Prism
return a.Distance < b.Distance;
});
if (!m_SelectionContext.empty())
{
if (auto alreadySelectedEntity = m_SceneHierarchyPanel->GetSelected();
m_SelectionContext.size() != 1 && alreadySelectedEntity)
{
const auto alreadySelectedEntityID = alreadySelectedEntity.GetUUID();
for (const auto& selectedEntity : m_SelectionContext)
{
if (alreadySelectedEntityID == selectedEntity.Entity.GetUUID()) continue;
OnSelected(selectedEntity);
return false;
}
}
OnSelected(m_SelectionContext[0]);
}
}
}
return false;
@ -1062,7 +1063,6 @@ namespace Prism
void EditorLayer::ShowBoundingBoxes(bool show, bool onTop)
{
SceneRenderer::GetOptions().ShowBoundingBoxes = show && !onTop;
m_DrawOnTopBoundingBoxes = show && onTop;
}
void EditorLayer::SelectEntity(Entity entity)

View File

@ -138,10 +138,8 @@ namespace Prism
// configure button
bool m_AllowViewportCameraEvents = false;
bool m_DrawOnTopBoundingBoxes = false;
bool m_UIShowBoundingBoxes = false;
bool m_UIShowBoundingBoxesOnTop = false;
enum class SceneType : uint32_t
{

View File

@ -1,62 +1,23 @@
Scene: Scene Name
Environment:
AssetHandle: 1249421934001634765
AssetHandle: 17073147362577408906
Light:
Direction: [-0.314, -0.941, -0.209]
Radiance: [0, 0, 0]
Multiplier: 0
Multiplier: 1
Entities:
- Entity: 18090260616187152572
- Entity: 3696833073589069488
Parent: 0
Children:
[]
TagComponent:
Tag: Directional Light
TransformComponent:
Position: [0, 0, 0]
Rotation: [0, 0, -2.7340124]
Scale: [0.9999992, 0.9999992, 1]
DirectionalLightComponent:
Radiance: [1, 1, 1]
CastShadows: true
SoftShadows: true
LightSize: 0.5
- Entity: 18154648535203342017
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [0, 6.282704, 0]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetID: 133168951455480052
- Entity: 386484027514287028
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [0, 0, 0]
Rotation: [0, 0, 0]
Scale: [50, 1, 50]
MeshComponent:
AssetID: 133168951455480052
- Entity: 6827989772960183355
Parent: 0
Children:
[]
TagComponent:
Tag: Sky Light
Tag: venice_dawn_1_4k
TransformComponent:
Position: [0, 0, 0]
Rotation: [0, 0, 0]
Scale: [1, 1, 1]
SkyLightComponent:
EnvironmentMap: 1249421934001634765
EnvironmentMap: 17073147362577408906
Intensity: 1
Angle: 0
PhysicsLayers:

View File

@ -58,11 +58,12 @@ void main()
vs_Output.WorldTransform = mat3(u_Transform);
vs_Output.Binormal = a_Binormal;
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * vec4(a_Position, 1.0);
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * localPosition;
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
// gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
gl_Position = u_ViewProjectionMatrix * u_Transform * localPosition;
}
#type fragment

View File

@ -0,0 +1,79 @@
//
// Created by Atdunbg on 2026/3/9.
//
#include "AnimationClip.h"
#include "assimp/scene.h"
struct aiAnimation;
namespace Prism
{
AnimationClip::AnimationClip(const aiScene* scene)
{
const aiAnimation* anim = scene->mAnimations[0]; // 先只处理第一个动画
m_Duration = (float)anim->mDuration;
m_TicksPerSecond = (float)(anim->mTicksPerSecond != 0 ? anim->mTicksPerSecond : 25.0);
for (uint32_t i = 0; i < anim->mNumChannels; i++)
{
aiNodeAnim* nodeAnim = anim->mChannels[i];
BoneChannel channel;
channel.BoneName = nodeAnim->mNodeName.C_Str();
// 位置关键帧
for (uint32_t j = 0; j < nodeAnim->mNumPositionKeys; j++)
{
const auto& key = nodeAnim->mPositionKeys[j];
channel.Positions.emplace_back((float)key.mTime,
glm::vec3(key.mValue.x, key.mValue.y, key.mValue.z));
}
// 旋转关键帧
for (uint32_t j = 0; j < nodeAnim->mNumRotationKeys; j++)
{
const auto& key = nodeAnim->mRotationKeys[j];
channel.Rotations.emplace_back((float)key.mTime,
glm::quat(key.mValue.w, key.mValue.x, key.mValue.y, key.mValue.z));
}
// 缩放关键帧
for (uint32_t j = 0; j < nodeAnim->mNumScalingKeys; j++)
{
const auto& key = nodeAnim->mScalingKeys[j];
channel.Scalings.emplace_back((float)key.mTime,
glm::vec3(key.mValue.x, key.mValue.y, key.mValue.z));
}
m_BoneChannels.push_back(channel);
}
}
glm::mat4 AnimationClip::SampleAtTime(const float timeTicks, const std::string& boneName, const glm::mat4& defaultTransform) const
{
for (const auto& channel : m_BoneChannels) {
if (channel.BoneName == boneName) {
const glm::vec3 pos = SampleChannel(channel.Positions, timeTicks, glm::vec3(0.0f));
const glm::quat rot = SampleChannel(channel.Rotations, timeTicks, glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
const glm::vec3 scl = SampleChannel(channel.Scalings, timeTicks, glm::vec3(1.0f));
return glm::translate(glm::mat4(1.0f), pos) * glm::toMat4(rot) * glm::scale(glm::mat4(1.0f), scl);
}
}
return defaultTransform;
}
template <typename T>
T AnimationClip::SampleChannel(const std::vector<KeyFrame<T>>& keys, float time, const T& defaultValue) const
{
if (keys.empty()) return defaultValue;
if (time <= keys.front().Time) return keys.front().Value;
if (time >= keys.back().Time) return keys.back().Value;
// 找到当前时间所在的关键帧区间
for (size_t i = 0; i < keys.size() - 1; ++i) {
if (time >= keys[i].Time && time <= keys[i+1].Time) {
float t = (time - keys[i].Time) / (keys[i+1].Time - keys[i].Time);
return Interpolate(keys[i].Value, keys[i+1].Value, t);
}
}
return defaultValue;
}
}

View File

@ -0,0 +1,63 @@
//
// Created by Atdunbg on 2026/3/9.
//
#ifndef PRISM_ANIMATIONCLIP_H
#define PRISM_ANIMATIONCLIP_H
#include "Prism/Asset/Asset.h"
#include <glm/glm.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/quaternion.hpp>
struct aiScene;
namespace Prism
{
template<typename T>
struct KeyFrame
{
float Time = 0.0f;
T Value;
KeyFrame() = default;
KeyFrame(const float t, const T& v) : Time(t), Value(v) {}
};
struct BoneChannel {
std::string BoneName;
std::vector<KeyFrame<glm::vec3>> Positions;
std::vector<KeyFrame<glm::quat>> Rotations;
std::vector<KeyFrame<glm::vec3>> Scalings;
};
class PRISM_API AnimationClip : public Asset
{
public:
AnimationClip(const aiScene* scene);
glm::mat4 SampleAtTime(float timeTicks, const std::string& boneName, const glm::mat4& defaultTransform) const;
private:
// 辅助采样模板函数
template<typename T>
T SampleChannel(const std::vector<KeyFrame<T>>& keys, float time, const T& defaultValue) const;
glm::vec3 Interpolate(const glm::vec3& a, const glm::vec3& b, const float t) const {
return glm::mix(a, b, t);
}
glm::quat Interpolate(const glm::quat& a, const glm::quat& b, const float t) const {
return glm::slerp(a, b, t);
}
public:
float m_Duration = 0.0f;
float m_TicksPerSecond;
std::vector<BoneChannel> m_BoneChannels;
};
}
#endif //PRISM_ANIMATIONCLIP_H

View File

@ -0,0 +1,115 @@
//
// Created by Atdunbg on 2026/3/9.
//
#include "AnimatorController.h"
namespace Prism
{
AnimationController::~AnimationController()
{
}
void AnimationController::Update(const float deltaTime)
{
if (m_State != PLAY || !m_currentClip || !m_skeleton)
return;
const float rawTime = m_AnimationCurrentTime + deltaTime * m_currentClip->m_TicksPerSecond * m_TimeMultiplier;
const float duration = m_currentClip->m_Duration;
if (!m_Loop && rawTime >= duration)
{
m_AnimationCurrentTime = 0.0f;
m_State = STOP;
}
else
{
m_AnimationCurrentTime = fmod(rawTime, duration);
}
ComputeBoneTransforms(m_AnimationCurrentTime);
}
void AnimationController::ComputeBoneTransforms(float time)
{
const auto boneCount = (uint32_t)m_skeleton->m_Bones.size();
m_FinalBoneTransforms.resize(boneCount);
std::vector<glm::mat4> localTransforms(boneCount, glm::mat4(1.0f));
for (uint32_t i = 0; i < boneCount; i++)
{
const BoneInfo& bone = m_skeleton->m_Bones[i];
if (m_currentClip)
{
localTransforms[i] = m_currentClip->SampleAtTime(time, bone.Name, bone.LocalBindPose);
}
else
{
localTransforms[i] = bone.LocalBindPose;
}
}
// 2. 递归计算全局变换(从根骨骼开始)
std::function<void(uint32_t, const glm::mat4&)> computeGlobal = [&](const uint32_t boneIdx, const glm::mat4& parentGlobal)
{
const glm::mat4 global = parentGlobal * localTransforms[boneIdx];
glm::mat4 final = global * m_skeleton->m_Bones[boneIdx].InverseTransform;
final = m_GlobalInverseTransform * final;
m_FinalBoneTransforms[boneIdx] = final;
for (uint32_t childIdx = 0; childIdx < boneCount; childIdx++)
{
if (m_skeleton->m_Bones[childIdx].ParentIndex == (int)boneIdx)
{
computeGlobal(childIdx, global);
}
}
};
for (uint32_t i = 0; i < boneCount; i++)
{
if (m_skeleton->m_Bones[i].ParentIndex == -1)
{
computeGlobal(i, glm::mat4(1.0f));
}
}
}
void AnimationController::ComputeBindPoseTransforms()
{
if (!m_skeleton) return;
uint32_t boneCount = (uint32_t)m_skeleton->m_Bones.size();
m_FinalBoneTransforms.resize(boneCount);
// 1. 收集每个骨骼的绑定姿势局部变换
std::vector<glm::mat4> localTransforms(boneCount);
for (uint32_t i = 0; i < boneCount; i++)
localTransforms[i] = m_skeleton->m_Bones[i].LocalBindPose;
// 2. 递归计算全局变换,并应用逆绑定矩阵和全局逆矩阵
std::function<void(uint32_t, const glm::mat4&)> computeGlobal =
[&](uint32_t idx, const glm::mat4& parentGlobal)
{
glm::mat4 global = parentGlobal * localTransforms[idx];
glm::mat4 final = m_GlobalInverseTransform * global * m_skeleton->m_Bones[idx].InverseTransform;
m_FinalBoneTransforms[idx] = final;
// 处理子骨骼
for (uint32_t child = 0; child < boneCount; child++)
{
if (m_skeleton->m_Bones[child].ParentIndex == (int)idx)
computeGlobal(child, global);
}
};
// 从所有根骨骼开始递归
for (uint32_t i = 0; i < boneCount; i++)
{
if (m_skeleton->m_Bones[i].ParentIndex == -1)
computeGlobal(i, glm::mat4(1.0f));
}
}
}

View File

@ -0,0 +1,67 @@
//
// Created by Atdunbg on 2026/3/9.
//
#ifndef PRISM_ANIMATORCONTROLLER_H
#define PRISM_ANIMATORCONTROLLER_H
#include "AnimationClip.h"
#include "Skeleton.h"
#include "Prism/Asset/Asset.h"
namespace Prism
{
class PRISM_API AnimationController : public Asset
{
public:
enum AnimationState : uint8_t
{
STOP = 0,
PLAY,
PAUSE
};
public:
~AnimationController();
void Update(const float deltaTime);
const std::vector<glm::mat4>& GetFinalBoneTransforms() const { return m_FinalBoneTransforms; }
void AnimationController::SetSkeleton(const Ref<Skeleton>& skeleton)
{
m_skeleton = skeleton;
if (m_skeleton)
{
ComputeBindPoseTransforms();
}
}
void AnimationController::SetAnimationClip(const Ref<AnimationClip>& clip) { m_currentClip = clip; }
void AnimationController::SetGlobalInverseTransform(const glm::mat4& inv) { m_GlobalInverseTransform = inv; }
void Play() { m_State = PLAY; }
void Pause() { m_State = PAUSE; }
void Stop() { if (m_State == STOP) return; m_State = STOP; m_AnimationCurrentTime = 0.0f; ComputeBindPoseTransforms(); }
AnimationState GetAnimationState() const { return m_State; }
float& GetCurrentTime() { return m_AnimationCurrentTime; }
float& GetMultiplierTime() { return m_TimeMultiplier; }
bool& GetLoop() { return m_Loop; }
private:
void ComputeBoneTransforms(float time);
void ComputeBindPoseTransforms();
Ref<Skeleton> m_skeleton = nullptr;
Ref<AnimationClip> m_currentClip = nullptr;
AnimationState m_State = STOP;
float m_AnimationCurrentTime = 0.0f;
float m_TimeMultiplier = 1.0f;
bool m_Loop = false;
std::vector<glm::mat4> m_FinalBoneTransforms;
glm::mat4 m_GlobalInverseTransform = glm::mat4(1.0f);
};
}
#endif //PRISM_ANIMATORCONTROLLER_H

View File

@ -0,0 +1,68 @@
//
// Created by Atdunbg on 2026/3/9.
//
#include "Skeleton.h"
#include "assimp/scene.h"
namespace Prism
{
// TODO: this maybe move Utils
extern glm::mat4 Mat4FromAssimpMat4(const aiMatrix4x4& matrix);
Skeleton::Skeleton(const aiScene* scene)
{
// 收集所有骨骼(通过所有 Mesh 中的 aiBone
for (uint32_t am = 0; am < scene->mNumMeshes; am++)
{
const aiMesh* aMesh = scene->mMeshes[am];
for (uint32_t i = 0; i < aMesh->mNumBones; i++)
{
const aiBone* bone = aMesh->mBones[i];
if (std::string boneName = bone->mName.C_Str(); m_NameToIndex.find(boneName) == m_NameToIndex.end())
{
const auto boneIndex = (uint32_t)m_Bones.size();
BoneInfo bi;
bi.Name = boneName;
bi.InverseTransform = Mat4FromAssimpMat4(bone->mOffsetMatrix);
bi.ParentIndex = -1; // 稍后设置
m_Bones.push_back(bi);
m_NameToIndex[boneName] = boneIndex;
}
}
}
// 设置骨骼的父子关系及默认局部变换(遍历节点树)
std::unordered_map<std::string, uint32_t>& nameToIdx = m_NameToIndex;
std::function<void(aiNode*, int)> traverseNodes = [&](const aiNode* node, const int parentBoneIdx)
{
const std::string nodeName = node->mName.C_Str();
const auto it = nameToIdx.find(nodeName);
int currentBoneIdx = -1;
if (it != nameToIdx.end())
{
currentBoneIdx = (int)it->second;
BoneInfo& bone = m_Bones[currentBoneIdx];
bone.ParentIndex = parentBoneIdx;
// 存储默认局部变换(绑定姿势下相对于父节点的变换)
bone.LocalBindPose = Mat4FromAssimpMat4(node->mTransformation);
}
for (uint32_t i = 0; i < node->mNumChildren; i++)
{
traverseNodes(node->mChildren[i], currentBoneIdx);
}
};
traverseNodes(scene->mRootNode, -1);
}
uint32_t Skeleton::GetBoneIndex(const std::string& name) const
{
const auto it = m_NameToIndex.find(name);
return (it != m_NameToIndex.end()) ? it->second : static_cast<uint32_t>(-1);
}
}

View File

@ -0,0 +1,35 @@
//
// Created by Atdunbg on 2026/3/9.
//
#ifndef PRISM_SKELETON_H
#define PRISM_SKELETON_H
#include "glm/glm.hpp"
#include "Prism/Asset/Asset.h"
struct aiScene;
namespace Prism
{
struct BoneInfo
{
std::string Name;
int ParentIndex; // -1 is Root
glm::mat4 LocalBindPose;
glm::mat4 InverseTransform; // aiScene::mOffsetMatrix
};
class PRISM_API Skeleton : public Asset
{
public:
Skeleton(const aiScene* scene);
uint32_t GetBoneIndex(const std::string& name) const;
public:
std::vector<BoneInfo> m_Bones;
std::unordered_map<std::string, uint32_t> m_NameToIndex;
};
}
#endif //PRISM_SKELETON_H

View File

@ -23,6 +23,7 @@ namespace Prism
s_Types["scene"] = AssetType::Scene;
s_Types["pmx"] = AssetType::Mesh;
s_Types["fbx"] = AssetType::Mesh;
s_Types["dae"] = AssetType::Mesh;
s_Types["obj"] = AssetType::Mesh;
s_Types["png"] = AssetType::Texture;
s_Types["tga"] = AssetType::Texture;

View File

@ -50,10 +50,10 @@ namespace Prism
if (Input::IsMouseButtonPressed(MouseButton::Right) && !altPressed)
{
Input::SetCursorMode(CursorMode::Disable);
if (!m_IsRightButtonDownState)
{
Input::SetCursorMode(CursorMode::Disable);
m_InitialMousePosition = { Input::GetMouseX(), Input::GetMouseY() };
m_IsRightButtonDownState = true;
m_FreeLookActive = true;
@ -183,6 +183,7 @@ namespace Prism
UI::Property("focus", m_FocalPoint);
UI::Property("position", m_Position);
UI::Separator();
UI::Property("Max Speed", m_MaxSpeed);
UI::Property("Current Speed", m_Velocity);
UI::EndPropertyGrid();
ImGui::End();
@ -198,10 +199,20 @@ namespace Prism
m_ViewMatrix = glm::inverse(m_ViewMatrix);
}
bool EditorCamera::OnMouseScroll(MouseScrolledEvent& e)
bool EditorCamera::OnMouseScroll(const MouseScrolledEvent& e)
{
const float delta = e.GetOffsetY() * 0.1f;
MouseZoom(delta);
const float delta = e.GetOffsetY();
if (m_IsRightButtonDownState)
{
const float factor = m_MaxSpeed * 0.1f;
m_MaxSpeed += delta * factor;
m_MaxSpeed = std::clamp(m_MaxSpeed, 0.1f, 50.0f);
}else
{
MouseZoom(delta * 0.1f);
}
return false;
}

View File

@ -52,7 +52,7 @@ namespace Prism
private:
void UpdateCameraView();
bool OnMouseScroll(MouseScrolledEvent& e);
bool OnMouseScroll(const MouseScrolledEvent& e);
void MousePan(const glm::vec2& delta);
void MouseRotate(const glm::vec2& delta);
void MouseZoom(float delta);

View File

@ -139,6 +139,11 @@ namespace Prism
m_SelectionContext = entity;
}
Entity SceneHierarchyPanel::GetSelected() const
{
return m_SelectionContext;
}
template<class T>
void SceneHierarchyPanel::AddComponentPopup(const char* componentName)
{
@ -311,27 +316,6 @@ namespace Prism
}
}
ImGui::End();
#if TODO
ImGui::Begin("Mesh Debug");
if (ImGui::CollapsingHeader(mesh->m_FilePath.c_str()))
{
if (mesh->m_IsAnimated)
{
if (ImGui::CollapsingHeader("Animation"))
{
if (ImGui::Button(mesh->m_AnimationPlaying ? "Pause" : "Play"))
mesh->m_AnimationPlaying = !mesh->m_AnimationPlaying;
ImGui::SliderFloat("##AnimationTime", &mesh->m_AnimationTime, 0.0f, (float)mesh->m_Scene->mAnimations[0]->mDuration);
ImGui::DragFloat("Time Scale", &mesh->m_TimeMultiplier, 0.05f, 0.0f, 10.0f);
}
}
}
ImGui::End();
#endif
}
void SceneHierarchyPanel::DrawEntityNode(Entity entity)
@ -582,10 +566,43 @@ namespace Prism
ImGui::SeparatorText("3D Component");
AddComponentPopup<MeshComponent>("Mesh");
AddComponentPopup<AnimationComponent>("Animation", [&](AnimationComponent& component)
{
if (m_SelectionContext.HasComponent<MeshComponent>())
{
const auto meshComponent = m_SelectionContext.GetComponent<MeshComponent>();
if (meshComponent.Mesh->IsAnimated())
{
component.AnimationController = meshComponent.Mesh->GetAnimatorController();
component.SkeletonAsset = meshComponent.Mesh->GetSkeleton();
}
}
});
AddComponentPopup<RigidBodyComponent>("RigidBody");
AddComponentPopup<BoxColliderComponent>("BoxCollider");
AddComponentPopup<SphereColliderComponent>("SphereCollider");
AddComponentPopup<CapsuleColliderComponent>("CapsuleCollider");
AddComponentPopup<BoxColliderComponent>("BoxCollider", [&](BoxColliderComponent& component)
{
if (m_SelectionContext.HasComponent<MeshComponent>())
{
component.DebugMesh = MeshFactory::CreateBox(component.Size);
}
});
AddComponentPopup<SphereColliderComponent>("SphereCollider", [&](SphereColliderComponent& component)
{
if (m_SelectionContext.HasComponent<MeshComponent>())
{
component.DebugMesh = MeshFactory::CreateSphere(component.Radius);
}
});
AddComponentPopup<CapsuleColliderComponent>("CapsuleCollider", [&](CapsuleColliderComponent& component)
{
if (m_SelectionContext.HasComponent<MeshComponent>())
{
component.DebugMesh = MeshFactory::CreateCapsule(component.Radius, component.Radius);
}
});
AddComponentPopup<MeshColliderComponent>("MeshCollider", [&](MeshColliderComponent& component)
{
if (m_SelectionContext.HasComponent<MeshComponent>())
@ -636,9 +653,67 @@ namespace Prism
UI::BeginPropertyGrid();
UI::PropertyAssetReference("Mesh", meshComponent.Mesh, AssetType::Mesh);
UI::Property("AnimationPlaying", meshComponent.Mesh->m_AnimationPlaying);
UI::Property("TimeMultiple", meshComponent.Mesh->m_TimeMultiplier);
UI::Property("AnimationTime", meshComponent.Mesh->m_AnimationTime);
UI::Property("WorldTime", meshComponent.Mesh->m_WorldTime);
UI::EndPropertyGrid();
});
DrawComponent<AnimationComponent>("AnimatorController", entity, [this](AnimationComponent& animatorComponent)
{
// UI::BeginPropertyGrid();
// UI::PropertyAssetReference("Animation", animatorComponent.AnimationController, AssetType::Other);
// UI::PropertyAssetReference("", animatorComponent.SkeletonAsset, AssetType::Other);
// UI::EndPropertyGrid();
if (animatorComponent.AnimationController)
{
UI::BeginPropertyGrid();
UI::Property("Current Time", animatorComponent.AnimationController->GetCurrentTime());
UI::Property("Multiplier Time", animatorComponent.AnimationController->GetMultiplierTime());
UI::Property("Loop", animatorComponent.AnimationController->GetLoop());
UI::EndPropertyGrid();
const AnimationController::AnimationState animationState = animatorComponent.AnimationController->GetAnimationState();
if (ImGui::Button("Play"))
{
if (animationState != AnimationController::PLAY)
animatorComponent.AnimationController->Play();
}
ImGui::SameLine();
if (ImGui::Button("Pause"))
{
if (animationState != AnimationController::PAUSE)
animatorComponent.AnimationController->Pause();
}
ImGui::SameLine();
if (ImGui::Button("Stop"))
{
if (animationState != AnimationController::STOP)
animatorComponent.AnimationController->Stop();
}
}
else
{
ImGui::Text("Load Animation: Not implement");
if (ImGui::Button("Try get from exist Mesh"))
{
if (const auto meshComponent = m_SelectionContext.TryGetComponent<MeshComponent>())
{
if (meshComponent->Mesh->IsAnimated())
{
animatorComponent.AnimationController = meshComponent->Mesh->GetAnimatorController();
animatorComponent.SkeletonAsset = meshComponent->Mesh->GetSkeleton();
}
}
}
}
});
DrawComponent<CameraComponent>("Camera", entity, [](CameraComponent& cameraComponent) {
// Projection Type
const char* projTypeStrings[] = { "Perspective", "Orthographic" };

View File

@ -18,6 +18,7 @@ namespace Prism
void SetContext(const Ref<Scene>& scene);
void SetSelected(Entity entity);
Entity GetSelected() const;
void SetSelectionChangedCallback(const std::function<void(Entity)>& func) { m_SelectionChangedCallback = func; }
void SetEntityDeletedCallback(const std::function<void(Entity)>& func) { m_EntityDeletedCallback = func; }

View File

@ -6,6 +6,8 @@
#define CAMERA_H
#include <glm/glm.hpp>
#include "Prism/Core/Ref.h"
#include "Prism/Core/TimeStep.h"
namespace Prism

View File

@ -10,7 +10,6 @@
#include "assimp/LogStream.hpp"
#include "assimp/postprocess.h"
#include "assimp/scene.h"
#include "glad/glad.h"
#define GLM_ENABLE_EXPERIMENTAL
#include <filesystem>
@ -144,6 +143,23 @@ namespace Prism
// Vertices
if (m_IsAnimated)
{
// 1. 创建 Skeleton
m_Skeleton = Ref<Skeleton>::Create(scene);
// ---------- 2. 如果有动画,创建 AnimationClip ----------
if (scene->mNumAnimations > 0)
{
Ref<AnimationClip> clip = Ref<AnimationClip>::Create(scene);
// ---------- 3. 创建 AnimatorController ----------
m_AnimatorController = Ref<AnimationController>::Create();
m_AnimatorController->SetSkeleton(m_Skeleton);
m_AnimatorController->SetAnimationClip(clip);
m_AnimatorController->SetGlobalInverseTransform(m_InverseTransform); // 根节点逆矩阵
}
for (size_t i = 0; i < mesh->mNumVertices; i++)
{
AnimatedVertex vertex;
@ -169,7 +185,7 @@ namespace Prism
for (size_t i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
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 };
@ -211,41 +227,31 @@ namespace Prism
// Bones
if (m_IsAnimated)
{
for (size_t m = 0; m < scene->mNumMeshes; m++)
{
aiMesh* mesh = scene->mMeshes[m];
Submesh& submesh = m_Submeshes[m];
for (size_t m = 0; m < scene->mNumMeshes; m++)
{
aiMesh* mesh = scene->mMeshes[m];
Submesh& submesh = m_Submeshes[m];
for (size_t i = 0; i < mesh->mNumBones; i++)
{
aiBone* bone = mesh->mBones[i];
std::string boneName = bone->mName.C_Str();
for (size_t i = 0; i < mesh->mNumBones; i++)
{
aiBone* bone = mesh->mBones[i];
std::string boneName(bone->mName.data);
uint32_t boneIndex = 0;
// 从 Skeleton 获取骨骼索引
uint32_t boneIndex = m_Skeleton->GetBoneIndex(boneName);
if (boneIndex == uint32_t(-1))
{
PM_CORE_ERROR("Bone '{}' not found in skeleton!", boneName);
continue;
}
if (m_BoneMapping.find(boneName) == m_BoneMapping.end())
{
// Allocate an index for a new bone
boneIndex = m_BoneCount;
m_BoneCount++;
BoneInfo bi;
m_BoneInfo.push_back(bi);
m_BoneInfo[boneIndex].BoneOffset = Mat4FromAssimpMat4(bone->mOffsetMatrix);
m_BoneMapping[boneName] = boneIndex;
}
else
{
PM_CORE_TRACE("Found existing bone in map");
boneIndex = m_BoneMapping[boneName];
}
for (size_t j = 0; j < bone->mNumWeights; j++)
{
uint32_t VertexID = submesh.BaseVertex + bone->mWeights[j].mVertexId;
float Weight = bone->mWeights[j].mWeight;
m_AnimatedVertices[VertexID].AddBoneData(boneIndex, Weight);
}
}
}
for (size_t j = 0; j < bone->mNumWeights; j++)
{
uint32_t VertexID = submesh.BaseVertex + bone->mWeights[j].mVertexId;
float Weight = bone->mWeights[j].mWeight;
m_AnimatedVertices[VertexID].AddBoneData(boneIndex, Weight);
}
}
}
}
// Material
@ -541,6 +547,11 @@ namespace Prism
void Mesh::OnUpdate(TimeStep deltaTime)
{
if (m_AnimatorController)
{
m_AnimatorController->Update(deltaTime);
}
/*
if (m_IsAnimated)
{
if (m_AnimationPlaying)
@ -555,6 +566,7 @@ namespace Prism
// TODO: We only need to recalc bones if rendering has been requested at the current animation frame
BoneTransform(m_AnimationTime);
}
*/
}
@ -594,6 +606,7 @@ namespace Prism
PM_MESH_LOG("------------------------------------------------------");
}
/*
void Mesh::BoneTransform(float time)
{
ReadNodeHierarchy(time, m_Scene->mRootNode, glm::mat4(1.0f));
@ -642,6 +655,7 @@ namespace Prism
result += "--";
return result;
}
*/
void Mesh::TraverseNodes(const aiNode* node, const glm::mat4& parentTransform, uint32_t level)
{
@ -662,6 +676,7 @@ namespace Prism
}
}
/*
const aiNodeAnim* Mesh::FindNodeAnim(const aiAnimation* animation, const std::string& nodeName)
{
for (uint32_t i = 0; i < animation->mNumChannels; i++)
@ -779,4 +794,5 @@ namespace Prism
auto aiVec = start + factor * delta;
return { aiVec.x, aiVec.y, aiVec.z };
}
*/
}

View File

@ -14,6 +14,8 @@
#include "Prism/Core/TimeStep.h"
#include "Prism/Core/Math/AABB.h"
#include "../Asset/Asset.h"
#include "Prism/Animation/AnimatorController.h"
#include "Prism/Animation/Skeleton.h"
struct aiNode;
struct aiAnimation;
@ -58,12 +60,12 @@ namespace Prism
};
static_assert(sizeof(Index) == 3 * sizeof(uint32_t));
struct BoneInfo
struct MeshBoneInfo
{
glm::mat4 BoneOffset;
glm::mat4 FinalTransformation;
BoneInfo() : BoneOffset(glm::mat4(1.0f)), FinalTransformation(glm::mat4(1.0f)) {}
MeshBoneInfo() : BoneOffset(glm::mat4(1.0f)), FinalTransformation(glm::mat4(1.0f)) {}
};
struct VertexBoneData
@ -107,11 +109,9 @@ namespace Prism
class PRISM_API Mesh : public Asset
{
public:
Mesh(const std::string& filename);
Mesh(const std::vector<Vertex>& vertices, const std::vector<Index>& indices, const glm::mat4& transform);
~Mesh();
~Mesh() override;
void OnUpdate(TimeStep deltaTime);
void DumpVertexBuffer();
@ -131,31 +131,26 @@ namespace Prism
bool IsAnimated() const { return m_IsAnimated; }
std::vector<Triangle> GetTriangleCache(const uint32_t index) const { return m_TriangleCache.at(index); }
std::vector<Triangle> GetTriangleCache(const uint32_t index) const { return m_TriangleCache.at(index); }
Ref<Skeleton> GetSkeleton() const { return m_Skeleton; }
Ref<AnimationController> GetAnimatorController() const { return m_AnimatorController; }
std::vector<glm::mat4> m_EmptyTransforms{};
const std::vector<glm::mat4>& GetBoneTransforms() const
{
return m_AnimatorController ? m_AnimatorController->GetFinalBoneTransforms() : m_EmptyTransforms;
}
private:
void BoneTransform(float time);
void ReadNodeHierarchy(float AnimationTime, const aiNode* pNode, const glm::mat4& ParentTransform);
void TraverseNodes(const aiNode* node, const glm::mat4& parentTransform = glm::mat4(1.0f), uint32_t level = 0);
const aiNodeAnim* FindNodeAnim(const aiAnimation* animation, const std::string& nodeName);
uint32_t FindPosition(float AnimationTime, const aiNodeAnim* pNodeAnim);
uint32_t FindRotation(float AnimationTime, const aiNodeAnim* pNodeAnim);
uint32_t FindScaling(float AnimationTime, const aiNodeAnim* pNodeAnim);
glm::vec3 InterpolateTranslation(float animationTime, const aiNodeAnim* nodeAnim);
glm::quat InterpolateRotation(float animationTime, const aiNodeAnim* nodeAnim);
glm::vec3 InterpolateScale(float animationTime, const aiNodeAnim* nodeAnim);
private:
std::vector<Submesh> m_Submeshes;
std::unique_ptr<Assimp::Importer> m_Importer;
const aiScene* m_Scene;
glm::mat4 m_InverseTransform;
uint32_t m_BoneCount = 0;
std::vector<BoneInfo> m_BoneInfo;
// Ref<VertexArray> m_VertexArray;
Ref<Pipeline> m_Pipeline;
Ref<VertexBuffer> m_VertexBuffer;
Ref<IndexBuffer> m_IndexBuffer;
@ -164,9 +159,11 @@ namespace Prism
std::vector<Vertex> m_StaticVertices;
std::vector<AnimatedVertex> m_AnimatedVertices;
std::vector<Index> m_Indices;
std::unordered_map<std::string, uint32_t> m_BoneMapping;
std::vector<glm::mat4> m_BoneTransforms;
const aiScene* m_Scene;
std::vector<Submesh> m_Submeshes;
Ref<Skeleton> m_Skeleton;
Ref<AnimationController> m_AnimatorController;
// Material
Ref<Shader> m_MeshShader;

View File

@ -5,6 +5,7 @@
#include "Renderer.h"
#include "Renderer2D.h"
#include "Renderer3D.h"
#include "RendererAPI.h"
#include "SceneRenderer.h"
#include "glad/glad.h"
@ -35,6 +36,7 @@ namespace Prism
GetShaderLibrary()->Load("assets/shaders/PBRShader_Static.glsl");
GetShaderLibrary()->Load("assets/shaders/PBRShader_Anim.glsl");
// this to Init 2D and 3D Renderer
SceneRenderer::Init();
// FullScreen Quad
@ -58,8 +60,6 @@ namespace Prism
s_Data.m_FullscreenQuadVertexBuffer = VertexBuffer::Create(fullScreenQuadVertex, sizeof(fullScreenQuadVertex[0]) * sizeof(fullScreenQuadVertex));
s_Data.m_FullscreenQuadIndexBuffer = IndexBuffer::Create(fullScreenQuadIndices, sizeof(fullScreenQuadIndices[0]) * sizeof(fullScreenQuadIndices));
Renderer2D::Init();
}
void Renderer::Clear()
@ -192,10 +192,11 @@ namespace Prism
if (mesh->m_IsAnimated)
{
for (size_t i = 0; i < mesh->m_BoneTransforms.size(); i++)
const auto& boneTransform = mesh->GetBoneTransforms();
for (size_t i = 0; i < boneTransform.size(); i++)
{
std::string uniformName = std::string("u_BoneTransforms[") + std::to_string(i) + std::string("]");
mesh->m_MeshShader->SetMat4(uniformName, mesh->m_BoneTransforms[i]);
shader->SetMat4(uniformName, boneTransform[i]);
}
}
shader->SetMat4("u_Transform", transform * submesh.Transform);
@ -227,10 +228,11 @@ namespace Prism
{
if (mesh->m_IsAnimated)
{
for (size_t i = 0; i < mesh->m_BoneTransforms.size(); i++)
const auto& boneTransform = mesh->GetBoneTransforms();
for (size_t i = 0; i < boneTransform.size(); i++)
{
std::string uniformName = std::string("u_BoneTransforms[") + std::to_string(i) + std::string("]");
shader->SetMat4(uniformName, mesh->m_BoneTransforms[i]);
shader->SetMat4(uniformName, boneTransform[i]);
}
}
shader->SetMat4("u_Transform", transform * submesh.Transform);

View File

@ -186,14 +186,11 @@ namespace Prism
{
}
void Renderer2D::BeginScene(const glm::mat4& viewProj, bool depthTest)
void Renderer2D::BeginScene(const glm::mat4& viewProj, const 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;
@ -206,8 +203,10 @@ namespace Prism
s_Data.TextureSlotIndex = 1;
}
void Renderer2D::EndScene()
void Renderer2D::EndScene(const Ref<RenderPass>& renderPass)
{
if (renderPass) Renderer::BeginRenderPass(renderPass, false);
uint32_t dataSize = (uint32_t)((uint8_t*)s_Data.QuadVertexBufferPtr - (uint8_t*)s_Data.QuadVertexBufferBase);
if (dataSize)
{
@ -257,6 +256,7 @@ namespace Prism
s_Data.Stats.DrawCalls++;
}
if (renderPass) Renderer::EndRenderPass();
#if OLD
Flush();
#endif
@ -614,6 +614,12 @@ namespace Prism
s_Data.QuadIndexCount = 0;
s_Data.QuadVertexBufferPtr = s_Data.QuadVertexBufferBase;
s_Data.CircleIndexCount = 0;
s_Data.CircleVertexBufferPtr = s_Data.CircleVertexBufferBase;
s_Data.LineIndexCount = 0;
s_Data.LineVertexBufferPtr = s_Data.LineVertexBufferBase;
s_Data.TextureSlotIndex = 1;
}

View File

@ -7,6 +7,7 @@
#include <glm/glm.hpp>
#include "RenderPass.h"
#include "Texture.h"
namespace Prism
@ -18,7 +19,7 @@ namespace Prism
static void Shutdown();
static void BeginScene(const glm::mat4& viewProj, bool depthTest = true);
static void EndScene();
static void EndScene(const Ref<RenderPass>& renderPass = nullptr);
static void Flush();
// Primitives

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
//
// Created by Atdunbg on 2026/3/10.
//
#ifndef PRISM_RENDERER3D_H
#define PRISM_RENDERER3D_H
#include "Texture.h"
#include "glm/glm.hpp"
#include "Prism/Core/Ref.h"
namespace Prism
{
class Shader;
class RenderPass;
struct SceneRendererOptions;
struct MeshColliderComponent;
struct CapsuleColliderComponent;
struct BoxColliderComponent;
struct SphereColliderComponent;
class MaterialInstance;
class Mesh;
struct SceneRendererCamera;
class Scene;
class PRISM_API Renderer3D
{
public:
static void Init();
static void SetViewportSize(uint32_t width, uint32_t height);
static void BeginScene(const Scene* scene, const SceneRendererCamera& camera);
static void EndScene(Ref<RenderPass>& renderPass);
static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const Ref<MaterialInstance>& overrideMaterial = nullptr);
static void SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f));
static void SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
static void SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
static void SubmitColliderMesh(const CapsuleColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
static void SubmitColliderMesh(const MeshColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
static std::pair<Ref<TextureCube>, Ref<TextureCube>> CreateEnvironmentMap(const std::string& filepath);
// static Ref<RenderPass> GetFinalRenderPass();
static Ref<RenderPass> GetGeoPass();
static Ref<Texture2D> GetFinalColorBuffer();
static void SetFocusPoint(const glm::vec2& point);
// TODO: Temp
// static uint32_t GetFinalColorBufferRendererID();
static SceneRendererOptions& GetOptions();
private:
static void FlushDrawList(Ref<RenderPass>& outRenderPass);
static void AutoExposurePass();
static void GeometryPass();
// static void CompositePass();
// static void BloomBlurPass();
static void ShadowMapPass();
};
}
#endif //PRISM_RENDERER3D_H

File diff suppressed because it is too large Load Diff

View File

@ -35,9 +35,44 @@ namespace Prism
static void SetViewportSize(uint32_t width, uint32_t height);
static void BeginScene(const Scene* scene, const SceneRendererCamera& camera);
static void BeginScene(const Scene* scene, const SceneRendererCamera& camera, bool enable2DDepthTest = true);
static void EndScene();
// Renderer2D
static void SubmitQuad(const glm::mat4& transform, const glm::vec4& color);
static void SubmitQuad(const glm::mat4& transform, const Ref<Texture2D>& texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f));
/**
* draw a Billboard's texture
* @param position entity position
* @param texture entity texture
* @param cameraPos editcamera or camera postion
* @param upDirection default (0.0f, 1.0f, 0.0f)
* @param tilingFactor default 0
* @param tintColor default (1.0f, 1.0f, 1.0f)
*/
static void SubmitBillBoardQuad(const glm::vec3& position, const Ref<Texture2D>& texture, const glm::vec3& cameraPos, const glm::vec3& upDirection = glm::vec3(0.0f, 1.0f, 0.0f), float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f));
static void SubmitQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color);
static void SubmitQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color);
static void SubmitQuad(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 SubmitQuad(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 SubmitRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const glm::vec4& color);
static void SubmitRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const glm::vec4& color);
static void SubmitRotatedQuad(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 SubmitRotatedQuad(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 SubmitRotatedRect(const glm::vec2& position, const glm::vec2& size, float rotation, const glm::vec4& color);
static void SubmitRotatedRect(const glm::vec3& position, const glm::vec2& size, float rotation, const glm::vec4& color);
static void SubmitCircle(const glm::vec2& position, float radius, const glm::vec4& color, float thickness = 0.05f);
static void SubmitCircle(const glm::vec3& position, float radius, const glm::vec4& color, float thickness = 0.05f);
static void SubmitLine(const glm::vec3& p0, const glm::vec3& p1, const glm::vec4& color = glm::vec4(1.0f));
// Renderer3D
static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const Ref<MaterialInstance>& overrideMaterial = nullptr);
static void SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f));
@ -49,24 +84,16 @@ namespace Prism
static std::pair<Ref<TextureCube>, Ref<TextureCube>> CreateEnvironmentMap(const std::string& filepath);
static Ref<RenderPass> GetFinalRenderPass();
static Ref<RenderPass> GetGeoPass();
static Ref<Texture2D> GetFinalColorBuffer();
static void SetFocusPoint(const glm::vec2& point);
// TODO: Temp
static uint32_t GetFinalColorBufferRendererID();
static SceneRendererOptions& GetOptions();
static void OnImGuiRender();
private:
static void FlushDrawList();
static void AutoExposurePass();
static void GeometryPass();
static void CompositePass();
static void BloomBlurPass();
static void ShadowMapPass();
};
}

View File

@ -19,6 +19,7 @@
#include <glm/gtx/quaternion.hpp>
#include <utility>
#include "Prism/Animation/Skeleton.h"
#include "Prism/Core/Math/Math.h"
#include "Prism/Renderer/SceneEnvironment.h"
@ -99,6 +100,16 @@ namespace Prism
operator Ref<Prism::Mesh> () { return Mesh; }
};
struct AnimationComponent
{
Ref<Skeleton> SkeletonAsset;
Ref<AnimationController> AnimationController;
AnimationComponent() = default;
AnimationComponent(const AnimationComponent&) = default;
};
struct ScriptComponent
{

View File

@ -36,6 +36,20 @@ namespace Prism
return m_Scene->m_Registry.get<T>(m_EntityHandle);
}
template<typename T>
T& GetComponent() const
{
PM_CORE_ASSERT(HasComponent<T>(), "Entity doesn't have component!");
return m_Scene->m_Registry.get<T>(m_EntityHandle);
}
template<typename T>
const T* TryGetComponent() const
{
return m_Scene->m_Registry.try_get<T>(m_EntityHandle);
}
template<typename T>
bool HasComponent() const
{
@ -77,6 +91,7 @@ namespace Prism
UUID GetUUID() { return GetComponent<IDComponent>().ID; }
UUID GetUUID() const { return GetComponent<IDComponent>().ID; }
UUID GetSceneUUID() const { return m_Scene->GetUUID(); }
private:

View File

@ -23,7 +23,6 @@
#include "Prism/Core/Input.h"
#include "Prism/Core/Math/Math.h"
#include "Prism/Renderer/Renderer.h"
#include "Prism/Renderer/Renderer2D.h"
namespace Prism
{
@ -233,18 +232,21 @@ namespace Prism
void Scene::OnRenderRuntime(const TimeStep ts)
{
/////////////////////////////////////////////////////////////////////
// RENDER 3D SCENE //
/////////////////////////////////////////////////////////////////////
Entity cameraEntity = GetMainCameraEntity();
if (!cameraEntity)
return;
const glm::mat4 cameraViewMatrix = glm::inverse(GetTransformRelativeToParent(cameraEntity));
const glm::mat4 cameraViewMatrix = glm::inverse(GetTransformRelativeToParent(cameraEntity));
PM_CORE_ASSERT(cameraEntity, "Scene does not contain any cameras!");
SceneCamera& camera = cameraEntity.GetComponent<CameraComponent>();
camera.SetViewportSize(m_ViewportWidth, m_ViewportHeight);
/////////////////////////////////////////////////////////////////////
// RENDER 3D SCENE //
/////////////////////////////////////////////////////////////////////
// Process lights
{
m_LightEnvironment = LightEnvironment();
@ -281,49 +283,45 @@ namespace Prism
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
SceneRenderer::BeginScene(this, { static_cast<Camera>(camera), cameraViewMatrix });
for (auto entity : group)
{
const auto& [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
if (meshComponent.Mesh)
const auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
for (const auto entity : group)
{
meshComponent.Mesh->OnUpdate(ts);
const auto& [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
if (meshComponent.Mesh)
{
meshComponent.Mesh->OnUpdate(ts);
glm::mat4 transform = GetTransformRelativeToParent(Entity(entity, this));
glm::mat4 transform = GetTransformRelativeToParent(Entity(entity, this));
// TODO: Should we render (logically)
SceneRenderer::SubmitMesh(meshComponent, transform);
// TODO: Should we render (logically)
SceneRenderer::SubmitMesh(meshComponent, transform);
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// RENDER 2D SCENE //
/////////////////////////////////////////////////////////////////////
// render sprite
{
const auto entitiesGroup = m_Registry.group<TransformComponent>(entt::get<SpriteRendererComponent>);
for (const auto entity : entitiesGroup)
{
auto [transformComponent, spriteRendererComponent] = entitiesGroup.get<TransformComponent, SpriteRendererComponent>(entity);
if (spriteRendererComponent.Texture)
SceneRenderer::SubmitQuad(transformComponent.GetTransform(), spriteRendererComponent.Texture, spriteRendererComponent.TilingFactor, spriteRendererComponent.Color);
else
SceneRenderer::SubmitQuad(transformComponent.GetTransform(), spriteRendererComponent.Color);
}
}
/////////////////////////////////////////////////////////////////////
}
SceneRenderer::EndScene();
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// RENDER 2D SCENE //
/////////////////////////////////////////////////////////////////////
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
const glm::mat4 cameraViewProjection = cameraViewMatrix * camera.GetProjectionMatrix();
Renderer2D::BeginScene(cameraViewProjection, false);
// render sprite
{
const auto entitiesGroup = m_Registry.group<TransformComponent>(entt::get<SpriteRendererComponent>);
for (const auto entity : entitiesGroup)
{
auto [transformComponent, spriteRendererComponent] = entitiesGroup.get<TransformComponent, SpriteRendererComponent>(entity);
if (spriteRendererComponent.Texture)
Renderer2D::DrawQuad(transformComponent.GetTransform(), spriteRendererComponent.Texture, spriteRendererComponent.TilingFactor, spriteRendererComponent.Color);
else
Renderer2D::DrawQuad(transformComponent.GetTransform(), spriteRendererComponent.Color);
}
}
Renderer2D::EndScene();
Renderer::EndRenderPass();
}
void Scene::OnRenderEditor(const TimeStep ts, const EditorCamera& editorCamera)
@ -335,12 +333,12 @@ namespace Prism
// Process lights
{
m_LightEnvironment = LightEnvironment();
auto lights = m_Registry.group<DirectionalLightComponent>(entt::get<TransformComponent>);
const auto lights = m_Registry.group<DirectionalLightComponent>(entt::get<TransformComponent>);
uint32_t directionalLightIndex = 0;
for (auto entity : lights)
for (const auto entity : lights)
{
auto [transformComponent, lightComponent] = lights.get<TransformComponent, DirectionalLightComponent>(entity);
glm::vec3 direction = -glm::normalize(glm::mat3(transformComponent.GetTransform()) * glm::vec3(1.0f));
const glm::vec3 direction = -glm::normalize(glm::mat3(transformComponent.GetTransform()) * glm::vec3(1.0f));
m_LightEnvironment.DirectionalLights[directionalLightIndex++] =
{
direction,
@ -353,148 +351,105 @@ namespace Prism
// TODO: only one sky light at the moment!
{
auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
if (!lights.empty())
{
for (auto entity : lights)
for (const auto entity : lights)
{
auto [transformComponent, skyLightComponent] = lights.get<TransformComponent, SkyLightComponent>(entity);
m_Environment = skyLightComponent.SceneEnvironment;
m_EnvironmentIntensity = skyLightComponent.Intensity;
SetSkybox(m_Environment->RadianceMap);
}
}else
{
// TODO:
}
}
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
SceneRenderer::BeginScene(this, { static_cast<Camera>(editorCamera), editorCamera.GetViewMatrix(), 0.1f, 1000.0f, 45.0f }); // TODO: real values
// TODO: this value should be storage and can modify
SceneRenderer::BeginScene(this, { static_cast<Camera>(editorCamera), editorCamera.GetViewMatrix(), 0.1f, 1000.0f, 45.0f});
{
for (const auto entity : group)
const auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
{
const auto& [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
if (meshComponent.Mesh)
for (const auto [entity, meshComponent, transformComponent]: group.each())
{
meshComponent.Mesh->OnUpdate(ts);
Entity e = {entity, this};
glm::mat4 transform = GetTransformRelativeToParent(Entity{ entity, this });
if (meshComponent.Mesh)
{
meshComponent.Mesh->OnUpdate(ts);
// TODO: Should we render (logically)
glm::mat4 transform = GetTransformRelativeToParent(e);
// TODO: Should we render (logically)
if (m_SelectedEntity == entity)
SceneRenderer::SubmitSelectedMesh(meshComponent, transform);
else
SceneRenderer::SubmitMesh(meshComponent, transform);
}
// Renderer Collider
if (m_SelectedEntity == entity)
SceneRenderer::SubmitSelectedMesh(meshComponent, transform);
{
glm::mat4 transform = GetTransformRelativeToParent(e);
if (const auto collider = e.TryGetComponent<BoxColliderComponent>())
SceneRenderer::SubmitColliderMesh(*collider, transform);
if (const auto collider = e.TryGetComponent<SphereColliderComponent>())
SceneRenderer::SubmitColliderMesh(*collider, transform);
if (const auto collider = e.TryGetComponent<CapsuleColliderComponent>())
SceneRenderer::SubmitColliderMesh(*collider, transform);
if (const auto collider = e.TryGetComponent<MeshColliderComponent>())
SceneRenderer::SubmitColliderMesh(*collider, transform);
}
}
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// RENDER 2D SCENE //
/////////////////////////////////////////////////////////////////////
// render sprite
{
const auto entitiesGroup = m_Registry.group<TransformComponent>(entt::get<SpriteRendererComponent>);
for (const auto entity : entitiesGroup)
{
auto [transformComponent, spriteRendererComponent] = entitiesGroup.get<TransformComponent, SpriteRendererComponent>(entity);
if (spriteRendererComponent.Texture)
SceneRenderer::SubmitQuad(transformComponent.GetTransform(), spriteRendererComponent.Texture, spriteRendererComponent.TilingFactor, spriteRendererComponent.Color);
else
SceneRenderer::SubmitMesh(meshComponent, transform);
SceneRenderer::SubmitQuad(transformComponent.GetTransform(), spriteRendererComponent.Color);
}
}
// render camera icon
{
const auto view = m_Registry.view<BoxColliderComponent>();
for (const auto entity : view)
const auto cameras = m_Registry.view<CameraComponent>();
if (!cameras.empty())
{
Entity e = { entity, this };
auto& collider = e.GetComponent<BoxColliderComponent>();
glm::mat4 transform = GetTransformRelativeToParent(e);
for (auto& entity : cameras)
{
Entity e = { entity, this };
SceneRenderer::SubmitBillBoardQuad(e.Transform().Translation, m_CameraIcon, editorCamera.GetPosition(), editorCamera.GetUpDirection());
}
}
if (m_SelectedEntity == entity)
SceneRenderer::SubmitColliderMesh(collider, transform);
}
}
{
const auto view = m_Registry.view<SphereColliderComponent>();
for (const auto entity : view)
{
Entity e = { entity, this };
auto& collider = e.GetComponent<SphereColliderComponent>();
glm::mat4 transform = GetTransformRelativeToParent(e);
if (m_SelectedEntity == entity)
SceneRenderer::SubmitColliderMesh(collider, transform);
}
}
{
const auto view = m_Registry.view<CapsuleColliderComponent>();
for (const auto entity : view)
{
Entity e = { entity, this };
auto& collider = e.GetComponent<CapsuleColliderComponent>();
glm::mat4 transform = GetTransformRelativeToParent(e);
if (m_SelectedEntity == entity)
SceneRenderer::SubmitColliderMesh(collider, transform);
}
}
{
const auto view = m_Registry.view<MeshColliderComponent>();
for (const auto entity : view)
{
Entity e = { entity, this };
auto& collider = e.GetComponent<MeshColliderComponent>();
glm::mat4 transform = GetTransformRelativeToParent(e);
if (m_SelectedEntity == entity)
SceneRenderer::SubmitColliderMesh(collider, transform);
const auto lights = m_Registry.view<SkyLightComponent>();
if (!lights.empty())
{
for (auto& entity : lights)
{
Entity e = { entity, this };
SceneRenderer::SubmitBillBoardQuad(e.Transform().Translation, m_LightIcon, editorCamera.GetPosition(), editorCamera.GetUpDirection());
}
}
}
/////////////////////////////////////////////////////////////////////
}
SceneRenderer::EndScene();
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// RENDER 2D SCENE //
/////////////////////////////////////////////////////////////////////
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
const auto viewProj = editorCamera.GetViewProjection();
Renderer2D::BeginScene(viewProj, false);
// render sprite
{
const auto entitiesGroup = m_Registry.group<TransformComponent>(entt::get<SpriteRendererComponent>);
for (const auto entity : entitiesGroup)
{
auto [transformComponent, spriteRendererComponent] = entitiesGroup.get<TransformComponent, SpriteRendererComponent>(entity);
if (spriteRendererComponent.Texture)
Renderer2D::DrawQuad(transformComponent.GetTransform(), spriteRendererComponent.Texture, spriteRendererComponent.TilingFactor, spriteRendererComponent.Color);
else
Renderer2D::DrawQuad(transformComponent.GetTransform(), spriteRendererComponent.Color);
}
}
// render camera icon
{
const auto cameras = m_Registry.view<CameraComponent>();
if (!cameras.empty())
{
for (auto& entity : cameras)
{
Entity e = { entity, this };
Renderer2D::DrawBillBoardQuad(e.Transform().Translation, m_CameraIcon, editorCamera.GetPosition(), editorCamera.GetUpDirection());
}
}
const auto lights = m_Registry.view<SkyLightComponent>();
if (!lights.empty())
{
for (auto& entity : lights)
{
Entity e = { entity, this };
Renderer2D::DrawBillBoardQuad(e.Transform().Translation, m_LightIcon, editorCamera.GetPosition(), editorCamera.GetUpDirection());
}
}
}
Renderer2D::EndScene();
Renderer::EndRenderPass();
}
void Scene::OnEvent(Event& e)

View File

@ -105,7 +105,7 @@ namespace Prism
void SetPhysics2DGravity(float gravity);
// Editor-specific
void SetSelectedEntity(entt::entity entity) { m_SelectedEntity = entity; }
void SetSelectedEntity(const entt::entity entity) { m_SelectedEntity = entity; }
private:
UUID m_SceneID;
@ -143,6 +143,7 @@ namespace Prism
private:
friend class Entity;
friend class Renderer3D;
friend class SceneRenderer;
friend class SceneSerializer;
friend class SceneHierarchyPanel;