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/entityview.hpp"
"src/gameview/entityview.cpp"
"src/gameview/skinning_ubo.hpp"
"src/gameview/skinning_ubo.cpp"
"src/gameview/vehicleview.hpp"
"src/gameview/vehicleview.cpp"
"src/gameview/worldview.hpp"

View File

@ -11,8 +11,8 @@ namespace assets
struct MeshVertexBoneInfluence
{
int bone_index;
float weight;
int bone_index = -1;
float weight = 0.0f;
};
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
// 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);
)
@ -48,6 +56,7 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
t.vert[0] = indices[0];
t.vert[1] = indices[1];
t.vert[2] = indices[2];
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;
if (!texture_name.empty())
{
texture = CacheManager::GetTexture("data/" + surface_name + ".png");
texture = CacheManager::GetTexture("data/" + texture_name + ".png");
}
mb.BeginSurface(sflags, surface_name, texture);
@ -111,10 +120,18 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
{
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
{
throw std::runtime_error("Unknown command in model file: " + command);
}
// TODO: skeleton
});

View File

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

View File

@ -48,6 +48,7 @@ void game::Character::Update()
auto bt_trans = bt_ghost_.getWorldTransform();
root_.local.SetBtTransform(bt_trans);
root_.local.position.z -= shape_.height * 0.5f + shape_.radius - 0.05f; // foot pos
UpdateMovement();
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)
{
auto character = player_characters_.at(&player);
std::cout << "player aiming " << yaw << " " << pitch <<std::endl;
character->SetForwardYaw(yaw);
}

View File

@ -1,11 +1,14 @@
#include "characterview.hpp"
#include "assets/cache.hpp"
#include "assets/model.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_)
{
sk_ = SkeletonInstance(assets::CacheManager::GetSkeleton("data/human.sk"), &root_);
basemodel_ = assets::CacheManager::GetModel("data/human.mdl");
sk_ = SkeletonInstance(basemodel_->GetSkeleton(), &root_);
ubo_.Update();
ubo_valid_ = true;
}
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);
root_.UpdateMatrix();
sk_.UpdateBoneMatrices();
ubo_valid_ = false;
}
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;
args.dlist.AddBeam(start, end, 0xFF007700, 0.05f);
// draw bones debug
const auto& bone_nodes = sk_.GetBoneNodes();
for (const auto& bone_node : bone_nodes)
//// draw bones debug
//const auto& bone_nodes = sk_.GetBoneNodes();
//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)
continue;
ubo_.Update();
ubo_valid_ = true;
}
glm::vec3 p0 = bone_node.parent->matrix[3];
glm::vec3 p1 = bone_node.matrix[3];
args.dlist.AddBeam(p0, p1, 0xFF00EEEE, 0.01f);
const auto& mesh = *basemodel_->GetMesh();
for (const auto& surface : mesh.surfaces)
{
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;
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;
}

View File

@ -1,7 +1,9 @@
#pragma once
#include "entityview.hpp"
#include "assets/model.hpp"
#include "game/skeletoninstance.hpp"
#include "skinning_ubo.hpp"
namespace game::view
{
@ -24,7 +26,10 @@ private:
private:
float yaw_ = 0.0f;
std::shared_ptr<const assets::Model> basemodel_;
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 "hud.hpp"
#include "surface.hpp"
#include "uniform_buffer.hpp"
namespace gfx
{
@ -12,11 +13,12 @@ namespace gfx
struct DrawSurfaceCmd
{
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
uint32_t first = 0; // first triangle index
uint32_t count = 0; // num triangles
float dist = 0.0f; // distance to camera - for transparnt sorting
const UniformBuffer<glm::mat4>* skinning = nullptr; // skinning matrices for skeletal meshes
};
struct DrawBeamCmd

View File

@ -167,6 +167,7 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
// cache to eliminate fake state changes
const gfx::Texture* last_texture = nullptr;
const gfx::VertexArray* last_vao = nullptr;
const gfx::UniformBuffer<glm::mat4>* last_skin = nullptr;
InvalidateShaders();
// enable depth test
@ -290,6 +291,13 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
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
if (last_vao != surface->va.get())
{

View File

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

View File

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