This commit is contained in:
tovjemam 2026-02-11 14:31:46 +01:00
parent 6396f94783
commit 374fdb1077
14 changed files with 146 additions and 26 deletions

View File

@ -75,6 +75,8 @@ set(CLIENT_ONLY_SOURCES
"src/gameview/client_session.cpp" "src/gameview/client_session.cpp"
"src/gameview/entityview.hpp" "src/gameview/entityview.hpp"
"src/gameview/entityview.cpp" "src/gameview/entityview.cpp"
"src/gameview/skinning_ubo.hpp"
"src/gameview/skinning_ubo.cpp"
"src/gameview/vehicleview.hpp" "src/gameview/vehicleview.hpp"
"src/gameview/vehicleview.cpp" "src/gameview/vehicleview.cpp"
"src/gameview/worldview.hpp" "src/gameview/worldview.hpp"

View File

@ -11,8 +11,8 @@ namespace assets
struct MeshVertexBoneInfluence struct MeshVertexBoneInfluence
{ {
int bone_index; int bone_index = -1;
float weight; float weight = 0.0f;
}; };
struct MeshVertex struct MeshVertex

View File

@ -27,7 +27,15 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
v.uv.y = 1.0f - v.uv.y; // FLIP FOR GL v.uv.y = 1.0f - v.uv.y; // FLIP FOR GL
// TODO: LUV & bone data if (model->skeleton_)
{
size_t num_bones = 0;
iss >> num_bones;
for (size_t i = 0; i < num_bones; ++i)
{
iss >> v.bones[i].bone_index >> v.bones[i].weight;
}
}
mb.AddVertex(v); mb.AddVertex(v);
) )
@ -48,6 +56,7 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
t.vert[0] = indices[0]; t.vert[0] = indices[0];
t.vert[1] = indices[1]; t.vert[1] = indices[1];
t.vert[2] = indices[2]; t.vert[2] = indices[2];
mb.AddTriangle(t); mb.AddTriangle(t);
) )
@ -97,7 +106,7 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
std::shared_ptr<const gfx::Texture> texture; std::shared_ptr<const gfx::Texture> texture;
if (!texture_name.empty()) if (!texture_name.empty())
{ {
texture = CacheManager::GetTexture("data/" + surface_name + ".png"); texture = CacheManager::GetTexture("data/" + texture_name + ".png");
} }
mb.BeginSurface(sflags, surface_name, texture); mb.BeginSurface(sflags, surface_name, texture);
@ -111,11 +120,19 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
{ {
temp_hull = std::make_unique<btConvexHullShape>(); temp_hull = std::make_unique<btConvexHullShape>();
} }
else if (command == "skeleton")
{
std::string skel_name;
iss >> skel_name;
model->skeleton_ = CacheManager::GetSkeleton("data/" + skel_name + ".sk");
CLIENT_ONLY(mb.SetMeshFlag(gfx::MF_SKELETAL));
}
else else
{ {
throw std::runtime_error("Unknown command in model file: " + command); throw std::runtime_error("Unknown command in model file: " + command);
} }
// TODO: skeleton // TODO: skeleton
}); });

View File

@ -3,8 +3,8 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include "skeleton.hpp"
#include "utils/defs.hpp" #include "utils/defs.hpp"
#include "collision/trianglemesh.hpp" #include "collision/trianglemesh.hpp"
#ifdef CLIENT #ifdef CLIENT
@ -43,6 +43,7 @@ public:
const collision::TriangleMesh* GetColMesh() const { return cmesh_.get(); } const collision::TriangleMesh* GetColMesh() const { return cmesh_.get(); }
btCollisionShape* GetColShape() const { return cshape_.get(); } btCollisionShape* GetColShape() const { return cshape_.get(); }
const std::shared_ptr<const Skeleton>& GetSkeleton() const { return skeleton_; }
CLIENT_ONLY(const std::shared_ptr<const Mesh>& GetMesh() const { return mesh_; }) CLIENT_ONLY(const std::shared_ptr<const Mesh>& GetMesh() const { return mesh_; })
private: private:
@ -50,6 +51,7 @@ private:
// std::vector<ModelCollisionShape> cshapes_; // std::vector<ModelCollisionShape> cshapes_;
std::unique_ptr<btCollisionShape> cshape_; std::unique_ptr<btCollisionShape> cshape_;
std::shared_ptr<const Skeleton> skeleton_;
CLIENT_ONLY(std::shared_ptr<const Mesh> mesh_;) CLIENT_ONLY(std::shared_ptr<const Mesh> mesh_;)
}; };

View File

@ -48,6 +48,7 @@ void game::Character::Update()
auto bt_trans = bt_ghost_.getWorldTransform(); auto bt_trans = bt_ghost_.getWorldTransform();
root_.local.SetBtTransform(bt_trans); root_.local.SetBtTransform(bt_trans);
root_.local.position.z -= shape_.height * 0.5f + shape_.radius - 0.05f; // foot pos
UpdateMovement(); UpdateMovement();
SendUpdateMsg(); SendUpdateMsg();

View File

@ -214,7 +214,6 @@ void game::OpenWorld::PlayerInput(Player& player, PlayerInputType type, bool ena
void game::OpenWorld::PlayerViewAnglesChanged(Player& player, float yaw, float pitch) void game::OpenWorld::PlayerViewAnglesChanged(Player& player, float yaw, float pitch)
{ {
auto character = player_characters_.at(&player); auto character = player_characters_.at(&player);
std::cout << "player aiming " << yaw << " " << pitch <<std::endl;
character->SetForwardYaw(yaw); character->SetForwardYaw(yaw);
} }

View File

@ -1,11 +1,14 @@
#include "characterview.hpp" #include "characterview.hpp"
#include "assets/cache.hpp" #include "assets/cache.hpp"
#include "assets/model.hpp"
#include "net/utils.hpp" #include "net/utils.hpp"
game::view::CharacterView::CharacterView(WorldView& world, net::InMessage& msg) : EntityView(world, msg) game::view::CharacterView::CharacterView(WorldView& world, net::InMessage& msg) : EntityView(world, msg), ubo_(sk_)
{ {
basemodel_ = assets::CacheManager::GetModel("data/human.mdl");
sk_ = SkeletonInstance(assets::CacheManager::GetSkeleton("data/human.sk"), &root_); sk_ = SkeletonInstance(basemodel_->GetSkeleton(), &root_);
ubo_.Update();
ubo_valid_ = true;
} }
bool game::view::CharacterView::ProcessMsg(net::EntMsgType type, net::InMessage& msg) bool game::view::CharacterView::ProcessMsg(net::EntMsgType type, net::InMessage& msg)
@ -26,6 +29,7 @@ void game::view::CharacterView::Update(const UpdateInfo& info)
sk_.ApplySkelAnim(*anim, info.time, 1.0f); sk_.ApplySkelAnim(*anim, info.time, 1.0f);
root_.UpdateMatrix(); root_.UpdateMatrix();
sk_.UpdateBoneMatrices(); sk_.UpdateBoneMatrices();
ubo_valid_ = false;
} }
void game::view::CharacterView::Draw(const DrawArgs& args) void game::view::CharacterView::Draw(const DrawArgs& args)
@ -40,17 +44,35 @@ void game::view::CharacterView::Draw(const DrawArgs& args)
end = start + glm::vec3(glm::cos(yaw_), glm::sin(yaw_), 0.0f) * 0.5f; end = start + glm::vec3(glm::cos(yaw_), glm::sin(yaw_), 0.0f) * 0.5f;
args.dlist.AddBeam(start, end, 0xFF007700, 0.05f); args.dlist.AddBeam(start, end, 0xFF007700, 0.05f);
// draw bones debug //// draw bones debug
const auto& bone_nodes = sk_.GetBoneNodes(); //const auto& bone_nodes = sk_.GetBoneNodes();
for (const auto& bone_node : bone_nodes) //for (const auto& bone_node : bone_nodes)
//{
// if (!bone_node.parent)
// continue;
// glm::vec3 p0 = bone_node.parent->matrix[3];
// glm::vec3 p1 = bone_node.matrix[3];
// args.dlist.AddBeam(p0, p1, 0xFF00EEEE, 0.01f);
//}
// draw human
if (!ubo_valid_)
{ {
if (!bone_node.parent) ubo_.Update();
continue; ubo_valid_ = true;
}
glm::vec3 p0 = bone_node.parent->matrix[3]; const auto& mesh = *basemodel_->GetMesh();
glm::vec3 p1 = bone_node.matrix[3]; for (const auto& surface : mesh.surfaces)
{
args.dlist.AddBeam(p0, p1, 0xFF00EEEE, 0.01f); gfx::DrawSurfaceCmd cmd;
cmd.surface = &surface;
cmd.matrices = &root_.matrix;
cmd.skinning = &ubo_;
args.dlist.AddSurface(cmd);
} }
} }
@ -61,6 +83,7 @@ bool game::view::CharacterView::ProcessUpdateMsg(net::InMessage& msg)
return false; return false;
net::DecodePosition(posq, root_.local.position); net::DecodePosition(posq, root_.local.position);
root_.local.rotation = glm::rotate(glm::quat(1.0f, 0.0f, 0.0f, 0.0f), yaw_ + glm::pi<float>() * 0.5f, glm::vec3(0, 0, 1));
return true; return true;
} }

View File

@ -1,7 +1,9 @@
#pragma once #pragma once
#include "entityview.hpp" #include "entityview.hpp"
#include "assets/model.hpp"
#include "game/skeletoninstance.hpp" #include "game/skeletoninstance.hpp"
#include "skinning_ubo.hpp"
namespace game::view namespace game::view
{ {
@ -24,7 +26,10 @@ private:
private: private:
float yaw_ = 0.0f; float yaw_ = 0.0f;
std::shared_ptr<const assets::Model> basemodel_;
SkeletonInstance sk_; SkeletonInstance sk_;
SkinningUBO ubo_;
bool ubo_valid_ = false;
}; };

View File

@ -0,0 +1,23 @@
#include "skinning_ubo.hpp"
#include "gfx/shader_defs.hpp"
game::view::SkinningUBO::SkinningUBO(const SkeletonInstance& sk) : sk_(sk)
{
}
void game::view::SkinningUBO::Update()
{
static glm::mat4 skin_mats[SD_MAX_BONES];
const auto& skeleton = sk_.GetSkeleton();
size_t num_mats = std::min(skeleton->GetNumBones(), static_cast<size_t>(SD_MAX_BONES));
for (size_t i = 0; i < num_mats; ++i)
{
const auto& bone = skeleton->GetBone(i);
const TransformNode& node = sk_.GetBoneNode(i);
skin_mats[i] = node.matrix * bone.inv_bind_matrix;
}
SetData(skin_mats, num_mats);
}

View File

@ -0,0 +1,22 @@
#pragma once
#include "gfx/uniform_buffer.hpp"
#include "game/skeletoninstance.hpp"
namespace game::view
{
class SkinningUBO : public gfx::UniformBuffer<glm::mat4>
{
public:
SkinningUBO(const SkeletonInstance& sk);
void Update();
private:
const SkeletonInstance& sk_;
};
}

View File

@ -5,6 +5,7 @@
#include "assets/skeleton.hpp" #include "assets/skeleton.hpp"
#include "hud.hpp" #include "hud.hpp"
#include "surface.hpp" #include "surface.hpp"
#include "uniform_buffer.hpp"
namespace gfx namespace gfx
{ {
@ -12,11 +13,12 @@ namespace gfx
struct DrawSurfaceCmd struct DrawSurfaceCmd
{ {
const Surface* surface = nullptr; const Surface* surface = nullptr;
const glm::mat4* matrices = nullptr; // model matrix, continues in array of matrices for skeletal meshes const glm::mat4* matrices = nullptr; // model matrix
const glm::vec4* color = nullptr; // optional tint const glm::vec4* color = nullptr; // optional tint
uint32_t first = 0; // first triangle index uint32_t first = 0; // first triangle index
uint32_t count = 0; // num triangles uint32_t count = 0; // num triangles
float dist = 0.0f; // distance to camera - for transparnt sorting float dist = 0.0f; // distance to camera - for transparnt sorting
const UniformBuffer<glm::mat4>* skinning = nullptr; // skinning matrices for skeletal meshes
}; };
struct DrawBeamCmd struct DrawBeamCmd

View File

@ -167,6 +167,7 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
// cache to eliminate fake state changes // cache to eliminate fake state changes
const gfx::Texture* last_texture = nullptr; const gfx::Texture* last_texture = nullptr;
const gfx::VertexArray* last_vao = nullptr; const gfx::VertexArray* last_vao = nullptr;
const gfx::UniformBuffer<glm::mat4>* last_skin = nullptr;
InvalidateShaders(); InvalidateShaders();
// enable depth test // enable depth test
@ -290,6 +291,13 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
last_texture = surface->texture.get(); last_texture = surface->texture.get();
} }
// bind skinning UBO
if (cmd.skinning && last_skin != cmd.skinning)
{
glBindBufferBase(GL_UNIFORM_BUFFER, 0, cmd.skinning->GetId());
last_skin = cmd.skinning;
}
// bind VAO // bind VAO
if (last_vao != surface->va.get()) if (last_vao != surface->va.get())
{ {

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#define SD_MAX_LIGHTS 4 #define SD_MAX_LIGHTS 4
#define SD_MAX_BONES 256 #define SD_MAX_BONES 128
#define SHF_CULL_ALPHA 1 #define SHF_CULL_ALPHA 1
#define SHF_BACKGROUND 2 #define SHF_BACKGROUND 2

View File

@ -141,6 +141,7 @@ SHADER_HEADER
R"GLSL( R"GLSL(
layout (location = 0) in vec3 a_pos; layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec3 a_normal; layout (location = 1) in vec3 a_normal;
layout (location = 2) in vec4 a_color;
layout (location = 3) in vec2 a_uv; layout (location = 3) in vec2 a_uv;
layout (location = 5) in ivec4 a_bone_ids; layout (location = 5) in ivec4 a_bone_ids;
layout (location = 6) in vec4 a_bone_weights; layout (location = 6) in vec4 a_bone_weights;
@ -156,7 +157,6 @@ COMPUTE_LIGHTS_GLSL
R"GLSL( R"GLSL(
out vec2 v_uv; out vec2 v_uv;
out vec3 v_color; out vec3 v_color;
void main() { void main() {
@ -168,13 +168,12 @@ void main() {
} }
} }
vec4 world_pos = u_model * bone_transform * vec4(a_pos, 1.0); vec4 world_pos = bone_transform * vec4(a_pos, 1.0);
vec3 world_normal = normalize(mat3(u_model) * mat3(bone_transform) * a_normal); vec3 world_normal = normalize(mat3(bone_transform) * a_normal);
gl_Position = u_view_proj * world_pos; gl_Position = u_view_proj * world_pos;
v_uv = a_uv; v_uv = a_uv;
v_color = ComputeLights(world_pos.xyz, world_normal) * a_color.rgb;
v_color = ComputeLights(world_pos.xyz, world_normal);
} }
)GLSL", )GLSL",
@ -182,16 +181,33 @@ void main() {
SHADER_HEADER SHADER_HEADER
R"GLSL( R"GLSL(
in vec2 v_uv; in vec2 v_uv;
in vec3 v_color; in vec3 v_color;
#define SHF_CULL_ALPHA 1
#define SHF_BACKGROUND 2
uniform sampler2D u_tex; uniform sampler2D u_tex;
uniform vec4 u_color;
uniform int u_flags;
layout (location = 0) out vec4 o_color; layout (location = 0) out vec4 o_color;
void main() { void main() {
o_color = vec4(texture(u_tex, v_uv)); o_color = vec4(texture(u_tex, v_uv));
if ((u_flags & SHF_CULL_ALPHA) > 0)
{
if (o_color.a < 0.5)
discard;
}
else if ((u_flags & SHF_BACKGROUND) > 0)
{
// blend with bg
o_color = mix(u_color, o_color, o_color.a);
}
o_color.rgb *= v_color; // Apply vertex color o_color.rgb *= v_color; // Apply vertex color
//o_color = vec4(1.0, 0.0, 0.0, 1.0);
} }
)GLSL", )GLSL",