Vehicle deform
This commit is contained in:
parent
8369181e9a
commit
3e284af672
@ -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"
|
||||
|
||||
@ -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
46
src/game/deform_grid.cpp
Normal 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
41
src/game/deform_grid.hpp
Normal 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_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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());
|
||||
@ -30,6 +33,9 @@ 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)
|
||||
@ -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;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
17
src/gfx/deform_grid_info.hpp
Normal file
17
src/gfx/deform_grid_info.hpp
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
32
src/gfx/deform_texture.cpp
Normal file
32
src/gfx/deform_texture.cpp
Normal 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_);
|
||||
}
|
||||
34
src/gfx/deform_texture.hpp
Normal file
34
src/gfx/deform_texture.hpp
Normal 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_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -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,6 +294,7 @@ 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();
|
||||
}
|
||||
@ -297,10 +302,28 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
||||
// 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)
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -16,6 +16,8 @@ namespace gfx
|
||||
SU_COLOR,
|
||||
SU_FLAGS,
|
||||
SU_CAMERA,
|
||||
SU_DEFORM_TEX,
|
||||
SU_DEFORM_INFO,
|
||||
|
||||
SU_COUNT
|
||||
};
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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,
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
Loading…
x
Reference in New Issue
Block a user