Skinning
This commit is contained in:
parent
6396f94783
commit
374fdb1077
@ -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"
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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,10 +120,18 @@ 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
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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_;)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
23
src/gameview/skinning_ubo.cpp
Normal file
23
src/gameview/skinning_ubo.cpp
Normal 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);
|
||||||
|
}
|
||||||
22
src/gameview/skinning_ubo.hpp
Normal file
22
src/gameview/skinning_ubo.hpp
Normal 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_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
|||||||
@ -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())
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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
|
||||||
@ -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",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user