Vehicle deform

This commit is contained in:
tovjemam 2026-03-06 22:32:45 +01:00
parent 8369181e9a
commit 3e284af672
21 changed files with 510 additions and 22 deletions

View File

@ -27,6 +27,8 @@ set(COMMON_SOURCES
"src/collision/trianglemesh.cpp"
"src/game/character_anim_state.hpp"
"src/game/character_anim_state.cpp"
"src/game/deform_grid.hpp"
"src/game/deform_grid.cpp"
"src/game/player_input.hpp"
"src/game/simple_entity_sync.hpp"
"src/game/skeletoninstance.hpp"
@ -90,6 +92,8 @@ set(CLIENT_ONLY_SOURCES
"src/gameview/worldview.cpp"
"src/gfx/buffer_object.cpp"
"src/gfx/buffer_object.hpp"
"src/gfx/deform_texture.hpp"
"src/gfx/deform_texture.cpp"
"src/gfx/draw_list.hpp"
"src/gfx/frustum.hpp"
"src/gfx/frustum.cpp"

View File

@ -21,12 +21,19 @@ enum ObjectFlag : ObjectFlags
OF_NOTIFY_CONTACT = 0x02,
};
struct ContactInfo
{
glm::vec3 pos;
glm::vec3 normal;
float impulse;
};
class ObjectCallback
{
public:
ObjectCallback() = default;
virtual void OnContact(float impulse) {}
virtual void OnContact(const ContactInfo& info) {}
virtual ~ObjectCallback() = default;
};

46
src/game/deform_grid.cpp Normal file
View File

@ -0,0 +1,46 @@
#include "deform_grid.hpp"
game::DeformGrid::DeformGrid(const gfx::DeformGridInfo& info)
: info_(info), data_(info_.res.x * info_.res.y * info_.res.z, glm::i8vec3(0))
{
}
void game::DeformGrid::ApplyImpulse(const glm::vec3& pos, const glm::vec3& impulse, float radius)
{
glm::vec3 step = (info_.max - info_.min) / glm::vec3(info_.res);
glm::ivec3 ipos;
// TODO: make more efficient
for (ipos.z = 0; ipos.z < info_.res.z; ++ipos.z)
{
for (ipos.y = 0; ipos.y < info_.res.y; ++ipos.y)
{
for (ipos.x = 0; ipos.x < info_.res.x; ++ipos.x)
{
glm::vec3 texel_pos = info_.min + glm::vec3(ipos) * step;
if (glm::distance2(pos, texel_pos) < radius * radius)
{
size_t idx = GetTexelIndex(ipos);
glm::vec3 offset = UnpackOffset(data_[idx]);
offset += impulse;
data_[idx] = PackOffset(offset);
}
}
}
}
}
glm::i8vec3 game::DeformGrid::PackOffset(const glm::vec3& offset)
{
return glm::i8vec3(glm::round(glm::clamp(offset / info_.max_offset, -1.0f, 1.0f) * 127.0f));
}
glm::vec3 game::DeformGrid::UnpackOffset(const glm::i8vec3& packed)
{
return glm::clamp(glm::vec3(packed) * 0.0078740157480315f, -1.0f, 1.0f) * info_.max_offset;
}

41
src/game/deform_grid.hpp Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include <vector>
#include <span>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtx/norm.hpp>
#include "gfx/deform_grid_info.hpp"
namespace game
{
class DeformGrid
{
public:
DeformGrid(const gfx::DeformGridInfo& info);
void ApplyImpulse(const glm::vec3& pos, const glm::vec3& impulse, float radius);
const gfx::DeformGridInfo& GetInfo() const { return info_; }
std::span<glm::i8vec3> GetData() { return data_; }
std::span<const glm::i8vec3> GetData() const { return data_; }
private:
glm::i8vec3 PackOffset(const glm::vec3& offset);
glm::vec3 UnpackOffset(const glm::i8vec3& packed);
size_t GetTexelIndex(const glm::ivec3& pos) const { return static_cast<size_t>(pos.x + (pos.y + pos.z * info_.res.y) * info_.res.x); }
private:
const gfx::DeformGridInfo info_;
std::vector<glm::i8vec3> data_;
};
}

View File

@ -47,12 +47,12 @@ game::OpenWorld::OpenWorld() : World("openworld")
SpawnBot();
}
auto& veh = Spawn<game::DrivableVehicle>("twingo", glm::vec3{0.8f, 0.1f, 0.1f});
auto& veh = Spawn<game::DrivableVehicle>("twingo", glm::vec3{1.0f, 0.8f, 0.1f});
veh.SetPosition({110.0f, 100.0f, 5.0f});
constexpr size_t in_row = 20;
for (size_t i = 0; i < 3000; ++i)
for (size_t i = 0; i < 1500; ++i)
{
Schedule(i * 40, [this, i] {
size_t col = i % in_row;

View File

@ -95,6 +95,14 @@ game::Vehicle::Vehicle(World& world, std::string model_name, const glm::vec3& co
bt_world.addRigidBody(body_.get(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::AllFilter);
bt_world.addAction(vehicle_.get());
// init deform
gfx::DeformGridInfo info{};
info.min = glm::vec3(-1.0f, -2.5f, 0.10f);
info.max = glm::vec3(1.0f, 2.0f, 1.8f);
info.res = glm::ivec3(8, 16, 8);
info.max_offset = 0.1f;
deformgrid_ = std::make_unique<DeformGrid>(info);
Update();
}
@ -127,20 +135,22 @@ void game::Vehicle::SendInitData(Player& player, net::OutMessage& msg) const
size_t fields_pos = msg.Reserve<VehicleSyncFieldFlags>();
auto fields = WriteState(msg, default_state);
msg.WriteAt(fields_pos, fields);
WriteDeformSync(msg);
}
void game::Vehicle::OnContact(float impulse)
void game::Vehicle::OnContact(const collision::ContactInfo& info)
{
Super::OnContact(impulse);
Super::OnContact(info);
crash_intensity_ += impulse;
crash_intensity_ += info.impulse;
if (impulse < 1000.0f)
if (info.impulse < 1000.0f)
return;
if (window_health_ > 0.0f)
{
window_health_ -= impulse;
window_health_ -= info.impulse;
if (window_health_ <= 0.0f) // just broken
{
@ -148,6 +158,11 @@ void game::Vehicle::OnContact(float impulse)
}
}
if (window_health_ <= 0.0f)
{
Deform(info.pos, -glm::normalize(info.normal) * 0.1f, 1.0f);
}
}
void game::Vehicle::SetInput(VehicleInputType type, bool enable)
@ -485,3 +500,56 @@ void game::Vehicle::SendUpdateMsg()
msg.WriteAt(fields_pos, fields);
}
void game::Vehicle::WriteDeformSync(net::OutMessage& msg) const
{
const auto texels = deformgrid_->GetData();
auto numtexels_pos = msg.Reserve<net::NumTexels>();
net::NumTexels numtexels = 0;
size_t last = 0;
for (size_t i = 0; i < texels.size(); ++i)
{
if (texels[i] == glm::i8vec3(0))
continue; // unchanged, no write
auto diff = i - last;
msg.WriteVarInt(diff);
for (size_t j = 0; j < 3; ++j)
{
msg.Write(texels[i][j]);
}
last = i;
++numtexels;
}
msg.WriteAt(numtexels_pos, numtexels);
}
void game::Vehicle::Deform(const glm::vec3& pos, const glm::vec3& deform, float radius)
{
net::PositionQ pos_q;
net::PositionQ deform_q;
net::EncodePosition(pos, pos_q);
net::EncodePosition(deform, deform_q);
SendDeformMsg(pos_q, deform_q);
// defeorm locally
glm::vec3 new_pos, new_deform;
net::DecodePosition(pos_q, new_pos);
net::DecodePosition(deform_q, new_deform);
deformgrid_->ApplyImpulse(new_pos, new_deform, 0.3f);
}
void game::Vehicle::SendDeformMsg(const net::PositionQ& pos, const net::PositionQ& deform)
{
auto msg = BeginEntMsg(net::EMSG_DEFORM);
net::WritePositionQ(msg, pos);
net::WritePositionQ(msg, deform);
}

View File

@ -9,6 +9,7 @@
#include "entity.hpp"
#include "world.hpp"
#include "vehicle_sync.hpp"
#include "deform_grid.hpp"
namespace game
{
@ -41,7 +42,7 @@ public:
virtual void Update() override;
virtual void SendInitData(Player& player, net::OutMessage& msg) const override;
virtual void OnContact(float impulse) override;
virtual void OnContact(const collision::ContactInfo& info) override;
void SetInput(VehicleInputType type, bool enable);
void SetInputs(VehicleInputFlags inputs) { in_ = inputs; }
@ -65,9 +66,14 @@ private:
void UpdateCrash();
void UpdateWheels();
void UpdateSyncState();
VehicleSyncFieldFlags WriteState(net::OutMessage& msg, const VehicleSyncState& base) const;
void SendUpdateMsg();
void WriteDeformSync(net::OutMessage& msg) const;
void Deform(const glm::vec3& pos, const glm::vec3& deform, float radius);
void SendDeformMsg(const net::PositionQ& pos, const net::PositionQ& deform);
private:
std::string model_name_;
std::shared_ptr<const assets::VehicleModel> model_;
@ -95,6 +101,8 @@ private:
float crash_intensity_ = 0.0f;
size_t no_crash_frames_ = 0;
std::unique_ptr<DeformGrid> deformgrid_;
};
} // namespace game

View File

@ -105,7 +105,7 @@ void game::World::HandleContacts()
static std::vector<net::ObjNum> to_destroy;
to_destroy.clear();
auto ProcessContact = [&](btRigidBody* body, btRigidBody* other_body, btManifoldPoint& pt) {
auto ProcessContact = [&](btRigidBody* body, btRigidBody* other_body, const btVector3& pos, const btVector3& normal, float impulse) {
collision::ObjectType type;
collision::ObjectFlags flags;
collision::ObjectCallback* cb;
@ -113,7 +113,11 @@ void game::World::HandleContacts()
if (cb && (flags & collision::OF_NOTIFY_CONTACT))
{
cb->OnContact(pt.getAppliedImpulse());
collision::ContactInfo info;
info.pos = glm::vec3(pos.x(), pos.y(), pos.z());
info.normal = glm::vec3(normal.x(), normal.y(), normal.z());
info.impulse = impulse;
cb->OnContact(info);
}
if (type == collision::OT_MAP_OBJECT && (flags & collision::OF_DESTRUCTIBLE))
@ -122,10 +126,10 @@ void game::World::HandleContacts()
if (!col)
return;
if (pt.getAppliedImpulse() > col->GetDestroyThreshold())
if (impulse > col->GetDestroyThreshold())
{
to_destroy.push_back(col->GetNum());
other_body->applyCentralImpulse(pt.m_normalWorldOnB * pt.getAppliedImpulse() * 0.5f);
other_body->applyCentralImpulse(-normal * impulse * 0.5f);
}
return;
@ -143,8 +147,8 @@ void game::World::HandleContacts()
for (int j = 0; j < contactManifold->getNumContacts(); j++)
{
btManifoldPoint& pt = contactManifold->getContactPoint(j);
ProcessContact(body0, body1, pt);
ProcessContact(body1, body0, pt);
ProcessContact(body0, body1, pt.m_localPointA, -pt.m_normalWorldOnB, pt.getAppliedImpulse());
ProcessContact(body1, body0, pt.m_localPointB, pt.m_normalWorldOnB, pt.getAppliedImpulse());
}
}

View File

@ -3,8 +3,10 @@
#include "assets/cache.hpp"
#include "net/utils.hpp"
#include "worldview.hpp"
#include "utils/random.hpp"
#include <iostream>
#include <ranges>
game::view::VehicleView::VehicleView(WorldView& world, net::InMessage& msg)
: EntityView(world, msg)
@ -16,6 +18,7 @@ game::view::VehicleView::VehicleView(WorldView& world, net::InMessage& msg)
model_ = assets::CacheManager::GetVehicleModel("data/" + std::string(modelname) + ".veh");
mesh_ = *model_->GetModel()->GetMesh();
InitMesh();
auto& modelwheels = model_->GetWheels();
wheels_.resize(modelwheels.size());
@ -29,7 +32,10 @@ game::view::VehicleView::VehicleView(WorldView& world, net::InMessage& msg)
if (!ReadState(&msg))
throw EntityInitError();
if (!ReadDeformSync(msg))
throw EntityInitError();
// init the other transform to identical
root_trans_[0] = root_trans_[1];
root_.local = root_trans_[0];
@ -43,6 +49,8 @@ bool game::view::VehicleView::ProcessMsg(net::EntMsgType type, net::InMessage& m
{
switch (type)
{
case net::EMSG_DEFORM:
return ProcessDeformMsg(msg);
default:
return Super::ProcessMsg(type, msg);
}
@ -141,6 +149,44 @@ void game::view::VehicleView::Draw(const DrawArgs& args)
args.dlist.AddSurface(cmd);
}
}
// temp deforms
for (const auto& [pos, deform] : debug_deforms_)
{
glm::vec3 start = root_.matrix * glm::vec4(pos, 1.0f);
glm::vec3 end = root_.matrix * glm::vec4(pos + deform, 1.0f);
glm::vec3 end2 = end + glm::vec3(0.0f, 0.0f, 0.1f);
args.dlist.AddBeam(start, end, 0xFFFFFF00, 0.01f);
args.dlist.AddBeam(end, end2, 0xFFFF00FF, 0.01f);
}
}
void game::view::VehicleView::InitMesh()
{
gfx::DeformGridInfo info{};
info.min = glm::vec3(-1.0f, -2.5f, 0.10f);
info.max = glm::vec3(1.0f, 2.0f, 1.8f);
info.res = glm::ivec3(8, 16, 8);
info.max_offset = 0.1f;
deform_ = std::make_unique<VehicleDeformView>(info);
for (auto& surface : mesh_.surfaces)
{
surface.deform_tex = deform_->tex;
surface.sflags |= gfx::SF_DEFORM_GRID;
}
// for (size_t i = 0; i < 20; ++i)
// {
// glm::vec3 pos(RandomFloat(-1.0f, 1.0f), RandomFloat(-2.0f, 2.0f), RandomFloat(0.0f, 2.0f));
// glm::vec3 impulse(RandomFloat(-1.0f, 1.0f), RandomFloat(-1.0f, 1.0f), RandomFloat(-1.0f, 1.0f));
// impulse *= 0.05f;
// deform_->grid.ApplyImpulse(pos, impulse, 1.0f);
// }
deform_->tex->SetData(deform_->grid.GetData());
}
bool game::view::VehicleView::ReadState(net::InMessage* msg)
@ -192,7 +238,7 @@ bool game::view::VehicleView::ReadState(net::InMessage* msg)
return false;
}
float steering = sync_.steering.Decode();
// wheels
@ -218,3 +264,58 @@ bool game::view::VehicleView::ReadState(net::InMessage* msg)
}
return true;
}
bool game::view::VehicleView::ReadDeformSync(net::InMessage& msg)
{
net::NumTexels numtexels;
if (!msg.Read(numtexels))
return false;
auto texels = deform_->grid.GetData();
std::ranges::fill(texels, glm::i8vec3(0));
size_t current = 0;
for (size_t i = 0; i < numtexels; ++i)
{
int64_t diff;
if (!msg.ReadVarInt(diff))
return false;
current += static_cast<size_t>(diff);
if (current >= texels.size())
return false;
auto& texel = texels[current];
for (size_t j = 0; j < 3; ++j)
{
if (!msg.Read(texel[j]))
return false;
}
}
deform_->tex->SetData(deform_->grid.GetData());
return true;
}
bool game::view::VehicleView::ProcessDeformMsg(net::InMessage& msg)
{
net::PositionQ pos_q, deform_q;
if (!net::ReadPositionQ(msg, pos_q) || !net::ReadPositionQ(msg, deform_q))
return false;
glm::vec3 pos, deform;
net::DecodePosition(pos_q, pos);
net::DecodePosition(deform_q, deform);
deform_->grid.ApplyImpulse(pos, deform, 0.3f);
deform_->tex->SetData(deform_->grid.GetData());
//debug_deforms_.emplace_back(std::make_tuple(pos, deform));
return true;
}

View File

@ -4,6 +4,7 @@
#include "assets/vehiclemdl.hpp"
#include "game/vehicle_sync.hpp"
#include "game/deform_grid.hpp"
#include <chrono>
@ -19,6 +20,14 @@ struct VehicleWheelViewInfo
float rotation = 0.0f;
};
struct VehicleDeformView
{
DeformGrid grid;
std::shared_ptr<gfx::DeformTexture> tex;
VehicleDeformView(const gfx::DeformGridInfo& info) : grid(info), tex(std::make_shared<gfx::DeformTexture>(info)) {}
};
class VehicleView : public EntityView
{
using Super = EntityView;
@ -32,8 +41,13 @@ public:
virtual void Draw(const DrawArgs& args) override;
private:
void InitMesh();
bool ReadState(net::InMessage* msg);
bool ReadDeformSync(net::InMessage& msg);
bool ProcessDeformMsg(net::InMessage& msg);
private:
std::shared_ptr<const assets::VehicleModel> model_;
assets::Mesh mesh_;
@ -51,6 +65,8 @@ private:
audio::SoundSource* snd_accel_src_ = nullptr;
bool windows_broken_ = false;
std::unique_ptr<VehicleDeformView> deform_;
std::vector<std::tuple<glm::vec3, glm::vec3>> debug_deforms_;
};
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <glm/glm.hpp>
namespace gfx
{
struct DeformGridInfo
{
glm::vec3 min;
glm::vec3 max;
glm::ivec3 res;
float max_offset;
};
}

View File

@ -0,0 +1,32 @@
#include "deform_texture.hpp"
#include <stdexcept>
gfx::DeformTexture::DeformTexture(const DeformGridInfo& info) : info_(info)
{
glGenTextures(1, &id_);
if (!id_)
throw std::runtime_error("Nelze vytvorit texturu!");
glBindTexture(GL_TEXTURE_3D, id_);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_3D, 0);
}
void gfx::DeformTexture::SetData(std::span<const glm::i8vec3> data)
{
glBindTexture(GL_TEXTURE_3D, id_);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB8_SNORM, info_.res.x, info_.res.y, info_.res.z, 0, GL_RGB, GL_BYTE, data.data());
}
gfx::DeformTexture::~DeformTexture()
{
glDeleteTextures(1, &id_);
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <span>
#include <glm/glm.hpp>
#include "client/gl.hpp"
#include "utils/defs.hpp"
#include "deform_grid_info.hpp"
namespace gfx
{
class DeformTexture
{
public:
DeformTexture(const DeformGridInfo& info);
DELETE_COPY_MOVE(DeformTexture)
void SetData(std::span<const glm::i8vec3> data);
const DeformGridInfo& GetInfo() const { return info_; }
GLuint GetId() const { return id_; }
~DeformTexture();
private:
const DeformGridInfo info_;
GLuint id_;
};
}

View File

@ -16,6 +16,7 @@ gfx::Renderer::Renderer()
{
ShaderSources::MakeShader(mesh_shader_.shader, SS_MESH_VERT, SS_MESH_FRAG);
ShaderSources::MakeShader(skel_mesh_shader_.shader, SS_SKEL_MESH_VERT, SS_SKEL_MESH_FRAG);
ShaderSources::MakeShader(deform_mesh_shader_.shader, SS_DEFORM_MESH_VERT, SS_DEFORM_MESH_FRAG);
ShaderSources::MakeShader(solid_shader_, SS_SOLID_VERT, SS_SOLID_FRAG);
ShaderSources::MakeShader(hud_shader_, SS_HUD_VERT, SS_HUD_FRAG);
ShaderSources::MakeShader(beam_shader_, SS_BEAM_VERT, SS_BEAM_FRAG);
@ -104,6 +105,7 @@ void gfx::Renderer::InvalidateShaders()
{
InvalidateMeshShader(mesh_shader_);
InvalidateMeshShader(skel_mesh_shader_);
InvalidateMeshShader(deform_mesh_shader_);
}
void gfx::Renderer::InvalidateMeshShader(MeshShader& mshader)
@ -171,6 +173,7 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
const gfx::Texture* last_texture = nullptr;
const gfx::VertexArray* last_vao = nullptr;
const gfx::UniformBuffer<glm::mat4>* last_skin = nullptr;
const DeformTexture* last_deform = nullptr;
InvalidateShaders();
// enable depth test
@ -199,6 +202,7 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
const bool twosided_flag = surface->sflags & SF_2SIDED;
const bool blend_flag = surface->sflags & SF_BLEND;
const bool object_color_flag = surface->sflags & SF_OBJECT_COLOR;
const bool deform_flag = surface->sflags & SF_DEFORM_GRID;
// sync 2sided
if (last_twosided != twosided_flag)
@ -212,7 +216,7 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
}
// select shader
MeshShader& mshader = skeletal_flag ? skel_mesh_shader_ : mesh_shader_;
MeshShader& mshader = skeletal_flag ? skel_mesh_shader_ : (deform_flag ? deform_mesh_shader_ : mesh_shader_);
SetupMeshShader(mshader, params);
// set model matrix
@ -290,16 +294,35 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
if (last_texture != surface->texture.get())
{
GLuint tex_id = surface->texture ? surface->texture->GetId() : 0;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_id);
last_texture = surface->texture.get();
}
// bind skinning UBO
if (cmd.skinning && last_skin != cmd.skinning)
{
glBindBufferBase(GL_UNIFORM_BUFFER, 0, cmd.skinning->GetId());
glBindBufferBase(GL_UNIFORM_BUFFER, 0, cmd.skinning->GetId());
last_skin = cmd.skinning;
}
// bind deform texture
if (deform_flag && surface->deform_tex.get() != last_deform)
{
const auto& deform_tex = *surface->deform_tex;
GLuint tex_id = deform_tex.GetId();
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_3D, tex_id);
last_deform = &deform_tex;
// update deform tex info
const auto& deform_info = deform_tex.GetInfo();
glm::mat3 deform_info_mat;
deform_info_mat[0] = deform_info.min;
deform_info_mat[1] = deform_info.max;
deform_info_mat[2] = glm::vec3(deform_info.max_offset, 0.0f, 0.0f);
glUniformMatrix3fv(mshader.shader->U(SU_DEFORM_INFO), 1, GL_FALSE, &deform_info_mat[0][0]);
}
// bind VAO
if (last_vao != surface->va.get())
@ -428,6 +451,8 @@ void gfx::Renderer::DrawHudList(std::span<DrawHudCmd> queue, const DrawListParam
const gfx::Texture* last_texture = nullptr;
const gfx::VertexArray* last_vao = nullptr;
glActiveTexture(GL_TEXTURE0);
for (const auto& cmd : queue)
{
if (!cmd.va || !cmd.texture)

View File

@ -52,6 +52,7 @@ namespace gfx
private:
MeshShader mesh_shader_;
MeshShader skel_mesh_shader_;
MeshShader deform_mesh_shader_;
std::unique_ptr<Shader> solid_shader_;
std::unique_ptr<BufferObject> beam_segments_vbo_;

View File

@ -11,6 +11,8 @@ static const char* const s_uni_names[] = {
"u_color", // SU_COLOR
"u_flags", // SU_FLAGS
"u_camera", // SU_CAMERA
"u_deform_tex", // SU_DEFORM_TEX
"u_deform_info", // SU_DEFORM_INFO
};
// Vytvori shader z daneho zdroje
@ -93,6 +95,7 @@ void gfx::Shader::SetupBindings()
glUseProgram(m_id);
glUniform1i(m_uni[SU_TEX], 0);
glUniform1i(m_uni[SU_DEFORM_TEX], 1);
// Bones UBO
int ubo_index = glGetUniformBlockIndex(m_id, "Bones");

View File

@ -16,6 +16,8 @@ namespace gfx
SU_COLOR,
SU_FLAGS,
SU_CAMERA,
SU_DEFORM_TEX,
SU_DEFORM_INFO,
SU_COUNT
};

View File

@ -212,6 +212,76 @@ void main() {
)GLSL",
// SS_DEFORM_MESH_VERT
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;
)GLSL"
MESH_MATRICES_GLSL
LIGHT_MATRICES_GLSL
COMPUTE_LIGHTS_GLSL
R"GLSL(
uniform sampler3D u_deform_tex;
uniform mat3 u_deform_info;
out vec2 v_uv;
out vec3 v_color;
void main() {
vec3 deform_pos = (a_pos - u_deform_info[0]) / (u_deform_info[1] - u_deform_info[0]);
vec3 pos = a_pos + texture(u_deform_tex, deform_pos).xyz * u_deform_info[2].x;
//vec3 pos = a_pos + u_deform_info[0] * u_deform_info[2].x;
//vec3 pos = a_pos + vec3(0.0, 0.0, 1.0);
vec4 world_pos = u_model * vec4(pos, 1.0);
vec3 world_normal = normalize(mat3(u_model) * a_normal);
gl_Position = u_view_proj * world_pos;
v_uv = a_uv;
v_color = ComputeLights(world_pos.xyz, world_normal) * a_color.rgb;
}
)GLSL",
// SS_DEFORM_MESH_FRAG
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",
// SS_SOLID_VERT
SHADER_HEADER
R"GLSL(

View File

@ -13,6 +13,9 @@ namespace gfx
SS_SKEL_MESH_VERT,
SS_SKEL_MESH_FRAG,
SS_DEFORM_MESH_VERT,
SS_DEFORM_MESH_FRAG,
SS_SOLID_VERT,
SS_SOLID_FRAG,

View File

@ -2,6 +2,7 @@
#include "texture.hpp"
#include "vertex_array.hpp"
#include "deform_texture.hpp"
namespace gfx
{
@ -24,16 +25,18 @@ enum SurfaceFlag : SurfaceFlags
SF_BLEND = 0x02, // enable blending, disable depth write
SF_BLEND_ADDITIVE = 0x04, // use additive blending instead of opacity
SF_OBJECT_COLOR = 0x08, // use object color for background instead of alpha culling
SF_DEFORM_GRID = 0x10, // use deform grid
};
struct Surface
{
std::shared_ptr<const gfx::Texture> texture;
std::shared_ptr<const gfx::VertexArray> va;
std::shared_ptr<const Texture> texture;
std::shared_ptr<const VertexArray> va;
size_t first = 0; // first triangle VA EBO
size_t count = 0; // number of triangles
MeshFlags mflags = MF_NONE;
SurfaceFlags sflags = SF_NONE;
std::shared_ptr<const DeformTexture> deform_tex;
};
} // namespace gfx

View File

@ -90,6 +90,7 @@ enum EntMsgType : uint8_t
EMSG_ATTACH,
// EMSG_UPDATE, // deprecated
EMSG_PLAYSOUND,
EMSG_DEFORM,
};
using PositionElemQ = Quantized<uint32_t, -10000, 10000, 1>;
@ -128,4 +129,6 @@ using ClothesName = FixedStr<32>;
using ObjNum = uint16_t;
using ObjCount = ObjNum;
using NumTexels = uint16_t;
} // namespace net