Implement danglymeshes
This commit is contained in:
parent
2212f0ff00
commit
1751023903
13 changed files with 126 additions and 6 deletions
|
@ -260,9 +260,11 @@ void ActionExecutor::advanceCreatureOnPath(const shared_ptr<Creature> &creature,
|
|||
|
||||
} else if (_game->module()->area()->moveCreatureTowards(creature, dest, run, dt)) {
|
||||
creature->setMovementType(run ? Creature::MovementType::Run : Creature::MovementType::Walk);
|
||||
creature->setAppliedForce(glm::vec3(glm::normalize(glm::vec2(dest - origin)), 0.0f));
|
||||
|
||||
} else {
|
||||
creature->setMovementType(Creature::MovementType::None);
|
||||
creature->setAppliedForce(glm::vec3(0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -638,6 +638,12 @@ void Creature::getOffhandDamage(int &min, int &max) const {
|
|||
getWeaponDamage(InventorySlot::leftWeapon, min, max);
|
||||
}
|
||||
|
||||
void Creature::setAppliedForce(glm::vec3 force) {
|
||||
if (_sceneNode && _sceneNode->type() == SceneNodeType::Model) {
|
||||
static_pointer_cast<ModelSceneNode>(_sceneNode)->setAppliedForce(force);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace game
|
||||
|
||||
} // namespace reone
|
||||
|
|
|
@ -196,10 +196,16 @@ public:
|
|||
void getMainHandDamage(int &min, int &max) const;
|
||||
void getOffhandDamage(int &min, int &max) const;
|
||||
|
||||
void setAttackTarget(std::shared_ptr<SpatialObject> target) { _combat.attackTarget = move(target); }
|
||||
void setAttackTarget(std::shared_ptr<SpatialObject> target) { _combat.attackTarget = std::move(target); }
|
||||
|
||||
// END Combat
|
||||
|
||||
// Physics
|
||||
|
||||
void setAppliedForce(glm::vec3 force);
|
||||
|
||||
// END Physics
|
||||
|
||||
// Scripts
|
||||
|
||||
void runSpawnScript();
|
||||
|
|
|
@ -165,9 +165,11 @@ void Player::update(float dt) {
|
|||
|
||||
if (_area->moveCreature(partyLeader, dir, true, dt)) {
|
||||
partyLeader->setMovementType(Creature::MovementType::Run);
|
||||
partyLeader->setAppliedForce(glm::vec3(dir, 0.0f));
|
||||
}
|
||||
} else if (actions.isEmpty()) {
|
||||
partyLeader->setMovementType(Creature::MovementType::None);
|
||||
partyLeader->setAppliedForce(glm::vec3(0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1088,18 +1088,17 @@ void MdlReader::readDanglymesh(ModelNode &node) {
|
|||
float period = readFloat();
|
||||
ignore(4); // unknown
|
||||
|
||||
node._danglymesh->displacement = displacement;
|
||||
node._danglymesh->displacement = 0.5f * displacement; // displacement is allegedly 1/2 meters per unit
|
||||
node._danglymesh->tightness = tightness;
|
||||
node._danglymesh->period = period;
|
||||
|
||||
size_t pos = tell();
|
||||
seek(kMdlDataOffset + constraintArrayDef.offset);
|
||||
for (uint32_t i = 0; i < constraintArrayDef.count; ++i) {
|
||||
float number = readFloat();
|
||||
float multiplier = readFloat();
|
||||
vector<float> positionValues(readFloatArray(3));
|
||||
|
||||
ModelNode::DanglymeshConstraint constraint;
|
||||
constraint.number = number;
|
||||
constraint.multiplier = glm::clamp(multiplier / 255.0f, 0.0f, 1.0f);
|
||||
constraint.position = glm::make_vec3(&positionValues[0]);
|
||||
node._danglymesh->constraints.push_back(move(constraint));
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public:
|
|||
};
|
||||
|
||||
struct DanglymeshConstraint {
|
||||
float number { 0.0f };
|
||||
float multiplier { 0.0f };
|
||||
glm::vec3 position { 0.0f };
|
||||
};
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ static constexpr int kBindingPointIndexLighting = 3;
|
|||
static constexpr int kBindingPointIndexSkeletal = 4;
|
||||
static constexpr int kBindingPointIndexParticles = 5;
|
||||
static constexpr int kBindingPointIndexGrass = 6;
|
||||
static constexpr int kBindingPointIndexDanglymesh = 7;
|
||||
|
||||
static constexpr GLchar kShaderBaseHeader[] = R"END(
|
||||
#version 330
|
||||
|
@ -60,7 +61,11 @@ const int FEATURE_PARTICLES = 0x400;
|
|||
const int FEATURE_WATER = 0x800;
|
||||
const int FEATURE_HDR = 0x1000;
|
||||
const int FEATURE_CUSTOMMAT = 0x2000;
|
||||
const int FEATURE_BLUR = 0x4000;
|
||||
const int FEATURE_TEXT = 0x8000;
|
||||
const int FEATURE_GRASS = 0x10000;
|
||||
const int FEATURE_FOG = 0x20000;
|
||||
const int FEATURE_DANGLYMESH = 0x40000;
|
||||
|
||||
const int NUM_CUBE_FACES = 6;
|
||||
const int MAX_BONES = 128;
|
||||
|
@ -68,6 +73,7 @@ const int MAX_LIGHTS = 16;
|
|||
const int MAX_PARTICLES = 32;
|
||||
const int MAX_CHARS = 128;
|
||||
const int MAX_GRASS_CLUSTERS = 256;
|
||||
const int MAX_DANGLYMESH_CONSTRAINTS = 512;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
const float GAMMA = 2.2;
|
||||
|
@ -182,6 +188,12 @@ layout(std140) uniform Grass {
|
|||
GrassCluster uGrassClusters[MAX_GRASS_CLUSTERS];
|
||||
};
|
||||
|
||||
layout(std140) uniform Danglymesh {
|
||||
vec4 uDanglymeshStride;
|
||||
float uDanglymeshDisplacement;
|
||||
vec4 uDanglymeshConstraints[MAX_DANGLYMESH_CONSTRAINTS];
|
||||
};
|
||||
|
||||
bool isFeatureEnabled(int flag) {
|
||||
return (uFeatureMask & flag) != 0;
|
||||
}
|
||||
|
@ -508,6 +520,12 @@ void main() {
|
|||
|
||||
} else {
|
||||
P = vec4(aPosition, 1.0);
|
||||
|
||||
if (isFeatureEnabled(FEATURE_DANGLYMESH)) {
|
||||
vec3 maxStride = vec3(uDanglymeshDisplacement * uDanglymeshConstraints[gl_VertexID / 4][gl_VertexID % 4]);
|
||||
vec3 stride = clamp(uDanglymeshStride.xyz, -maxStride, maxStride);
|
||||
P += vec4(stride, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
fragPosition = vec3(uGeneral.model * P);
|
||||
|
@ -1192,6 +1210,7 @@ void Shaders::init() {
|
|||
glGenBuffers(1, &_uboSkeletal);
|
||||
glGenBuffers(1, &_uboParticles);
|
||||
glGenBuffers(1, &_uboGrass);
|
||||
glGenBuffers(1, &_uboDanglymesh);
|
||||
|
||||
for (auto &program : _programs) {
|
||||
glUseProgram(program.second);
|
||||
|
@ -1209,6 +1228,7 @@ void Shaders::init() {
|
|||
_defaultUniforms.skeletal = make_shared<SkeletalUniforms>();
|
||||
_defaultUniforms.particles = make_shared<ParticlesUniforms>();
|
||||
_defaultUniforms.grass = make_shared<GrassUniforms>();
|
||||
_defaultUniforms.danglymesh = make_shared<DanglymeshUniforms>();
|
||||
|
||||
_inited = true;
|
||||
}
|
||||
|
@ -1260,6 +1280,7 @@ void Shaders::initUBOs() {
|
|||
static SkeletalUniforms defaultsSkeletal;
|
||||
static ParticlesUniforms defaultsParticles;
|
||||
static GrassUniforms defaultsGrass;
|
||||
static DanglymeshUniforms defaultsDanglymesh;
|
||||
|
||||
initUBO("Combined", kBindingPointIndexCombined, _uboCombined, defaultsCombined, offsetof(ShaderUniforms, text));
|
||||
initUBO("Text", kBindingPointIndexText, _uboText, defaultsText);
|
||||
|
@ -1267,6 +1288,7 @@ void Shaders::initUBOs() {
|
|||
initUBO("Skeletal", kBindingPointIndexSkeletal, _uboSkeletal, defaultsSkeletal);
|
||||
initUBO("Particles", kBindingPointIndexParticles, _uboParticles, defaultsParticles);
|
||||
initUBO("Grass", kBindingPointIndexGrass, _uboGrass, defaultsGrass);
|
||||
initUBO("Danglymesh", kBindingPointIndexDanglymesh, _uboDanglymesh, defaultsDanglymesh);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
@ -1324,6 +1346,10 @@ void Shaders::deinit() {
|
|||
glDeleteBuffers(1, &_uboGrass);
|
||||
_uboGrass = 0;
|
||||
}
|
||||
if (_uboDanglymesh) {
|
||||
glDeleteBuffers(1, &_uboDanglymesh);
|
||||
_uboDanglymesh = 0;
|
||||
}
|
||||
|
||||
// Delete programs
|
||||
for (auto &pair : _programs) {
|
||||
|
@ -1383,6 +1409,10 @@ void Shaders::setUniforms(const ShaderUniforms &uniforms) {
|
|||
glBindBufferBase(GL_UNIFORM_BUFFER, kBindingPointIndexGrass, _uboGrass);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(GrassUniforms), uniforms.grass.get());
|
||||
}
|
||||
if (uniforms.combined.featureMask & UniformFeatureFlags::danglymesh) {
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, kBindingPointIndexDanglymesh, _uboDanglymesh);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(DanglymeshUniforms), uniforms.danglymesh.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Shaders::setUniform(const string &name, const glm::mat4 &m) {
|
||||
|
|
|
@ -72,6 +72,7 @@ struct UniformFeatureFlags {
|
|||
static constexpr int text = 0x8000;
|
||||
static constexpr int grass = 0x10000;
|
||||
static constexpr int fog = 0x20000;
|
||||
static constexpr int danglymesh = 0x40000;
|
||||
};
|
||||
|
||||
struct ShaderGeneral {
|
||||
|
@ -187,6 +188,13 @@ struct TextUniforms {
|
|||
ShaderCharacter chars[kMaxCharacters];
|
||||
};
|
||||
|
||||
struct DanglymeshUniforms {
|
||||
glm::vec4 stride { 0.0f };
|
||||
float displacement { 0.0f };
|
||||
char padding[12];
|
||||
glm::vec4 constraints[kMaxDanglymeshConstraints];
|
||||
};
|
||||
|
||||
struct ShaderUniforms {
|
||||
CombinedUniforms combined;
|
||||
|
||||
|
@ -195,6 +203,7 @@ struct ShaderUniforms {
|
|||
std::shared_ptr<SkeletalUniforms> skeletal;
|
||||
std::shared_ptr<ParticlesUniforms> particles;
|
||||
std::shared_ptr<GrassUniforms> grass;
|
||||
std::shared_ptr<DanglymeshUniforms> danglymesh;
|
||||
};
|
||||
|
||||
class Shaders : boost::noncopyable {
|
||||
|
@ -248,6 +257,7 @@ private:
|
|||
uint32_t _uboSkeletal { 0 };
|
||||
uint32_t _uboParticles { 0 };
|
||||
uint32_t _uboGrass { 0 };
|
||||
uint32_t _uboDanglymesh { 0 };
|
||||
|
||||
// END UBO
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ constexpr int kMaxLights = 16;
|
|||
constexpr int kMaxParticles = 32;
|
||||
constexpr int kMaxCharacters = 128;
|
||||
constexpr int kMaxGrassClusters = 256;
|
||||
constexpr int kMaxDanglymeshConstraints = 512;
|
||||
|
||||
enum class PixelFormat {
|
||||
Grayscale,
|
||||
|
|
|
@ -128,7 +128,36 @@ void ModelNodeSceneNode::update(float dt) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Danglymesh animation
|
||||
shared_ptr<ModelNode::Danglymesh> danglymesh(_modelNode->danglymesh());
|
||||
if (danglymesh) {
|
||||
bool forceApplied = glm::length2(_danglymeshAnimation.force) > 0.0f;
|
||||
if (forceApplied) {
|
||||
// When force is applied, stride in the opposite direction from the applied force
|
||||
glm::vec3 strideDir(-_danglymeshAnimation.force);
|
||||
glm::vec3 maxStride(danglymesh->displacement);
|
||||
_danglymeshAnimation.stride = glm::clamp(_danglymeshAnimation.stride + danglymesh->period * strideDir * dt, -maxStride, maxStride);
|
||||
} else {
|
||||
// When force is not applied, gradually nullify stride
|
||||
float strideMag2 = glm::length2(_danglymeshAnimation.stride);
|
||||
if (strideMag2 > 0.0f) {
|
||||
glm::vec3 strideDir(-_danglymeshAnimation.stride);
|
||||
_danglymeshAnimation.stride += danglymesh->period * strideDir * dt;
|
||||
if ((strideDir.x > 0.0f && _danglymeshAnimation.stride.x > 0.0f) || (strideDir.x < 0.0f && _danglymeshAnimation.stride.x < 0.0f)) {
|
||||
_danglymeshAnimation.stride.x = 0.0f;
|
||||
}
|
||||
if ((strideDir.y > 0.0f && _danglymeshAnimation.stride.y > 0.0f) || (strideDir.y < 0.0f && _danglymeshAnimation.stride.y < 0.0f)) {
|
||||
_danglymeshAnimation.stride.y = 0.0f;
|
||||
}
|
||||
if ((strideDir.z > 0.0f && _danglymeshAnimation.stride.z > 0.0f) || (strideDir.z < 0.0f && _danglymeshAnimation.stride.z < 0.0f)) {
|
||||
_danglymeshAnimation.stride.z = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SceneNode::update(dt);
|
||||
}
|
||||
|
||||
|
@ -315,6 +344,17 @@ void ModelNodeSceneNode::drawSingle(bool shadowPass) {
|
|||
uniforms.combined.general.fogFar = _sceneGraph->fogFar();
|
||||
uniforms.combined.general.fogColor = glm::vec4(_sceneGraph->fogColor(), 1.0f);
|
||||
}
|
||||
|
||||
shared_ptr<ModelNode::Danglymesh> danglymesh(_modelNode->danglymesh());
|
||||
if (danglymesh) {
|
||||
uniforms.combined.featureMask |= UniformFeatureFlags::danglymesh;
|
||||
uniforms.danglymesh->stride = glm::vec4(_danglymeshAnimation.stride, 0.0f);
|
||||
uniforms.danglymesh->displacement = danglymesh->displacement;
|
||||
size_t i = 0;
|
||||
for (i = 0; i < danglymesh->constraints.size(); ++i) {
|
||||
uniforms.danglymesh->constraints[i / 4][i % 4] = danglymesh->constraints[i].multiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Shaders::instance().activate(program, uniforms);
|
||||
|
@ -375,6 +415,13 @@ bool ModelNodeSceneNode::isLightingEnabled() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
void ModelNodeSceneNode::setAppliedForce(glm::vec3 force) {
|
||||
if (_modelNode->danglymesh()) {
|
||||
// Convert force from world to object space
|
||||
_danglymeshAnimation.force = _absoluteTransformInv * glm::vec4(force, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 ModelNodeSceneNode::getOrigin() const {
|
||||
return _absoluteTransform * glm::vec4(_modelNode->getCenterOfAABB(), 1.0f);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ public:
|
|||
|
||||
void drawSingle(bool shadowPass);
|
||||
|
||||
void setAppliedForce(glm::vec3 force);
|
||||
|
||||
bool shouldRender() const;
|
||||
bool shouldCastShadows() const;
|
||||
|
||||
|
@ -62,6 +64,11 @@ private:
|
|||
std::shared_ptr<render::Texture> bumpmap;
|
||||
} _textures;
|
||||
|
||||
struct DanglymeshAnimation {
|
||||
glm::vec3 force { 0.0f }; /**< net force applied to this scene node */
|
||||
glm::vec3 stride { 0.0f }; /**< how far have vertices traveled from the rest position? */
|
||||
} _danglymeshAnimation;
|
||||
|
||||
const ModelSceneNode *_modelSceneNode;
|
||||
const render::ModelNode *_modelNode;
|
||||
|
||||
|
|
|
@ -370,6 +370,15 @@ void ModelSceneNode::signalEvent(const string &name) {
|
|||
}
|
||||
}
|
||||
|
||||
void ModelSceneNode::setAppliedForce(glm::vec3 force) {
|
||||
for (auto &nodePair : _modelNodeByIndex) {
|
||||
nodePair.second->setAppliedForce(force);
|
||||
}
|
||||
for (auto &attached : _attachedModels) {
|
||||
attached.second->setAppliedForce(force);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scene
|
||||
|
||||
} // namespace reone
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
|
||||
void refreshAABB();
|
||||
void signalEvent(const std::string &name);
|
||||
void setAppliedForce(glm::vec3 force);
|
||||
|
||||
bool isCulledOut() const { return _culledOut; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue