Merge pull request #14619 from SamGondelman/matTarget

Case 20240: Better material entity targeting
This commit is contained in:
Sam Gateau 2019-01-23 15:47:22 -08:00 committed by GitHub
commit 3ec9290dca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 22 deletions

View file

@ -841,10 +841,14 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {number} priority=0 - The priority for applying the material to its parent. Only the highest priority material is
* applied, with materials of the same priority randomly assigned. Materials that come with the model have a priority of
* <code>0</code>.
* @property {string|number} parentMaterialName="0" - Selects the submesh or submeshes within the parent to apply the material
* to. If in the format <code>"mat::string"</code>, all submeshes with material name <code>"string"</code> are replaced.
* Otherwise the property value is parsed as an unsigned integer, specifying the mesh index to modify. Invalid values are
* parsed to <code>0</code>.
* @property {string} parentMaterialName="0" - Selects the mesh part or parts within the parent to which to apply the material.
* If in the format <code>"mat::string"</code>, all mesh parts with material name <code>"string"</code> are replaced.
* Otherwise the property value is parsed as an unsigned integer, specifying the mesh part index to modify. If <code>"all"</code>,
* all mesh parts will be replaced. If an array (starts with <code>"["</code> and ends with <code>"]"</code>), the string will be
* split at each <code>","</code> and each element will be parsed as either a number or a string if it starts with
* <code>"mat::"</code>. In other words, <code>"[0,1,mat::string,mat::string2]"</code> will replace mesh parts 0 and 1, and any
* mesh parts with material <code>"string"</code> or <code>"string2"</code>. Do not put spaces around the commas. Invalid values
* are parsed to <code>0</code>.
* @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either <code>"uv"</code> or
* <code>"projected"</code>. In "uv" mode, the material will be evaluated within the UV space of the mesh it is applied to. In
* "projected" mode, the 3D transform of the Material Entity will be used to evaluate the texture coordinates for the material.

View file

@ -1486,29 +1486,56 @@ bool Model::isRenderable() const {
return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());
}
std::vector<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
// try to find all meshes with materials that match parentMaterialName as a string
// if none, return parentMaterialName as a uint
std::vector<unsigned int> toReturn;
const QString MATERIAL_NAME_PREFIX = "mat::";
if (parentMaterialName.startsWith(MATERIAL_NAME_PREFIX)) {
parentMaterialName.replace(0, MATERIAL_NAME_PREFIX.size(), QString(""));
for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) {
if (_modelMeshMaterialNames[i] == parentMaterialName.toStdString()) {
toReturn.push_back(i);
}
}
}
std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
std::set<unsigned int> toReturn;
if (toReturn.empty()) {
toReturn.push_back(parentMaterialName.toUInt());
const QString all("all");
if (parentMaterialName == all) {
for (unsigned int i = 0; i < (unsigned int)_modelMeshRenderItemIDs.size(); i++) {
toReturn.insert(i);
}
} else if (!parentMaterialName.isEmpty()) {
auto parseFunc = [this, &toReturn] (QString& target) {
if (target.isEmpty()) {
return;
}
// if target starts with "mat::", try to find all meshes with materials that match target as a string
// otherwise, return target as a uint
const QString MATERIAL_NAME_PREFIX("mat::");
if (target.startsWith(MATERIAL_NAME_PREFIX)) {
std::string targetStdString = target.replace(0, MATERIAL_NAME_PREFIX.size(), "").toStdString();
for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) {
if (_modelMeshMaterialNames[i] == targetStdString) {
toReturn.insert(i);
}
}
return;
}
toReturn.insert(target.toUInt());
};
if (parentMaterialName.length() > 2 && parentMaterialName.startsWith("[") && parentMaterialName.endsWith("]")) {
QStringList list = parentMaterialName.split(",", QString::SkipEmptyParts);
for (int i = 0; i < list.length(); i++) {
auto& target = list[i];
if (i == 0) {
target = target.replace(0, 1, "");
}
if (i == list.length() - 1) {
target = target.replace(target.length() - 1, 1, "");
}
parseFunc(target);
}
} else {
parseFunc(parentMaterialName);
}
}
return toReturn;
}
void Model::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
std::vector<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
std::set<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
render::Transaction transaction;
for (auto shapeID : shapeIDs) {
if (shapeID < _modelMeshRenderItemIDs.size()) {
@ -1531,7 +1558,7 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par
}
void Model::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
std::vector<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
std::set<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
render::Transaction transaction;
for (auto shapeID : shapeIDs) {
if (shapeID < _modelMeshRenderItemIDs.size()) {

View file

@ -513,7 +513,7 @@ private:
void calculateTextureInfo();
std::vector<unsigned int> getMeshIDsFromMaterialID(QString parentMaterialName);
std::set<unsigned int> getMeshIDsFromMaterialID(QString parentMaterialName);
};
Q_DECLARE_METATYPE(ModelPointer)