Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visualiser: Support for keyframe-animated models. #904

Merged
merged 3 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/dependencies/flamegpu2-visualiser.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ cmake_policy(SET CMP0079 NEW)

# Set the visualiser repo and tag to use unless overridden by the user.
# @todo - If the git version has changed in this file, fetch again?
set(DEFAULT_VISUALISATION_GIT_VERSION "31cefa01020542528e199ec78a7cf2319a843009")
set(DEFAULT_VISUALISATION_GIT_VERSION "ef676da1daf8d8118bc7b2b75ede958c4f08afc9")
set(DEFAULT_VISUALISATION_REPOSITORY "https://github.com/FLAMEGPU/FLAMEGPU2-visualiser.git")

# If overridden by the user, attempt to use that
Expand Down
16 changes: 16 additions & 0 deletions include/flamegpu/visualiser/AgentStateVis.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ class AgentStateVis {
* @see Stock::Models::Model
*/
void setModel(const Stock::Models::Model &model);
/**
* Use a keyframe animated model from file
* @param modelPathA The path to the model's first file (must be .obj)
* @param modelPathB The path to the model's second file (must be .obj, have the same number of vertices/polygons as the first file)
* @param texturePath Optional path to the texture used by the two models
* @see setModel(const std::string &, const std::string &) This version can be used to provide agents a static model
* @note Lerp variable must be set first via AgentVis::setKeyFrameModel() otherwise an exception will be thrown.
*/
void setKeyFrameModel(const std::string& modelPathA, const std::string& modelPathB, const std::string& texturePath = "");
/**
* Use a stock keyframe animated model
* @param model Model from the libraries internal resources
* @see setModel(const Stock::Models::Model &) This version can be used to provide agents a static model
* @note Lerp variable must be set first via AgentVis::setKeyFrameModel() otherwise an exception will be thrown.
*/
void setKeyFrameModel(const Stock::Models::KeyFrameModel& model);
/**
* Scale each dimension of the model to the corresponding world scales
* @param xLen World scale of the model's on the x axis
Expand Down
16 changes: 16 additions & 0 deletions include/flamegpu/visualiser/AgentVis.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,22 @@ class AgentVis {
* @param model Model from the libraries internal resources
*/
void setModel(const Stock::Models::Model &model);
/**
* Use a keyframe animated model from file
* @param modelPathA The path to the model's first file (must be .obj)
* @param modelPathB The path to the model's second file (must be .obj, have the same number of vertices/polygons as the first file)
* @param lerpVariableName Name of the agent variable used for controlling linear interpolation between the two frames. This must be a `float` type variable with a value in the inclusive-inclusive range [0, 1]
* @param texturePath Optional path to the texture used by the two models
* @see setModel(const std::string &, const std::string &) This version can be used to provide agents a static model
*/
void setKeyFrameModel(const std::string& modelPathA, const std::string& modelPathB, const std::string& lerpVariableName, const std::string& texturePath = "");
/**
* Use a stock keyframe animated model
* @param model Model from the libraries internal resources
* @param lerpVariableName Name of the agent variable used for controlling linear interpolation between the two frames. This must be a `float` type variable with a value in the inclusive-inclusive range [0, 1]
* @see setModel(const Stock::Models::Model &) This version can be used to provide agents a static model
*/
void setKeyFrameModel(const Stock::Models::KeyFrameModel& model, const std::string& lerpVariableName);
/**
* Scale each dimension of the model to the corresponding world scales
* @param xLen World scale of the model's on the x axis
Expand Down
4 changes: 2 additions & 2 deletions src/flamegpu/io/XMLStateReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ int XMLStateReader::parse() {
it.second->reserve(f->second);
}

bool hasWarnedElements = false;
bool hasWarnedMissingVar = false;
// Read in agent data
for (pElement = pRoot->FirstChildElement("xagent"); pElement != nullptr; pElement = pElement->NextSiblingElement("xagent")) {
// Find agent name
Expand All @@ -289,8 +291,6 @@ int XMLStateReader::parse() {
// Create instance to store variable data in
agentVec->push_back();
AgentVector::Agent instance = agentVec->back();
bool hasWarnedElements = false;
bool hasWarnedMissingVar = false;
// Iterate agent variables
for (auto iter = agentVariables.begin(); iter != agentVariables.end(); ++iter) {
const std::string variable_name = iter->first;
Expand Down
16 changes: 16 additions & 0 deletions src/flamegpu/visualiser/AgentStateVis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ void AgentStateVis::setModel(const Stock::Models::Model &model) {
AgentStateConfig::setString(&config.model_path, model.modelPath);
configFlags.model_path = 1;
}
void AgentStateVis::setKeyFrameModel(const std::string& modelPathA, const std::string& modelPathB, const std::string& texturePath) {
if (parent.core_tex_buffers.find(TexBufferConfig::AnimationLerp) == parent.core_tex_buffers.end()) {
THROW exception::InvalidOperation("Unable to use AgentStateVis::setKeyFrameModel(), AgentVis::setKeyFrameModel()"
" must be called first to specify the lerp variable for all agent states.\n");
}
AgentStateConfig::setString(&config.model_path, modelPathA);
AgentStateConfig::setString(&config.model_pathB, modelPathB);
if (!texturePath.empty()) {
AgentStateConfig::setString(&config.model_texture, texturePath);
clearColor();
}
configFlags.model_path = 1;
}
void AgentStateVis::setKeyFrameModel(const Stock::Models::KeyFrameModel& model) {
setKeyFrameModel(model.modelPathA, model.modelPathB, model.texturePath ? model.texturePath : "");
}
void AgentStateVis::setModelScale(float xLen, float yLen, float zLen) {
if (xLen <= 0 || yLen <= 0 || zLen <= 0) {
THROW exception::InvalidArgument("AgentStateVis::setModelScale(): Invalid argument, lengths must all be positive.\n");
Expand Down
48 changes: 44 additions & 4 deletions src/flamegpu/visualiser/AgentVis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ AgentVis::AgentVis(CUDAAgent &_agent, const std::shared_ptr<AutoPalette>& autopa
: owned_auto_palette(nullptr)
, agent(_agent)
, agentData(_agent.getAgentDescription()) {
if (_agent.getAgentDescription().variables.find("x") != _agent.getAgentDescription().variables.end()) {
if (_agent.getAgentDescription().variables.find("x") != _agent.getAgentDescription().variables.end() &&
_agent.getAgentDescription().variables.at("x").type == std::type_index(typeid(float))) {
setXVariable("x");
}
if (_agent.getAgentDescription().variables.find("y") != _agent.getAgentDescription().variables.end()) {
if (_agent.getAgentDescription().variables.find("y") != _agent.getAgentDescription().variables.end() &&
_agent.getAgentDescription().variables.at("y").type == std::type_index(typeid(float))) {
setYVariable("y");
}
if (_agent.getAgentDescription().variables.find("z") != _agent.getAgentDescription().variables.end()) {
if (_agent.getAgentDescription().variables.find("z") != _agent.getAgentDescription().variables.end() &&
_agent.getAgentDescription().variables.at("z").type == std::type_index(typeid(float))) {
setZVariable("z");
}
if (autopalette) {
Expand Down Expand Up @@ -724,8 +727,10 @@ void AgentVis::setModel(const std::string &modelPath, const std::string &texture
}
void AgentVis::setModel(const Stock::Models::Model &model) {
AgentStateConfig::setString(&defaultConfig.model_path, model.modelPath);
if (model.texturePath && model.texturePath[0] != '\0')
if (model.texturePath && model.texturePath[0] != '\0') {
AgentStateConfig::setString(&defaultConfig.model_texture, model.texturePath);
clearColor();
}
// Apply to all states which haven't had the setting overridden
for (auto &s : states) {
if (!s.second.configFlags.model_path) {
Expand All @@ -735,6 +740,41 @@ void AgentVis::setModel(const Stock::Models::Model &model) {
}
}
}
void AgentVis::setKeyFrameModel(const std::string& modelPathA, const std::string& modelPathB, const std::string& lerpVariableName, const std::string& texturePath) {
auto it = agentData.variables.find(lerpVariableName);
if (it == agentData.variables.end()) {
THROW exception::InvalidAgentVar("Variable '%s' was not found within agent '%s', "
"in AgentVis::setKeyFrameModel()\n",
lerpVariableName.c_str(), agentData.name.c_str());
} else if (it->second.type != std::type_index(typeid(float)) || it->second.elements != 1) {
THROW exception::InvalidAgentVar("Visualisation animation lerp variable must be type float[1], agent '%s' variable '%s' is type %s[%u], "
"in AgentVis::setKeyFrameModel()\n",
agentData.name.c_str(), lerpVariableName.c_str(), it->second.type.name(), it->second.elements);
}
AgentStateConfig::setString(&defaultConfig.model_path, modelPathA);
AgentStateConfig::setString(&defaultConfig.model_pathB, modelPathB);
if (!texturePath.empty()) {
AgentStateConfig::setString(&defaultConfig.model_texture, texturePath);
clearColor();
}
core_tex_buffers.erase(TexBufferConfig::AnimationLerp);
core_tex_buffers[TexBufferConfig::AnimationLerp].agentVariableName = lerpVariableName;
// Apply to all states which haven't had the setting overridden
for (auto& s : states) {
if (!s.second.configFlags.model_path) {
AgentStateConfig::setString(&s.second.config.model_path, modelPathA);
AgentStateConfig::setString(&s.second.config.model_pathB, modelPathB);
if (!texturePath.empty()) {
AgentStateConfig::setString(&s.second.config.model_texture, texturePath);
// Clear colour in state
s.second.config.color_shader_src = "";
}
}
}
}
void AgentVis::setKeyFrameModel(const Stock::Models::KeyFrameModel& model, const std::string& lerpVariableName) {
setKeyFrameModel(model.modelPathA, model.modelPathB, lerpVariableName, model.texturePath ? model.texturePath : "");
}
void AgentVis::setModelScale(float xLen, float yLen, float zLen) {
if (xLen <= 0 || yLen <= 0 || zLen <= 0) {
THROW exception::InvalidArgument("AgentVis::setModelScale(): Invalid argument, lengths must all be positive.\n");
Expand Down