Merge pull request #12515 from SamGondelman/scriptableMaterials

Material reflection
This commit is contained in:
Sam Gondelman 2018-03-07 14:29:31 -08:00 committed by GitHub
commit f51a35455a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 311 additions and 22 deletions

View file

@ -681,5 +681,9 @@ scriptable::ScriptableModelBase ModelOverlay::getScriptableModel() {
}
auto result = _model->getScriptableModel();
result.objectID = getID();
{
std::lock_guard<std::mutex> lock(_materialsLock);
result.appendMaterials(_materials);
}
return result;
}

View file

@ -1801,5 +1801,9 @@ scriptable::ScriptableModelBase Avatar::getScriptableModel() {
}
auto result = _skeletonModel->getScriptableModel();
result.objectID = getSessionUUID().isNull() ? AVATAR_SELF_ID : getSessionUUID();
{
std::lock_guard<std::mutex> lock(_materialsLock);
result.appendMaterials(_materials);
}
return result;
}

View file

@ -974,6 +974,10 @@ scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScript
auto result = _model->getScriptableModel();
result.objectID = getEntity()->getID();
{
std::lock_guard<std::mutex> lock(_materialsLock);
result.appendMaterials(_materials);
}
return result;
}

View file

@ -169,8 +169,12 @@ scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel() {
auto geometryCache = DependencyManager::get<GeometryCache>();
auto geometryShape = geometryCache->getShapeForEntityShape(_shape);
glm::vec3 vertexColor;
if (_materials["0"].top().material) {
vertexColor = _materials["0"].top().material->getAlbedo();
{
std::lock_guard<std::mutex> lock(_materialsLock);
result.appendMaterials(_materials);
if (_materials["0"].top().material) {
vertexColor = _materials["0"].top().material->getAlbedo();
}
}
if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) {
result.objectID = getEntity()->getID();

View file

@ -868,16 +868,6 @@ void SphericalHarmonics::evalFromTexture(const Texture& texture) {
// TextureSource
TextureSource::TextureSource() {
}
TextureSource::~TextureSource() {
}
void TextureSource::reset(const QUrl& url) {
_imageUrl = url;
}
void TextureSource::resetTexture(gpu::TexturePointer texture) {
_gpuTexture = texture;
}

View file

@ -647,13 +647,11 @@ typedef std::vector<TextureView> TextureViews;
// It provides the mechanism to create a texture using a customizable TextureLoader
class TextureSource {
public:
TextureSource();
~TextureSource();
TextureSource(const QUrl& url, int type = 0) : _imageUrl(url), _type(type) {}
const QUrl& getUrl() const { return _imageUrl; }
const gpu::TexturePointer getGPUTexture() const { return _gpuTexture; }
void reset(const QUrl& url);
int getType() const { return _type; }
void resetTexture(gpu::TexturePointer texture);
@ -662,6 +660,7 @@ public:
protected:
gpu::TexturePointer _gpuTexture;
QUrl _imageUrl;
int _type { 0 };
};
typedef std::shared_ptr< TextureSource > TextureSourcePointer;

View file

@ -1,4 +1,4 @@
set(TARGET_NAME graphics-scripting)
setup_hifi_library()
link_hifi_libraries(shared networking graphics fbx model-networking script-engine)
link_hifi_libraries(shared networking graphics fbx image model-networking script-engine)
include_hifi_library_headers(gpu)

View file

@ -6,9 +6,14 @@
#include <QtCore/QUuid>
#include <QPointer>
#include <memory>
#include <unordered_map>
#include <DependencyManager.h>
#include <SpatiallyNestable.h>
#include "graphics/Material.h"
#include "graphics/TextureMap.h"
namespace graphics {
class Mesh;
}
@ -31,6 +36,53 @@ namespace scriptable {
using ModelProviderPointer = std::shared_ptr<scriptable::ModelProvider>;
using WeakModelProviderPointer = std::weak_ptr<scriptable::ModelProvider>;
class ScriptableMaterial {
public:
ScriptableMaterial() {}
ScriptableMaterial(const graphics::MaterialPointer& material);
ScriptableMaterial(const ScriptableMaterial& material) { *this = material; }
ScriptableMaterial& operator=(const ScriptableMaterial& material);
QString name;
QString model;
float opacity;
float roughness;
float metallic;
float scattering;
bool unlit;
glm::vec3 emissive;
glm::vec3 albedo;
QString emissiveMap;
QString albedoMap;
QString opacityMap;
QString metallicMap;
QString specularMap;
QString roughnessMap;
QString glossMap;
QString normalMap;
QString bumpMap;
QString occlusionMap;
QString lightmapMap;
QString scatteringMap;
};
/**jsdoc
* @typedef {object} Graphics.MaterialLayer
* @property {Material} material - This layer's material.
* @property {number} priority - The priority of this layer. If multiple materials are applied to a mesh part, only the highest priority layer is used.
*/
class ScriptableMaterialLayer {
public:
ScriptableMaterialLayer() {}
ScriptableMaterialLayer(const graphics::MaterialLayer& materialLayer) : material(materialLayer.material), priority(materialLayer.priority) {}
ScriptableMaterialLayer(const ScriptableMaterialLayer& materialLayer) { *this = materialLayer; }
ScriptableMaterialLayer& operator=(const ScriptableMaterialLayer& materialLayer);
ScriptableMaterial material;
quint16 priority;
};
typedef QHash<QString, QVector<scriptable::ScriptableMaterialLayer>> MultiMaterialMap;
class ScriptableMeshBase : public QObject {
Q_OBJECT
public:
@ -55,6 +107,8 @@ namespace scriptable {
WeakModelProviderPointer provider;
QUuid objectID; // spatially nestable ID
QVector<scriptable::ScriptableMeshBase> meshes;
MultiMaterialMap materialLayers;
QVector<QString> materialNames;
ScriptableModelBase(QObject* parent = nullptr) : QObject(parent) {}
ScriptableModelBase(const ScriptableModelBase& other) : QObject(other.parent()) { *this = other; }
@ -63,9 +117,11 @@ namespace scriptable {
void append(const ScriptableMeshBase& mesh);
void append(scriptable::WeakMeshPointer mesh);
void appendMaterial(const graphics::MaterialLayer& materialLayer, int shapeID, std::string materialName);
void appendMaterials(const std::unordered_map<std::string, graphics::MultiMaterial>& materialsToAppend);
void appendMaterialNames(const std::vector<std::string>& names);
// TODO: in future containers for these could go here
// QVariantMap shapes;
// QVariantMap materials;
// QVariantMap armature;
};

View file

@ -297,6 +297,10 @@ namespace {
qRegisterMetaType<scriptable::ScriptableMeshPointer>(),
qRegisterMetaType<scriptable::ScriptableModelPointer>(),
qRegisterMetaType<scriptable::ScriptableMeshPartPointer>(),
qRegisterMetaType<scriptable::ScriptableMaterial>(),
qRegisterMetaType<scriptable::ScriptableMaterialLayer>(),
qRegisterMetaType<QVector<scriptable::ScriptableMaterialLayer>>(),
qRegisterMetaType<scriptable::MultiMaterialMap>(),
qRegisterMetaType<graphics::Mesh::Topology>(),
};
}
@ -335,6 +339,67 @@ namespace scriptable {
);
}
QScriptValue qVectorScriptableMaterialLayerToScriptValue(QScriptEngine* engine, const QVector<scriptable::ScriptableMaterialLayer>& vector) {
return qScriptValueFromSequence(engine, vector);
}
void qVectorScriptableMaterialLayerFromScriptValue(const QScriptValue& array, QVector<scriptable::ScriptableMaterialLayer>& result) {
qScriptValueToSequence(array, result);
}
QScriptValue scriptableMaterialToScriptValue(QScriptEngine* engine, const scriptable::ScriptableMaterial &material) {
QScriptValue obj = engine->newObject();
obj.setProperty("name", material.name);
obj.setProperty("model", material.model);
obj.setProperty("opacity", material.opacity);
obj.setProperty("roughness", material.roughness);
obj.setProperty("metallic", material.metallic);
obj.setProperty("scattering", material.scattering);
obj.setProperty("unlit", material.unlit);
obj.setProperty("emissive", vec3toScriptValue(engine, material.emissive));
obj.setProperty("albedo", vec3toScriptValue(engine, material.albedo));
obj.setProperty("emissiveMap", material.emissiveMap);
obj.setProperty("albedoMap", material.albedoMap);
obj.setProperty("opacityMap", material.opacityMap);
obj.setProperty("metallicMap", material.metallicMap);
obj.setProperty("specularMap", material.specularMap);
obj.setProperty("roughnessMap", material.roughnessMap);
obj.setProperty("glossMap", material.glossMap);
obj.setProperty("normalMap", material.normalMap);
obj.setProperty("bumpMap", material.bumpMap);
obj.setProperty("occlusionMap", material.occlusionMap);
obj.setProperty("lightmapMap", material.lightmapMap);
obj.setProperty("scatteringMap", material.scatteringMap);
return obj;
}
void scriptableMaterialFromScriptValue(const QScriptValue &object, scriptable::ScriptableMaterial& material) {
// No need to convert from QScriptValue to ScriptableMaterial
}
QScriptValue scriptableMaterialLayerToScriptValue(QScriptEngine* engine, const scriptable::ScriptableMaterialLayer &materialLayer) {
QScriptValue obj = engine->newObject();
obj.setProperty("material", scriptableMaterialToScriptValue(engine, materialLayer.material));
obj.setProperty("priority", materialLayer.priority);
return obj;
}
void scriptableMaterialLayerFromScriptValue(const QScriptValue &object, scriptable::ScriptableMaterialLayer& materialLayer) {
// No need to convert from QScriptValue to ScriptableMaterialLayer
}
QScriptValue multiMaterialMapToScriptValue(QScriptEngine* engine, const scriptable::MultiMaterialMap& map) {
QScriptValue obj = engine->newObject();
for (auto key : map.keys()) {
obj.setProperty(key, qVectorScriptableMaterialLayerToScriptValue(engine, map[key]));
}
return obj;
}
void multiMaterialMapFromScriptValue(const QScriptValue& map, scriptable::MultiMaterialMap& result) {
// No need to convert from QScriptValue to MultiMaterialMap
}
template <typename T> int registerDebugEnum(QScriptEngine* engine, const DebugEnums<T>& debugEnums) {
static const DebugEnums<T>& instance = debugEnums;
return qScriptRegisterMetaType<T>(
@ -351,6 +416,7 @@ namespace scriptable {
void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterSequenceMetaType<QVector<glm::uint32>>(engine);
qScriptRegisterSequenceMetaType<QVector<scriptable::ScriptableMaterialLayer>>(engine);
scriptable::registerQPointerMetaType<scriptable::ScriptableModel>(engine);
scriptable::registerQPointerMetaType<scriptable::ScriptableMesh>(engine);
@ -361,6 +427,11 @@ void GraphicsScriptingInterface::registerMetaTypes(QScriptEngine* engine) {
scriptable::registerDebugEnum<gpu::Semantic>(engine, gpu::SEMANTICS);
scriptable::registerDebugEnum<gpu::Dimension>(engine, gpu::DIMENSIONS);
qScriptRegisterMetaType(engine, scriptable::scriptableMaterialToScriptValue, scriptable::scriptableMaterialFromScriptValue);
qScriptRegisterMetaType(engine, scriptable::scriptableMaterialLayerToScriptValue, scriptable::scriptableMaterialLayerFromScriptValue);
qScriptRegisterMetaType(engine, scriptable::qVectorScriptableMaterialLayerToScriptValue, scriptable::qVectorScriptableMaterialLayerFromScriptValue);
qScriptRegisterMetaType(engine, scriptable::multiMaterialMapToScriptValue, scriptable::multiMaterialMapFromScriptValue);
Q_UNUSED(metaTypeIds);
}

View file

@ -400,6 +400,5 @@ scriptable::ScriptableMesh::~ScriptableMesh() {
strongMesh.reset();
}
#include "ScriptableMesh.moc"

View file

@ -14,14 +14,120 @@
#include <QtScript/QScriptEngine>
#include "graphics/Material.h"
#include "image/Image.h"
// #define SCRIPTABLE_MESH_DEBUG 1
scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const scriptable::ScriptableMaterial& material) {
name = material.name;
model = material.model;
opacity = material.opacity;
roughness = material.roughness;
metallic = material.metallic;
scattering = material.scattering;
unlit = material.unlit;
emissive = material.emissive;
albedo = material.albedo;
emissiveMap = material.emissiveMap;
albedoMap = material.albedoMap;
opacityMap = material.opacityMap;
metallicMap = material.metallicMap;
specularMap = material.specularMap;
roughnessMap = material.roughnessMap;
glossMap = material.glossMap;
normalMap = material.normalMap;
bumpMap = material.bumpMap;
occlusionMap = material.occlusionMap;
lightmapMap = material.lightmapMap;
scatteringMap = material.scatteringMap;
return *this;
}
scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPointer& material) :
name(material->getName().c_str()),
model(material->getModel().c_str()),
opacity(material->getOpacity()),
roughness(material->getRoughness()),
metallic(material->getMetallic()),
scattering(material->getScattering()),
unlit(material->isUnlit()),
emissive(material->getEmissive()),
albedo(material->getAlbedo())
{
auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP);
if (map && map->getTextureSource()) {
emissiveMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::ALBEDO_MAP);
if (map && map->getTextureSource()) {
albedoMap = map->getTextureSource()->getUrl().toString();
if (map->useAlphaChannel()) {
opacityMap = albedoMap;
}
}
map = material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP);
if (map && map->getTextureSource()) {
if (map->getTextureSource()->getType() == image::TextureUsage::Type::METALLIC_TEXTURE) {
metallicMap = map->getTextureSource()->getUrl().toString();
} else if (map->getTextureSource()->getType() == image::TextureUsage::Type::SPECULAR_TEXTURE) {
specularMap = map->getTextureSource()->getUrl().toString();
}
}
map = material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP);
if (map && map->getTextureSource()) {
if (map->getTextureSource()->getType() == image::TextureUsage::Type::ROUGHNESS_TEXTURE) {
roughnessMap = map->getTextureSource()->getUrl().toString();
} else if (map->getTextureSource()->getType() == image::TextureUsage::Type::GLOSS_TEXTURE) {
glossMap = map->getTextureSource()->getUrl().toString();
}
}
map = material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP);
if (map && map->getTextureSource()) {
if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) {
normalMap = map->getTextureSource()->getUrl().toString();
} else if (map->getTextureSource()->getType() == image::TextureUsage::Type::BUMP_TEXTURE) {
bumpMap = map->getTextureSource()->getUrl().toString();
}
}
map = material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP);
if (map && map->getTextureSource()) {
occlusionMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::LIGHTMAP_MAP);
if (map && map->getTextureSource()) {
lightmapMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP);
if (map && map->getTextureSource()) {
scatteringMap = map->getTextureSource()->getUrl().toString();
}
}
scriptable::ScriptableMaterialLayer& scriptable::ScriptableMaterialLayer::operator=(const scriptable::ScriptableMaterialLayer& materialLayer) {
material = materialLayer.material;
priority = materialLayer.priority;
return *this;
}
scriptable::ScriptableModelBase& scriptable::ScriptableModelBase::operator=(const scriptable::ScriptableModelBase& other) {
provider = other.provider;
objectID = other.objectID;
for (const auto& mesh : other.meshes) {
append(mesh);
}
materialLayers = other.materialLayers;
materialNames = other.materialNames;
return *this;
}
@ -34,6 +140,8 @@ scriptable::ScriptableModelBase::~ScriptableModelBase() {
m.strongMesh.reset();
}
meshes.clear();
materialLayers.clear();
materialNames.clear();
}
void scriptable::ScriptableModelBase::append(scriptable::WeakMeshPointer mesh) {
@ -47,6 +155,27 @@ void scriptable::ScriptableModelBase::append(const ScriptableMeshBase& mesh) {
meshes << mesh;
}
void scriptable::ScriptableModelBase::appendMaterial(const graphics::MaterialLayer& materialLayer, int shapeID, std::string materialName) {
materialLayers[QString::number(shapeID)].push_back(ScriptableMaterialLayer(materialLayer));
materialLayers["mat::" + QString::fromStdString(materialName)].push_back(ScriptableMaterialLayer(materialLayer));
}
void scriptable::ScriptableModelBase::appendMaterials(const std::unordered_map<std::string, graphics::MultiMaterial>& materialsToAppend) {
auto materialsToAppendCopy = materialsToAppend;
for (auto& multiMaterial : materialsToAppendCopy) {
while (!multiMaterial.second.empty()) {
materialLayers[QString(multiMaterial.first.c_str())].push_back(ScriptableMaterialLayer(multiMaterial.second.top()));
multiMaterial.second.pop();
}
}
}
void scriptable::ScriptableModelBase::appendMaterialNames(const std::vector<std::string>& names) {
for (auto& name : names) {
materialNames.append(QString::fromStdString(name));
}
}
QString scriptable::ScriptableModel::toString() const {
return QString("[ScriptableModel%1%2 numMeshes=%3]")
.arg(objectID.isNull() ? "" : " objectID="+objectID.toString())

View file

@ -21,6 +21,8 @@ namespace scriptable {
* @property {Uuid} objectID - UUID of corresponding inworld object (if model is associated)
* @property {number} numMeshes - The number of submeshes contained in the model.
* @property {Graphics.Mesh[]} meshes - Array of submesh references.
* @property {Object.<string, Graphics.MaterialLayer[]>} materialLayers - Map of materials layer lists. You can look up a material layer list by mesh part number or by material name.
* @property {string[]} materialNames - Array of all the material names used by the mesh parts of this model, in order (e.g. materialNames[0] is the name of the first mesh part's material).
*/
class ScriptableModel : public ScriptableModelBase {
@ -28,18 +30,24 @@ namespace scriptable {
Q_PROPERTY(QUuid objectID MEMBER objectID CONSTANT)
Q_PROPERTY(glm::uint32 numMeshes READ getNumMeshes)
Q_PROPERTY(ScriptableMeshes meshes READ getMeshes)
Q_PROPERTY(scriptable::MultiMaterialMap materialLayers READ getMaterialLayers)
Q_PROPERTY(QVector<QString> materialNames READ getMaterialNames)
public:
ScriptableModel(QObject* parent = nullptr) : ScriptableModelBase(parent) {}
ScriptableModel(const ScriptableModel& other) : ScriptableModelBase(other) {}
ScriptableModel(const ScriptableModelBase& other) : ScriptableModelBase(other) {}
ScriptableModel& operator=(const ScriptableModelBase& view) { ScriptableModelBase::operator=(view); return *this; }
operator scriptable::ScriptableModelBasePointer() {
return QPointer<scriptable::ScriptableModelBase>(qobject_cast<scriptable::ScriptableModelBase*>(this));
}
ScriptableMeshes getMeshes();
const ScriptableMeshes getConstMeshes() const;
scriptable::MultiMaterialMap getMaterialLayers() { return materialLayers; }
QVector<QString> getMaterialNames() { return materialNames; }
public slots:
scriptable::ScriptableModelPointer cloneModel(const QVariantMap& options = QVariantMap());
QString toString() const;
@ -53,3 +61,6 @@ namespace scriptable {
Q_DECLARE_METATYPE(scriptable::ScriptableModelPointer)
Q_DECLARE_METATYPE(QVector<scriptable::ScriptableModelPointer>)
Q_DECLARE_METATYPE(scriptable::ScriptableMaterial)
Q_DECLARE_METATYPE(scriptable::ScriptableMaterialLayer)
Q_DECLARE_METATYPE(scriptable::MultiMaterialMap)

View file

@ -356,8 +356,9 @@ public:
void setTextureTransforms(const Transform& transform);
const std::string& getName() { return _name; }
const std::string& getName() const { return _name; }
const std::string& getModel() const { return _model; }
void setModel(const std::string& model) { _model = model; }
protected:

View file

@ -11,6 +11,8 @@
#include "QJsonDocument"
#include "QJsonArray"
#include "RegisteredMetaTypes.h"
NetworkMaterialResource::NetworkMaterialResource(const QUrl& url) :
Resource(url) {}
@ -39,6 +41,11 @@ bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3&
color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble());
return true;
}
} else if (array.isObject()) {
bool toReturn;
isSRGB = true;
color = vec3FromVariant(array.toObject(), toReturn);
return toReturn;
}
return false;
}

View file

@ -294,7 +294,7 @@ _type(),
_sourceIsKTX(false),
_maxNumPixels(100)
{
_textureSource = std::make_shared<gpu::TextureSource>();
_textureSource = std::make_shared<gpu::TextureSource>(url);
_lowestRequestedMipLevel = 0;
_loaded = true;
}
@ -310,7 +310,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, image::TextureUsage::Type type,
_sourceIsKTX(url.path().endsWith(".ktx")),
_maxNumPixels(maxNumPixels)
{
_textureSource = std::make_shared<gpu::TextureSource>();
_textureSource = std::make_shared<gpu::TextureSource>(url, (int)type);
_lowestRequestedMipLevel = 0;
_shouldFailOnRedirect = !_sourceIsKTX;

View file

@ -62,6 +62,7 @@ void CauterizedModel::createVisibleRenderItemSet() {
Q_ASSERT(_modelMeshRenderItems.isEmpty());
_modelMeshRenderItems.clear();
_modelMeshMaterialNames.clear();
_modelMeshRenderItemShapes.clear();
Transform transform;
@ -86,6 +87,7 @@ void CauterizedModel::createVisibleRenderItemSet() {
for (int partIndex = 0; partIndex < numParts; partIndex++) {
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
_modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName());
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
shapeID++;
}

View file

@ -684,12 +684,20 @@ scriptable::ScriptableModelBase Model::getScriptableModel() {
const FBXGeometry& geometry = getFBXGeometry();
int numberOfMeshes = geometry.meshes.size();
int shapeID = 0;
for (int i = 0; i < numberOfMeshes; i++) {
const FBXMesh& fbxMesh = geometry.meshes.at(i);
if (auto mesh = fbxMesh._mesh) {
result.append(mesh);
int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) {
result.appendMaterial(graphics::MaterialLayer(getGeometry()->getShapeMaterial(shapeID), 0), shapeID, _modelMeshMaterialNames[shapeID]);
shapeID++;
}
}
}
result.appendMaterialNames(_modelMeshMaterialNames);
return result;
}