feat: Add feature toggle to enable dynamic room lighting

This commit is contained in:
Vsevolod Kremianskii 2021-02-15 18:18:25 +07:00
parent 3e68ee914b
commit 9c41c3432b
15 changed files with 86 additions and 54 deletions

View file

@ -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();

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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);
}

View file

@ -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")) {

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -24,7 +24,8 @@ namespace render {
enum class Feature {
PBR,
HDR,
SelfIllumAsLights
SelfIllumAsLights,
DynamicRoomLighting
};
bool isFeatureEnabled(Feature feature);

View file

@ -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())) {

View file

@ -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;
}

View file

@ -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