feat: Add feature toggle to enable dynamic room lighting
This commit is contained in:
parent
3e68ee914b
commit
9c41c3432b
15 changed files with 86 additions and 54 deletions
|
@ -77,7 +77,7 @@ void AnimatedCamera::setModel(const shared_ptr<Model> &model) {
|
|||
(!_model && !model)) return;
|
||||
|
||||
if (model) {
|
||||
_model = make_unique<ModelSceneNode>(_sceneGraph, model);
|
||||
_model = make_unique<ModelSceneNode>(ModelSceneNode::Classification::Other, model, _sceneGraph);
|
||||
_model->attach("camerahook", _sceneNode);
|
||||
} else {
|
||||
_model.reset();
|
||||
|
|
|
@ -389,7 +389,7 @@ void Combat::fireProjectile(const shared_ptr<Creature> &attacker, const shared_p
|
|||
|
||||
weapon->playShotSound(0, projectilePosition);
|
||||
|
||||
round.projectile = make_shared<ModelSceneNode>(&_game->sceneGraph(), ammunitionType->model);
|
||||
round.projectile = make_shared<ModelSceneNode>(ModelSceneNode::Classification::Projectile, ammunitionType->model, &_game->sceneGraph());
|
||||
round.projectile->setPosition(projectilePosition);
|
||||
round.projectile->signalEvent(kModelEventDetonate);
|
||||
|
||||
|
|
|
@ -385,7 +385,7 @@ void CharacterGeneration::loadCharacterModel() {
|
|||
}
|
||||
|
||||
shared_ptr<ModelSceneNode> CharacterGeneration::getCharacterModel(SceneGraph &sceneGraph) {
|
||||
auto root = make_shared<ModelSceneNode>(&sceneGraph, Models::instance().get("cgbody_light"));
|
||||
auto root = make_shared<ModelSceneNode>(ModelSceneNode::Classification::Other, Models::instance().get("cgbody_light"), &sceneGraph);
|
||||
|
||||
// Attach character model to the root model
|
||||
auto objectFactory = make_unique<ObjectFactory>(_game, &sceneGraph);
|
||||
|
|
|
@ -181,7 +181,7 @@ void ClassSelection::configureClassModel(int index, Gender gender, ClassType cla
|
|||
}
|
||||
|
||||
shared_ptr<ModelSceneNode> ClassSelection::getCharacterModel(const std::shared_ptr<StaticCreatureBlueprint> &character, SceneGraph &sceneGraph) {
|
||||
auto root = make_shared<ModelSceneNode>(&sceneGraph, Models::instance().get("cgbody_light"));
|
||||
auto root = make_shared<ModelSceneNode>(ModelSceneNode::Classification::Other, Models::instance().get("cgbody_light"), &sceneGraph);
|
||||
|
||||
// Attach character model to the root model
|
||||
auto objectFactory = make_unique<ObjectFactory>(_game, &sceneGraph);
|
||||
|
|
|
@ -95,7 +95,7 @@ void PortraitSelection::loadHeadModel() {
|
|||
}
|
||||
|
||||
shared_ptr<ModelSceneNode> PortraitSelection::getCharacterModel(SceneGraph &sceneGraph) {
|
||||
auto root = make_shared<ModelSceneNode>(&sceneGraph, Models::instance().get("cghead_light"));
|
||||
auto root = make_shared<ModelSceneNode>(ModelSceneNode::Classification::Other, Models::instance().get("cghead_light"), &sceneGraph);
|
||||
|
||||
// Create a creature from the current portrait
|
||||
|
||||
|
|
|
@ -130,9 +130,9 @@ void MainMenu::setup3DView() {
|
|||
}
|
||||
|
||||
shared_ptr<ModelSceneNode> MainMenu::getKotorModel(SceneGraph &sceneGraph) {
|
||||
auto model = make_shared<ModelSceneNode>(&sceneGraph, Models::instance().get("mainmenu"));
|
||||
model->setLightingEnabled(true);
|
||||
auto model = make_shared<ModelSceneNode>(ModelSceneNode::Classification::Other, Models::instance().get("mainmenu"), &sceneGraph);
|
||||
model->animator().playAnimation("default", AnimationProperties::fromFlags(AnimationFlags::loop));
|
||||
|
||||
return move(model);
|
||||
}
|
||||
|
||||
|
|
|
@ -113,9 +113,8 @@ void Area::loadLYT() {
|
|||
|
||||
glm::vec3 position(lytRoom.position.x, lytRoom.position.y, lytRoom.position.z);
|
||||
|
||||
auto sceneNode = make_shared<ModelSceneNode>(&_game->sceneGraph(), model);
|
||||
auto sceneNode = make_shared<ModelSceneNode>(ModelSceneNode::Classification::Room, model, &_game->sceneGraph());
|
||||
sceneNode->setLocalTransform(glm::translate(glm::mat4(1.0f), position));
|
||||
sceneNode->setLightingEnabled(true);
|
||||
|
||||
for (auto &anim : model->getAnimationNames()) {
|
||||
if (boost::starts_with(anim, "animloop")) {
|
||||
|
|
|
@ -68,9 +68,7 @@ shared_ptr<ModelSceneNode> CreatureModelBuilder::build() {
|
|||
shared_ptr<Model> model(Models::instance().get(modelName, gr2Model ? ResourceType::Gr2 : ResourceType::Mdl));
|
||||
if (!model) return nullptr;
|
||||
|
||||
auto modelSceneNode = make_unique<ModelSceneNode>(&_creature->sceneGraph(), model);
|
||||
modelSceneNode->setLightingEnabled(true);
|
||||
|
||||
auto modelSceneNode = make_unique<ModelSceneNode>(ModelSceneNode::Classification::Creature, model, &_creature->sceneGraph());
|
||||
if (gr2Model) return move(modelSceneNode);
|
||||
|
||||
// Body texture
|
||||
|
@ -95,9 +93,9 @@ shared_ptr<ModelSceneNode> CreatureModelBuilder::build() {
|
|||
if (!headModelName.empty()) {
|
||||
shared_ptr<Model> headModel(Models::instance().get(headModelName));
|
||||
if (headModel) {
|
||||
shared_ptr<ModelSceneNode> headSceneNode(modelSceneNode->attach(g_headHookNode, headModel));
|
||||
shared_ptr<ModelSceneNode> headSceneNode(modelSceneNode->attach(g_headHookNode, headModel, ModelSceneNode::Classification::Creature));
|
||||
if (headSceneNode && maskModel) {
|
||||
headSceneNode->attach(g_maskHookNode, maskModel);
|
||||
headSceneNode->attach(g_maskHookNode, maskModel, ModelSceneNode::Classification::Equipment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +106,7 @@ shared_ptr<ModelSceneNode> CreatureModelBuilder::build() {
|
|||
if (!leftWeaponModelName.empty()) {
|
||||
shared_ptr<Model> leftWeaponModel(Models::instance().get(leftWeaponModelName));
|
||||
if (leftWeaponModel) {
|
||||
modelSceneNode->attach("lhand", leftWeaponModel);
|
||||
modelSceneNode->attach("lhand", leftWeaponModel, ModelSceneNode::Classification::Equipment);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +116,7 @@ shared_ptr<ModelSceneNode> CreatureModelBuilder::build() {
|
|||
if (!rightWeaponModelName.empty()) {
|
||||
shared_ptr<Model> rightWeaponModel(Models::instance().get(rightWeaponModelName));
|
||||
if (rightWeaponModel) {
|
||||
modelSceneNode->attach("rhand", rightWeaponModel);
|
||||
modelSceneNode->attach("rhand", rightWeaponModel, ModelSceneNode::Classification::Equipment);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,13 +78,11 @@ void Door::loadBlueprint(const GffStruct &gffs) {
|
|||
shared_ptr<DoorBlueprint> blueprint(Blueprints::instance().getDoor(resRef));
|
||||
blueprint->load(*this);
|
||||
|
||||
shared_ptr<TwoDaTable> table(Resources::instance().get2DA("genericdoors"));
|
||||
shared_ptr<TwoDaTable> genericDoors(Resources::instance().get2DA("genericdoors"));
|
||||
string modelName(boost::to_lower_copy(genericDoors->getString(_genericType, "modelname")));
|
||||
auto model = make_unique<ModelSceneNode>(ModelSceneNode::Classification::Door, Models::instance().get(modelName), _sceneGraph);
|
||||
|
||||
string modelName(boost::to_lower_copy(table->getString(_genericType, "modelname")));
|
||||
auto model = make_unique<ModelSceneNode>(_sceneGraph, Models::instance().get(modelName));
|
||||
model->setLightingEnabled(true);
|
||||
_sceneNode = move(model);
|
||||
|
||||
_walkmesh = Walkmeshes::instance().get(modelName + "0", ResourceType::Dwk);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,13 +80,11 @@ void Placeable::load(const shared_ptr<PlaceableBlueprint> &blueprint) {
|
|||
}
|
||||
blueprint->load(*this);
|
||||
|
||||
shared_ptr<TwoDaTable> table(Resources::instance().get2DA("placeables"));
|
||||
string modelName(boost::to_lower_copy(table->getString(_appearance, "modelname")));
|
||||
|
||||
auto model = make_shared<ModelSceneNode>(_sceneGraph, Models::instance().get(modelName));
|
||||
model->setLightingEnabled(true);
|
||||
_sceneNode = model;
|
||||
shared_ptr<TwoDaTable> placeables(Resources::instance().get2DA("placeables"));
|
||||
string modelName(boost::to_lower_copy(placeables->getString(_appearance, "modelname")));
|
||||
auto model = make_shared<ModelSceneNode>(ModelSceneNode::Classification::Placeable, Models::instance().get(modelName), _sceneGraph);
|
||||
|
||||
_sceneNode = move(model);
|
||||
_walkmesh = Walkmeshes::instance().get(modelName, ResourceType::Pwk);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,9 +26,10 @@ namespace reone {
|
|||
namespace render {
|
||||
|
||||
static unordered_map<Feature, bool> g_features {
|
||||
{ Feature::PBR, true },
|
||||
{ Feature::PBR, false },
|
||||
{ Feature::HDR, false },
|
||||
{ Feature::SelfIllumAsLights, false }
|
||||
{ Feature::SelfIllumAsLights, false },
|
||||
{ Feature::DynamicRoomLighting, false }
|
||||
};
|
||||
|
||||
bool isFeatureEnabled(Feature feature) {
|
||||
|
|
|
@ -24,7 +24,8 @@ namespace render {
|
|||
enum class Feature {
|
||||
PBR,
|
||||
HDR,
|
||||
SelfIllumAsLights
|
||||
SelfIllumAsLights,
|
||||
DynamicRoomLighting
|
||||
};
|
||||
|
||||
bool isFeatureEnabled(Feature feature);
|
||||
|
|
|
@ -90,7 +90,13 @@ bool ModelNodeSceneNode::shouldRender() const {
|
|||
|
||||
bool ModelNodeSceneNode::shouldCastShadows() const {
|
||||
shared_ptr<ModelMesh> mesh(_modelNode->mesh());
|
||||
return mesh && mesh->shouldCastShadows() && !static_cast<bool>(_modelNode->skin());
|
||||
if (!mesh) return false;
|
||||
|
||||
if (isFeatureEnabled(Feature::DynamicRoomLighting) && _modelSceneNode->classification() == ModelSceneNode::Classification::Room) {
|
||||
return mesh->shouldRender();
|
||||
}
|
||||
|
||||
return mesh->shouldCastShadows() && !static_cast<bool>(_modelNode->skin());
|
||||
}
|
||||
|
||||
bool ModelNodeSceneNode::isTransparent() const {
|
||||
|
@ -100,6 +106,32 @@ bool ModelNodeSceneNode::isTransparent() const {
|
|||
return mesh->isTransparent() || _modelNode->alpha() < 1.0f;
|
||||
}
|
||||
|
||||
static bool isLightingEnabled(ModelSceneNode::Classification clazz) {
|
||||
switch (clazz) {
|
||||
case ModelSceneNode::Classification::Room:
|
||||
return isFeatureEnabled(Feature::DynamicRoomLighting);
|
||||
|
||||
case ModelSceneNode::Classification::Creature:
|
||||
case ModelSceneNode::Classification::Door:
|
||||
case ModelSceneNode::Classification::Placeable:
|
||||
case ModelSceneNode::Classification::Other:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isReceivingShadows(ModelSceneNode::Classification clazz) {
|
||||
switch (clazz) {
|
||||
case ModelSceneNode::Classification::Room:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelNodeSceneNode::renderSingle(bool shadowPass) {
|
||||
shared_ptr<ModelMesh> mesh(_modelNode->mesh());
|
||||
if (!mesh) return;
|
||||
|
@ -141,7 +173,7 @@ void ModelNodeSceneNode::renderSingle(bool shadowPass) {
|
|||
}
|
||||
}
|
||||
|
||||
if (mesh->hasLightmapTexture()) {
|
||||
if (mesh->hasLightmapTexture() && !isFeatureEnabled(Feature::DynamicRoomLighting)) {
|
||||
uniforms.general.featureMask |= UniformFeatureFlags::lightmap;
|
||||
}
|
||||
|
||||
|
@ -155,10 +187,7 @@ void ModelNodeSceneNode::renderSingle(bool shadowPass) {
|
|||
uniforms.bumpmap.swizzled = mesh->isBumpmapSwizzled();
|
||||
}
|
||||
|
||||
bool receivesShadows =
|
||||
_modelSceneNode->model()->classification() == Model::Classification::Other &&
|
||||
!_modelNode->isSelfIllumEnabled();
|
||||
|
||||
bool receivesShadows = isReceivingShadows(_modelSceneNode->classification()) && !_modelNode->isSelfIllumEnabled();
|
||||
if (receivesShadows) {
|
||||
uniforms.general.featureMask |= UniformFeatureFlags::shadows;
|
||||
}
|
||||
|
@ -185,8 +214,8 @@ void ModelNodeSceneNode::renderSingle(bool shadowPass) {
|
|||
uniforms.general.featureMask |= UniformFeatureFlags::selfIllum;
|
||||
uniforms.general.selfIllumColor = glm::vec4(_modelNode->selfIllumColor(), 1.0f);
|
||||
}
|
||||
if (_modelSceneNode->isLightingEnabled() &&
|
||||
!mesh->hasLightmapTexture() &&
|
||||
if (isLightingEnabled(_modelSceneNode->classification()) &&
|
||||
(!mesh->hasLightmapTexture() || isFeatureEnabled(Feature::DynamicRoomLighting)) &&
|
||||
!_modelNode->isSelfIllumEnabled() &&
|
||||
(!diffuseTexture || !diffuseTexture->isAdditive())) {
|
||||
|
||||
|
|
|
@ -45,8 +45,9 @@ static constexpr int kSelfIlluminatedPriority = 5;
|
|||
|
||||
static bool g_drawAABB = false;
|
||||
|
||||
ModelSceneNode::ModelSceneNode(SceneGraph *sceneGraph, const shared_ptr<Model> &model, set<string> ignoreNodes) :
|
||||
ModelSceneNode::ModelSceneNode(Classification classification, const shared_ptr<Model> &model, SceneGraph *sceneGraph, set<string> ignoreNodes) :
|
||||
SceneNode(sceneGraph),
|
||||
_classification(classification),
|
||||
_model(model),
|
||||
_animator(this, ignoreNodes) {
|
||||
|
||||
|
@ -114,7 +115,7 @@ void ModelSceneNode::initModelNodes() {
|
|||
shared_ptr<ModelMesh> mesh(child->mesh());
|
||||
if (mesh) {
|
||||
glm::vec3 size(mesh->mesh()->aabb().getSize());
|
||||
radius = glm::dot(size, size);
|
||||
radius = glm::max(1.0f, glm::sqrt(glm::dot(size, size)));
|
||||
} else {
|
||||
radius = 1.0f;
|
||||
}
|
||||
|
@ -170,7 +171,7 @@ void ModelSceneNode::render() {
|
|||
}
|
||||
}
|
||||
|
||||
shared_ptr<ModelSceneNode> ModelSceneNode::attach(const string &parent, const shared_ptr<Model> &model) {
|
||||
shared_ptr<ModelSceneNode> ModelSceneNode::attach(const string &parent, const shared_ptr<Model> &model, ModelSceneNode::Classification classification) {
|
||||
ModelNodeSceneNode *parentNode = getModelNode(parent);
|
||||
if (!parentNode) return nullptr;
|
||||
|
||||
|
@ -187,8 +188,7 @@ shared_ptr<ModelSceneNode> ModelSceneNode::attach(const string &parent, const sh
|
|||
for (const ModelNode *node = parentModelNode; node; node = node->parent()) {
|
||||
ignoreNodes.insert(node->name());
|
||||
}
|
||||
auto modelNode = make_shared<ModelSceneNode>(_sceneGraph, model, ignoreNodes);
|
||||
modelNode->setLightingEnabled(_lightingEnabled);
|
||||
auto modelNode = make_shared<ModelSceneNode>(classification, model, _sceneGraph, ignoreNodes);
|
||||
parentNode->addChild(modelNode);
|
||||
|
||||
return _attachedModels.insert(make_pair(parentNumber, move(modelNode))).first->second;
|
||||
|
@ -244,7 +244,7 @@ void ModelSceneNode::updateAbsoluteTransform() {
|
|||
}
|
||||
|
||||
void ModelSceneNode::updateLighting() {
|
||||
if (!_lightingEnabled || !_lightingDirty) return;
|
||||
if (!_lightingDirty) return;
|
||||
|
||||
_lightsAffectedBy.clear();
|
||||
glm::vec3 center(_absoluteTransform * glm::vec4(_model->aabb().center(), 1.0f));
|
||||
|
@ -321,10 +321,6 @@ void ModelSceneNode::setProjectileSpeed(float speed) {
|
|||
_projectileSpeed = speed;
|
||||
}
|
||||
|
||||
void ModelSceneNode::setLightingEnabled(bool enabled) {
|
||||
_lightingEnabled = enabled;
|
||||
}
|
||||
|
||||
void ModelSceneNode::setLightsAffectedBy(const vector<LightSceneNode *> &lights) {
|
||||
_lightsAffectedBy = lights;
|
||||
}
|
||||
|
|
|
@ -38,15 +38,26 @@ class ModelNodeSceneNode;
|
|||
|
||||
class ModelSceneNode : public SceneNode {
|
||||
public:
|
||||
enum class Classification {
|
||||
Room,
|
||||
Creature,
|
||||
Placeable,
|
||||
Door,
|
||||
Equipment,
|
||||
Projectile,
|
||||
Other
|
||||
};
|
||||
|
||||
ModelSceneNode(
|
||||
SceneGraph *sceneGraph,
|
||||
Classification classification,
|
||||
const std::shared_ptr<render::Model> &model,
|
||||
SceneGraph *sceneGraph,
|
||||
std::set<std::string> ignoreNodes = std::set<std::string>());
|
||||
|
||||
void update(float dt) override;
|
||||
void render() override;
|
||||
|
||||
std::shared_ptr<ModelSceneNode> attach(const std::string &parent, const std::shared_ptr<render::Model> &model);
|
||||
std::shared_ptr<ModelSceneNode> attach(const std::string &parent, const std::shared_ptr<render::Model> &model, ModelSceneNode::Classification classification);
|
||||
void attach(const std::string &parent, const std::shared_ptr<SceneNode> &node);
|
||||
|
||||
void refreshAABB();
|
||||
|
@ -61,6 +72,7 @@ public:
|
|||
glm::vec3 getCenterOfAABB() const;
|
||||
const std::string &getName() const;
|
||||
|
||||
Classification classification() const { return _classification; }
|
||||
std::shared_ptr<render::Model> model() const { return _model; }
|
||||
std::shared_ptr<render::Texture> textureOverride() const { return _textureOverride; }
|
||||
float alpha() const { return _alpha; }
|
||||
|
@ -80,17 +92,17 @@ public:
|
|||
void updateLighting();
|
||||
void setLightingIsDirty();
|
||||
|
||||
bool isLightingEnabled() const { return _lightingEnabled; }
|
||||
const std::vector<LightSceneNode *> &lightsAffectedBy() const { return _lightsAffectedBy; }
|
||||
|
||||
void setLightingEnabled(bool affected);
|
||||
void setLightsAffectedBy(const std::vector<LightSceneNode *> &lights);
|
||||
|
||||
// END Dynamic lighting
|
||||
|
||||
private:
|
||||
Classification _classification;
|
||||
std::shared_ptr<render::Model> _model;
|
||||
SceneNodeAnimator _animator;
|
||||
|
||||
std::unordered_map<uint16_t, ModelNodeSceneNode *> _modelNodeByIndex;
|
||||
std::unordered_map<uint16_t, ModelNodeSceneNode *> _modelNodeByNumber;
|
||||
std::vector<std::shared_ptr<EmitterSceneNode>> _emitters;
|
||||
|
@ -99,15 +111,15 @@ private:
|
|||
bool _visible { true };
|
||||
bool _onScreen { true };
|
||||
float _alpha { 1.0f };
|
||||
bool _lightingEnabled { false };
|
||||
std::vector<LightSceneNode *> _lightsAffectedBy;
|
||||
bool _lightingDirty { true };
|
||||
AABB _aabb;
|
||||
float _projectileSpeed;
|
||||
|
||||
void initModelNodes();
|
||||
std::unique_ptr<ModelNodeSceneNode> getModelNodeSceneNode(render::ModelNode &node) const;
|
||||
void updateAbsoluteTransform() override;
|
||||
|
||||
std::unique_ptr<ModelNodeSceneNode> getModelNodeSceneNode(render::ModelNode &node) const;
|
||||
};
|
||||
|
||||
} // namespace scene
|
||||
|
|
Loading…
Reference in a new issue