mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-10 07:57:27 +02:00
Merge pull request #14656 from SamGondelman/matFallthrough
Case 20241: Material entity fallthrough
This commit is contained in:
commit
d92d256cfc
14 changed files with 1074 additions and 509 deletions
|
@ -42,10 +42,23 @@ ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Pare
|
|||
// TODO: move into Procedural.cpp
|
||||
PrepareStencil::testMaskDrawShape(*_procedural._opaqueState);
|
||||
PrepareStencil::testMask(*_procedural._transparentState);
|
||||
|
||||
addMaterial(graphics::MaterialLayer(_material, 0), "0");
|
||||
}
|
||||
|
||||
bool ShapeEntityRenderer::needsRenderUpdate() const {
|
||||
if (_procedural.isEnabled() && _procedural.isFading()) {
|
||||
if (resultWithReadLock<bool>([&] {
|
||||
if (_procedural.isEnabled() && _procedural.isFading()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.needsUpdate()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -56,7 +69,11 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
|||
if (_lastUserData != entity->getUserData()) {
|
||||
return true;
|
||||
}
|
||||
if (_material != entity->getMaterial()) {
|
||||
|
||||
if (_color != entity->getColor()) {
|
||||
return true;
|
||||
}
|
||||
if (_alpha != entity->getAlpha()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -79,10 +96,6 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
_procedural.setProceduralData(ProceduralData::parse(_lastUserData));
|
||||
}
|
||||
|
||||
removeMaterial(_material, "0");
|
||||
_material = entity->getMaterial();
|
||||
addMaterial(graphics::MaterialLayer(_material, 0), "0");
|
||||
|
||||
_shape = entity->getShape();
|
||||
});
|
||||
|
||||
|
@ -111,6 +124,20 @@ void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
|||
_procedural.setIsFading(isFading);
|
||||
}
|
||||
});
|
||||
|
||||
glm::u8vec3 color = entity->getColor();
|
||||
float alpha = entity->getAlpha();
|
||||
if (_color != color || _alpha != alpha) {
|
||||
_color = color;
|
||||
_alpha = alpha;
|
||||
_material->setAlbedo(toGlm(_color));
|
||||
_material->setOpacity(_alpha);
|
||||
|
||||
auto materials = _materials.find("0");
|
||||
if (materials != _materials.end()) {
|
||||
materials->second.setNeedsUpdate(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ShapeEntityRenderer::isTransparent() const {
|
||||
|
@ -120,18 +147,15 @@ bool ShapeEntityRenderer::isTransparent() const {
|
|||
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end()) {
|
||||
if (mat->second.top().material) {
|
||||
auto matKey = mat->second.top().material->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
return true;
|
||||
}
|
||||
if (mat->second.getMaterialKey().isTranslucent()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Parent::isTransparent();
|
||||
}
|
||||
|
||||
bool ShapeEntityRenderer::useMaterialPipeline() const {
|
||||
bool ShapeEntityRenderer::useMaterialPipeline(const graphics::MultiMaterial& materials) const {
|
||||
bool proceduralReady = resultWithReadLock<bool>([&] {
|
||||
return _procedural.isReady();
|
||||
});
|
||||
|
@ -139,12 +163,7 @@ bool ShapeEntityRenderer::useMaterialPipeline() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.top().material) {
|
||||
drawMaterialKey = mat->second.top().material->getKey();
|
||||
}
|
||||
|
||||
graphics::MaterialKey drawMaterialKey = materials.getMaterialKey();
|
||||
if (drawMaterialKey.isEmissive() || drawMaterialKey.isUnlit() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -159,11 +178,13 @@ bool ShapeEntityRenderer::useMaterialPipeline() const {
|
|||
}
|
||||
|
||||
ShapeKey ShapeEntityRenderer::getShapeKey() {
|
||||
if (useMaterialPipeline()) {
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
if (_materials["0"].top().material) {
|
||||
drawMaterialKey = _materials["0"].top().material->getKey();
|
||||
}
|
||||
auto mat = _materials.find("0");
|
||||
if (mat != _materials.end() && mat->second.needsUpdate()) {
|
||||
RenderPipelines::updateMultiMaterial(mat->second);
|
||||
}
|
||||
|
||||
if (mat != _materials.end() && useMaterialPipeline(mat->second)) {
|
||||
graphics::MaterialKey drawMaterialKey = mat->second.getMaterialKey();
|
||||
|
||||
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||
bool hasTangents = drawMaterialKey.isNormalMap();
|
||||
|
@ -216,7 +237,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
std::shared_ptr<graphics::Material> mat;
|
||||
graphics::MultiMaterial materials;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
GeometryCache::Shape geometryShape;
|
||||
bool proceduralRender = false;
|
||||
|
@ -224,29 +245,24 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
withReadLock([&] {
|
||||
geometryShape = geometryCache->getShapeForEntityShape(_shape);
|
||||
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
|
||||
mat = _materials["0"].top().material;
|
||||
if (mat) {
|
||||
outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity());
|
||||
if (_procedural.isReady()) {
|
||||
outColor = _procedural.getColor(outColor);
|
||||
outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f;
|
||||
_procedural.prepare(batch, _position, _dimensions, _orientation, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
proceduralRender = true;
|
||||
}
|
||||
materials = _materials["0"];
|
||||
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||
outColor = glm::vec4(schema._albedo, schema._opacity);
|
||||
if (_procedural.isReady()) {
|
||||
outColor = _procedural.getColor(outColor);
|
||||
outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f;
|
||||
_procedural.prepare(batch, _position, _dimensions, _orientation, ProceduralProgramKey(outColor.a < 1.0f));
|
||||
proceduralRender = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!mat) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (proceduralRender) {
|
||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
|
||||
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
||||
} else {
|
||||
geometryCache->renderShape(batch, geometryShape, outColor);
|
||||
}
|
||||
} else if (!useMaterialPipeline()) {
|
||||
} else if (!useMaterialPipeline(materials)) {
|
||||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
render::ShapePipelinePointer pipeline;
|
||||
|
@ -262,7 +278,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
|||
}
|
||||
} else {
|
||||
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
|
||||
RenderPipelines::bindMaterial(mat, batch, args->_enableTexturing);
|
||||
RenderPipelines::bindMaterials(materials, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
|
@ -281,8 +297,9 @@ scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel() {
|
|||
{
|
||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||
result.appendMaterials(_materials);
|
||||
if (_materials["0"].top().material) {
|
||||
vertexColor = _materials["0"].top().material->getAlbedo();
|
||||
auto materials = _materials.find("0");
|
||||
if (materials != _materials.end()) {
|
||||
vertexColor = materials->second.getSchemaBuffer().get<graphics::MultiMaterial::Schema>()._albedo;
|
||||
}
|
||||
}
|
||||
if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) {
|
||||
|
|
|
@ -35,12 +35,14 @@ private:
|
|||
virtual void doRender(RenderArgs* args) override;
|
||||
virtual bool isTransparent() const override;
|
||||
|
||||
bool useMaterialPipeline() const;
|
||||
bool useMaterialPipeline(const graphics::MultiMaterial& materials) const;
|
||||
|
||||
Procedural _procedural;
|
||||
QString _lastUserData;
|
||||
entity::Shape _shape { entity::Sphere };
|
||||
std::shared_ptr<graphics::Material> _material;
|
||||
std::shared_ptr<graphics::Material> _material { std::make_shared<graphics::Material>() };
|
||||
glm::u8vec3 _color;
|
||||
float _alpha;
|
||||
glm::vec3 _position;
|
||||
glm::vec3 _dimensions;
|
||||
glm::quat _orientation;
|
||||
|
|
|
@ -112,7 +112,6 @@ EntityItemPointer ShapeEntityItem::sphereFactory(const EntityItemID& entityID, c
|
|||
ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
|
||||
_type = EntityTypes::Shape;
|
||||
_volumeMultiplier *= PI / 6.0f;
|
||||
_material = std::make_shared<graphics::Material>();
|
||||
}
|
||||
|
||||
EntityItemProperties ShapeEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const {
|
||||
|
@ -215,7 +214,6 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
void ShapeEntityItem::setColor(const glm::u8vec3& value) {
|
||||
withWriteLock([&] {
|
||||
_color = value;
|
||||
_material->setAlbedo(toGlm(_color));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -228,7 +226,6 @@ glm::u8vec3 ShapeEntityItem::getColor() const {
|
|||
void ShapeEntityItem::setAlpha(float alpha) {
|
||||
withWriteLock([&] {
|
||||
_alpha = alpha;
|
||||
_material->setOpacity(alpha);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -99,8 +99,6 @@ public:
|
|||
virtual void computeShapeInfo(ShapeInfo& info) override;
|
||||
virtual ShapeType getShapeType() const override;
|
||||
|
||||
std::shared_ptr<graphics::Material> getMaterial() { return _material; }
|
||||
|
||||
protected:
|
||||
glm::u8vec3 _color;
|
||||
float _alpha { 1.0f };
|
||||
|
@ -110,8 +108,6 @@ protected:
|
|||
//! prior functionality where new or unsupported shapes are treated as
|
||||
//! ellipsoids.
|
||||
ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID };
|
||||
|
||||
std::shared_ptr<graphics::Material> _material;
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeEntityItem_h
|
||||
|
|
|
@ -40,13 +40,13 @@ namespace scriptable {
|
|||
* @typedef {object} Graphics.Material
|
||||
* @property {string} name
|
||||
* @property {string} model
|
||||
* @property {number} opacity
|
||||
* @property {number} roughness
|
||||
* @property {number} metallic
|
||||
* @property {number} scattering
|
||||
* @property {boolean} unlit
|
||||
* @propety {Vec3} emissive
|
||||
* @propety {Vec3} albedo
|
||||
* @property {number|string} opacity
|
||||
* @property {number|string} roughness
|
||||
* @property {number|string} metallic
|
||||
* @property {number|string} scattering
|
||||
* @property {boolean|string} unlit
|
||||
* @propety {Vec3|string} emissive
|
||||
* @propety {Vec3|string} albedo
|
||||
* @property {string} emissiveMap
|
||||
* @property {string} albedoMap
|
||||
* @property {string} opacityMap
|
||||
|
@ -59,6 +59,11 @@ namespace scriptable {
|
|||
* @property {string} occlusionMap
|
||||
* @property {string} lightmapMap
|
||||
* @property {string} scatteringMap
|
||||
* @property {string} texCoordTransform0
|
||||
* @property {string} texCoordTransform1
|
||||
* @property {string} lightmapParams
|
||||
* @property {string} materialParams
|
||||
* @property {boolean} defaultFallthrough
|
||||
*/
|
||||
class ScriptableMaterial {
|
||||
public:
|
||||
|
@ -88,6 +93,9 @@ namespace scriptable {
|
|||
QString occlusionMap;
|
||||
QString lightmapMap;
|
||||
QString scatteringMap;
|
||||
|
||||
bool defaultFallthrough;
|
||||
std::unordered_map<uint, bool> propertyFallthroughs; // not actually exposed to script
|
||||
};
|
||||
|
||||
/**jsdoc
|
||||
|
|
|
@ -362,25 +362,64 @@ namespace scriptable {
|
|||
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", vec3ColorToScriptValue(engine, material.emissive));
|
||||
obj.setProperty("albedo", vec3ColorToScriptValue(engine, material.albedo));
|
||||
obj.setProperty("emissiveMap", material.emissiveMap);
|
||||
obj.setProperty("albedoMap", material.albedoMap);
|
||||
|
||||
const QScriptValue FALLTHROUGH("fallthrough");
|
||||
obj.setProperty("opacity", material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_VAL_BIT) ? FALLTHROUGH : material.opacity);
|
||||
obj.setProperty("roughness", material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT) ? FALLTHROUGH : material.roughness);
|
||||
obj.setProperty("metallic", material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT) ? FALLTHROUGH : material.metallic);
|
||||
obj.setProperty("scattering", material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT) ? FALLTHROUGH : material.scattering);
|
||||
obj.setProperty("unlit", material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT) ? FALLTHROUGH : material.unlit);
|
||||
obj.setProperty("emissive", material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_VAL_BIT) ? FALLTHROUGH : vec3ColorToScriptValue(engine, material.emissive));
|
||||
obj.setProperty("albedo", material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_VAL_BIT) ? FALLTHROUGH : vec3ColorToScriptValue(engine, material.albedo));
|
||||
|
||||
obj.setProperty("emissiveMap", material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_MAP_BIT) ? FALLTHROUGH : material.emissiveMap);
|
||||
obj.setProperty("albedoMap", material.propertyFallthroughs.at(graphics::MaterialKey::ALBEDO_MAP_BIT) ? FALLTHROUGH : 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);
|
||||
obj.setProperty("occlusionMap", material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT) ? FALLTHROUGH : material.occlusionMap);
|
||||
obj.setProperty("lightmapMap", material.propertyFallthroughs.at(graphics::MaterialKey::LIGHTMAP_MAP_BIT) ? FALLTHROUGH : material.lightmapMap);
|
||||
obj.setProperty("scatteringMap", material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT) ? FALLTHROUGH : material.scatteringMap);
|
||||
|
||||
// Only set one of each of these
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT)) {
|
||||
obj.setProperty("metallicMap", FALLTHROUGH);
|
||||
} else if (!material.metallicMap.isEmpty()) {
|
||||
obj.setProperty("metallicMap", material.metallicMap);
|
||||
} else if (!material.specularMap.isEmpty()) {
|
||||
obj.setProperty("specularMap", material.specularMap);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::ROUGHNESS_MAP_BIT)) {
|
||||
obj.setProperty("roughnessMap", FALLTHROUGH);
|
||||
} else if (!material.roughnessMap.isEmpty()) {
|
||||
obj.setProperty("roughnessMap", material.roughnessMap);
|
||||
} else if (!material.glossMap.isEmpty()) {
|
||||
obj.setProperty("glossMap", material.glossMap);
|
||||
}
|
||||
|
||||
if (material.propertyFallthroughs.at(graphics::MaterialKey::NORMAL_MAP_BIT)) {
|
||||
obj.setProperty("normalMap", FALLTHROUGH);
|
||||
} else if (!material.normalMap.isEmpty()) {
|
||||
obj.setProperty("normalMap", material.normalMap);
|
||||
} else if (!material.bumpMap.isEmpty()) {
|
||||
obj.setProperty("bumpMap", material.bumpMap);
|
||||
}
|
||||
|
||||
// These need to be implemented, but set the fallthrough for now
|
||||
if (material.propertyFallthroughs.at(graphics::Material::TEXCOORDTRANSFORM0)) {
|
||||
obj.setProperty("texCoordTransform0", FALLTHROUGH);
|
||||
}
|
||||
if (material.propertyFallthroughs.at(graphics::Material::TEXCOORDTRANSFORM1)) {
|
||||
obj.setProperty("texCoordTransform1", FALLTHROUGH);
|
||||
}
|
||||
if (material.propertyFallthroughs.at(graphics::Material::LIGHTMAP_PARAMS)) {
|
||||
obj.setProperty("lightmapParams", FALLTHROUGH);
|
||||
}
|
||||
if (material.propertyFallthroughs.at(graphics::Material::MATERIAL_PARAMS)) {
|
||||
obj.setProperty("materialParams", FALLTHROUGH);
|
||||
}
|
||||
|
||||
obj.setProperty("defaultFallthrough", material.defaultFallthrough);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const
|
|||
lightmapMap = material.lightmapMap;
|
||||
scatteringMap = material.scatteringMap;
|
||||
|
||||
defaultFallthrough = material.defaultFallthrough;
|
||||
propertyFallthroughs = material.propertyFallthroughs;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -54,7 +57,9 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPoint
|
|||
scattering(material->getScattering()),
|
||||
unlit(material->isUnlit()),
|
||||
emissive(material->getEmissive()),
|
||||
albedo(material->getAlbedo())
|
||||
albedo(material->getAlbedo()),
|
||||
defaultFallthrough(material->getDefaultFallthrough()),
|
||||
propertyFallthroughs(material->getPropertyFallthroughs())
|
||||
{
|
||||
auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP);
|
||||
if (map && map->getTextureSource()) {
|
||||
|
|
|
@ -17,125 +17,125 @@
|
|||
using namespace graphics;
|
||||
using namespace gpu;
|
||||
|
||||
Material::Material() :
|
||||
_key(0),
|
||||
_schemaBuffer(),
|
||||
_textureMaps()
|
||||
{
|
||||
// created from nothing: create the Buffer to store the properties
|
||||
Schema schema;
|
||||
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema, sizeof(Schema)));
|
||||
const float Material::DEFAULT_EMISSIVE { 0.0f };
|
||||
const float Material::DEFAULT_OPACITY { 1.0f };
|
||||
const float Material::DEFAULT_ALBEDO { 0.5f };
|
||||
const float Material::DEFAULT_METALLIC { 0.0f };
|
||||
const float Material::DEFAULT_ROUGHNESS { 1.0f };
|
||||
const float Material::DEFAULT_SCATTERING { 0.0f };
|
||||
|
||||
Material::Material() {
|
||||
for (int i = 0; i < NUM_TOTAL_FLAGS; i++) {
|
||||
_propertyFallthroughs[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
Material::Material(const Material& material) :
|
||||
_name(material._name),
|
||||
_model(material._model),
|
||||
_key(material._key),
|
||||
_textureMaps(material._textureMaps)
|
||||
_emissive(material._emissive),
|
||||
_opacity(material._opacity),
|
||||
_albedo(material._albedo),
|
||||
_roughness(material._roughness),
|
||||
_metallic(material._metallic),
|
||||
_scattering(material._scattering),
|
||||
_texcoordTransforms(material._texcoordTransforms),
|
||||
_lightmapParams(material._lightmapParams),
|
||||
_materialParams(material._materialParams),
|
||||
_textureMaps(material._textureMaps),
|
||||
_defaultFallthrough(material._defaultFallthrough),
|
||||
_propertyFallthroughs(material._propertyFallthroughs)
|
||||
{
|
||||
// copied: create the Buffer to store the properties, avoid holding a ref to the old Buffer
|
||||
Schema schema;
|
||||
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema, sizeof(Schema)));
|
||||
_schemaBuffer.edit<Schema>() = material._schemaBuffer.get<Schema>();
|
||||
}
|
||||
|
||||
Material& Material::operator= (const Material& material) {
|
||||
Material& Material::operator=(const Material& material) {
|
||||
QMutexLocker locker(&_textureMapsMutex);
|
||||
|
||||
_name = material._name;
|
||||
_model = material._model;
|
||||
_key = material._key;
|
||||
_emissive = material._emissive;
|
||||
_opacity = material._opacity;
|
||||
_albedo = material._albedo;
|
||||
_roughness = material._roughness;
|
||||
_metallic = material._metallic;
|
||||
_scattering = material._scattering;
|
||||
_texcoordTransforms = material._texcoordTransforms;
|
||||
_lightmapParams = material._lightmapParams;
|
||||
_materialParams = material._materialParams;
|
||||
_textureMaps = material._textureMaps;
|
||||
|
||||
_key = (material._key);
|
||||
_textureMaps = (material._textureMaps);
|
||||
_hasCalculatedTextureInfo = false;
|
||||
|
||||
// copied: create the Buffer to store the properties, avoid holding a ref to the old Buffer
|
||||
Schema schema;
|
||||
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema, sizeof(Schema)));
|
||||
_schemaBuffer.edit<Schema>() = material._schemaBuffer.get<Schema>();
|
||||
_defaultFallthrough = material._defaultFallthrough;
|
||||
_propertyFallthroughs = material._propertyFallthroughs;
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Material::~Material() {
|
||||
}
|
||||
|
||||
void Material::setEmissive(const Color& emissive, bool isSRGB) {
|
||||
_key.setEmissive(glm::any(glm::greaterThan(emissive, Color(0.0f))));
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32) _key._flags.to_ulong();
|
||||
_schemaBuffer.edit<Schema>()._emissive = (isSRGB ? ColorUtils::sRGBToLinearVec3(emissive) : emissive);
|
||||
void Material::setEmissive(const glm::vec3& emissive, bool isSRGB) {
|
||||
_key.setEmissive(glm::any(glm::greaterThan(emissive, glm::vec3(0.0f))));
|
||||
_emissive = (isSRGB ? ColorUtils::sRGBToLinearVec3(emissive) : emissive);
|
||||
}
|
||||
|
||||
void Material::setOpacity(float opacity) {
|
||||
_key.setTranslucentFactor((opacity < 1.0f));
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
_schemaBuffer.edit<Schema>()._opacity = opacity;
|
||||
_opacity = opacity;
|
||||
}
|
||||
|
||||
void Material::setUnlit(bool value) {
|
||||
_key.setUnlit(value);
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
}
|
||||
|
||||
void Material::setAlbedo(const Color& albedo, bool isSRGB) {
|
||||
_key.setAlbedo(glm::any(glm::greaterThan(albedo, Color(0.0f))));
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
_schemaBuffer.edit<Schema>()._albedo = (isSRGB ? ColorUtils::sRGBToLinearVec3(albedo) : albedo);
|
||||
void Material::setAlbedo(const glm::vec3& albedo, bool isSRGB) {
|
||||
_key.setAlbedo(glm::any(glm::greaterThan(albedo, glm::vec3(0.0f))));
|
||||
_albedo = (isSRGB ? ColorUtils::sRGBToLinearVec3(albedo) : albedo);
|
||||
}
|
||||
|
||||
void Material::setRoughness(float roughness) {
|
||||
roughness = std::min(1.0f, std::max(roughness, 0.0f));
|
||||
_key.setGlossy((roughness < 1.0f));
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
_schemaBuffer.edit<Schema>()._roughness = roughness;
|
||||
_key.setGlossy(roughness < 1.0f);
|
||||
_roughness = roughness;
|
||||
}
|
||||
|
||||
void Material::setMetallic(float metallic) {
|
||||
metallic = glm::clamp(metallic, 0.0f, 1.0f);
|
||||
_key.setMetallic(metallic > 0.0f);
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
_schemaBuffer.edit<Schema>()._metallic = metallic;
|
||||
_metallic = metallic;
|
||||
}
|
||||
|
||||
void Material::setScattering(float scattering) {
|
||||
scattering = glm::clamp(scattering, 0.0f, 1.0f);
|
||||
_key.setMetallic(scattering > 0.0f);
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
_schemaBuffer.edit<Schema>()._scattering = scattering;
|
||||
_scattering = scattering;
|
||||
}
|
||||
|
||||
void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) {
|
||||
QMutexLocker locker(&_textureMapsMutex);
|
||||
|
||||
if (textureMap) {
|
||||
_key.setMapChannel(channel, (true));
|
||||
_key.setMapChannel(channel, true);
|
||||
_textureMaps[channel] = textureMap;
|
||||
} else {
|
||||
_key.setMapChannel(channel, (false));
|
||||
_key.setMapChannel(channel, false);
|
||||
_textureMaps.erase(channel);
|
||||
}
|
||||
_hasCalculatedTextureInfo = false;
|
||||
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
|
||||
if (channel == MaterialKey::ALBEDO_MAP) {
|
||||
resetOpacityMap();
|
||||
|
||||
// update the texcoord0 with albedo
|
||||
_schemaBuffer.edit<Schema>()._texcoordTransforms[0] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
|
||||
_texcoordTransforms[0] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
|
||||
}
|
||||
|
||||
if (channel == MaterialKey::OCCLUSION_MAP) {
|
||||
_schemaBuffer.edit<Schema>()._texcoordTransforms[1] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
|
||||
_texcoordTransforms[1] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
|
||||
}
|
||||
|
||||
if (channel == MaterialKey::LIGHTMAP_MAP) {
|
||||
// update the texcoord1 with lightmap
|
||||
_schemaBuffer.edit<Schema>()._texcoordTransforms[1] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
|
||||
_schemaBuffer.edit<Schema>()._lightmapParams = (textureMap ? glm::vec2(textureMap->getLightmapOffsetScale()) : glm::vec2(0.0, 1.0));
|
||||
_texcoordTransforms[1] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
|
||||
_lightmapParams = (textureMap ? glm::vec2(textureMap->getLightmapOffsetScale()) : glm::vec2(0.0, 1.0));
|
||||
}
|
||||
|
||||
_schemaBuffer.edit<Schema>()._materialParams = (textureMap ? glm::vec2(textureMap->getMappingMode(), textureMap->getRepeat()) : glm::vec2(MaterialMappingMode::UV, 1.0));
|
||||
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
_materialParams = (textureMap ? glm::vec2(textureMap->getMappingMode(), textureMap->getRepeat()) : glm::vec2(MaterialMappingMode::UV, 1.0));
|
||||
|
||||
}
|
||||
|
||||
|
@ -163,11 +163,8 @@ void Material::resetOpacityMap() const {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
}
|
||||
|
||||
|
||||
const TextureMapPointer Material::getTextureMap(MapChannel channel) const {
|
||||
QMutexLocker locker(&_textureMapsMutex);
|
||||
|
||||
|
@ -179,40 +176,6 @@ const TextureMapPointer Material::getTextureMap(MapChannel channel) const {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool Material::calculateMaterialInfo() const {
|
||||
if (!_hasCalculatedTextureInfo) {
|
||||
QMutexLocker locker(&_textureMapsMutex);
|
||||
|
||||
bool allTextures = true; // assume we got this...
|
||||
_textureSize = 0;
|
||||
_textureCount = 0;
|
||||
|
||||
for (auto const &textureMapItem : _textureMaps) {
|
||||
auto textureMap = textureMapItem.second;
|
||||
if (textureMap) {
|
||||
auto textureSoure = textureMap->getTextureSource();
|
||||
if (textureSoure) {
|
||||
auto texture = textureSoure->getGPUTexture();
|
||||
if (texture) {
|
||||
auto size = texture->getSize();
|
||||
_textureSize += size;
|
||||
_textureCount++;
|
||||
} else {
|
||||
allTextures = false;
|
||||
}
|
||||
} else {
|
||||
allTextures = false;
|
||||
}
|
||||
} else {
|
||||
allTextures = false;
|
||||
}
|
||||
}
|
||||
_hasCalculatedTextureInfo = allTextures;
|
||||
}
|
||||
return _hasCalculatedTextureInfo;
|
||||
}
|
||||
|
||||
void Material::setTextureTransforms(const Transform& transform, MaterialMappingMode mode, bool repeat) {
|
||||
for (auto &textureMapItem : _textureMaps) {
|
||||
if (textureMapItem.second) {
|
||||
|
@ -222,7 +185,32 @@ void Material::setTextureTransforms(const Transform& transform, MaterialMappingM
|
|||
}
|
||||
}
|
||||
for (int i = 0; i < NUM_TEXCOORD_TRANSFORMS; i++) {
|
||||
_schemaBuffer.edit<Schema>()._texcoordTransforms[i] = transform.getMatrix();
|
||||
_texcoordTransforms[i] = transform.getMatrix();
|
||||
}
|
||||
_schemaBuffer.edit<Schema>()._materialParams = glm::vec2(mode, repeat);
|
||||
_materialParams = glm::vec2(mode, repeat);
|
||||
}
|
||||
|
||||
MultiMaterial::MultiMaterial() {
|
||||
Schema schema;
|
||||
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema, sizeof(Schema)));
|
||||
}
|
||||
|
||||
void MultiMaterial::calculateMaterialInfo() const {
|
||||
if (!_hasCalculatedTextureInfo) {
|
||||
bool allTextures = true; // assume we got this...
|
||||
_textureSize = 0;
|
||||
_textureCount = 0;
|
||||
|
||||
auto textures = _textureTable->getTextures();
|
||||
for (auto const &texture : textures) {
|
||||
if (texture && texture->isDefined()) {
|
||||
auto size = texture->getSize();
|
||||
_textureSize += size;
|
||||
_textureCount++;
|
||||
} else {
|
||||
allTextures = false;
|
||||
}
|
||||
}
|
||||
_hasCalculatedTextureInfo = allTextures;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
|
||||
#include <ColorUtils.h>
|
||||
|
@ -176,7 +177,6 @@ public:
|
|||
bool isTexelOpaque() const { return isOpaque() && isOpacityMaskMap(); }
|
||||
};
|
||||
|
||||
|
||||
class MaterialFilter {
|
||||
public:
|
||||
MaterialKey::Flags _value{ 0 };
|
||||
|
@ -266,84 +266,44 @@ public:
|
|||
|
||||
class Material {
|
||||
public:
|
||||
typedef gpu::BufferView UniformBufferView;
|
||||
|
||||
typedef glm::vec3 Color;
|
||||
|
||||
// Texture Map Array Schema
|
||||
static const int NUM_TEXCOORD_TRANSFORMS{ 2 };
|
||||
|
||||
typedef MaterialKey::MapChannel MapChannel;
|
||||
typedef std::map<MapChannel, TextureMapPointer> TextureMaps;
|
||||
typedef std::bitset<MaterialKey::NUM_MAP_CHANNELS> MapFlags;
|
||||
|
||||
Material();
|
||||
Material(const Material& material);
|
||||
Material& operator= (const Material& material);
|
||||
virtual ~Material();
|
||||
|
||||
const MaterialKey& getKey() const { return _key; }
|
||||
|
||||
void setEmissive(const Color& emissive, bool isSRGB = true);
|
||||
Color getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_schemaBuffer.get<Schema>()._emissive) : _schemaBuffer.get<Schema>()._emissive); }
|
||||
static const float DEFAULT_EMISSIVE;
|
||||
void setEmissive(const glm::vec3& emissive, bool isSRGB = true);
|
||||
glm::vec3 getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_emissive) : _emissive); }
|
||||
|
||||
static const float DEFAULT_OPACITY;
|
||||
void setOpacity(float opacity);
|
||||
float getOpacity() const { return _schemaBuffer.get<Schema>()._opacity; }
|
||||
float getOpacity() const { return _opacity; }
|
||||
|
||||
void setUnlit(bool value);
|
||||
bool isUnlit() const { return _key.isUnlit(); }
|
||||
|
||||
void setAlbedo(const Color& albedo, bool isSRGB = true);
|
||||
Color getAlbedo(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_schemaBuffer.get<Schema>()._albedo) : _schemaBuffer.get<Schema>()._albedo); }
|
||||
static const float DEFAULT_ALBEDO;
|
||||
void setAlbedo(const glm::vec3& albedo, bool isSRGB = true);
|
||||
glm::vec3 getAlbedo(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_albedo) : _albedo); }
|
||||
|
||||
static const float DEFAULT_METALLIC;
|
||||
void setMetallic(float metallic);
|
||||
float getMetallic() const { return _schemaBuffer.get<Schema>()._metallic; }
|
||||
float getMetallic() const { return _metallic; }
|
||||
|
||||
static const float DEFAULT_ROUGHNESS;
|
||||
void setRoughness(float roughness);
|
||||
float getRoughness() const { return _schemaBuffer.get<Schema>()._roughness; }
|
||||
float getRoughness() const { return _roughness; }
|
||||
|
||||
static const float DEFAULT_SCATTERING;
|
||||
void setScattering(float scattering);
|
||||
float getScattering() const { return _schemaBuffer.get<Schema>()._scattering; }
|
||||
|
||||
// Schema to access the attribute values of the material
|
||||
class Schema {
|
||||
public:
|
||||
glm::vec3 _emissive { 0.0f }; // No Emissive
|
||||
float _opacity { 1.0f }; // Opacity = 1 => Not Transparent
|
||||
|
||||
glm::vec3 _albedo { 0.5f }; // Grey albedo => isAlbedo
|
||||
float _roughness { 1.0f }; // Roughness = 1 => Not Glossy
|
||||
|
||||
float _metallic { 0.0f }; // Not Metallic
|
||||
float _scattering { 0.0f }; // Scattering info
|
||||
#if defined(__clang__)
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
glm::vec2 _spare { 0.0f }; // Padding
|
||||
|
||||
uint32_t _key { 0 }; // a copy of the materialKey
|
||||
#if defined(__clang__)
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
glm::vec3 _spare2 { 0.0f };
|
||||
|
||||
// for alignment beauty, Material size == Mat4x4
|
||||
|
||||
// Texture Coord Transform Array
|
||||
glm::mat4 _texcoordTransforms[NUM_TEXCOORD_TRANSFORMS];
|
||||
|
||||
glm::vec2 _lightmapParams { 0.0, 1.0 };
|
||||
|
||||
// x: material mode (0 for UV, 1 for PROJECTED)
|
||||
// y: 1 for texture repeat, 0 for discard outside of 0 - 1
|
||||
glm::vec2 _materialParams { 0.0, 1.0 };
|
||||
|
||||
Schema() {}
|
||||
};
|
||||
|
||||
const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; }
|
||||
float getScattering() const { return _scattering; }
|
||||
|
||||
// The texture map to channel association
|
||||
static const int NUM_TEXCOORD_TRANSFORMS { 2 };
|
||||
void setTextureMap(MapChannel channel, const TextureMapPointer& textureMap);
|
||||
const TextureMaps& getTextureMaps() const { return _textureMaps; } // FIXME - not thread safe...
|
||||
const TextureMapPointer getTextureMap(MapChannel channel) const;
|
||||
|
@ -355,10 +315,6 @@ public:
|
|||
// conversion from legacy material properties to PBR equivalent
|
||||
static float shininessToRoughness(float shininess) { return 1.0f - shininess / 100.0f; }
|
||||
|
||||
int getTextureCount() const { calculateMaterialInfo(); return _textureCount; }
|
||||
size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; }
|
||||
bool hasTextureInfo() const { return _hasCalculatedTextureInfo; }
|
||||
|
||||
void setTextureTransforms(const Transform& transform, MaterialMappingMode mode, bool repeat);
|
||||
|
||||
const std::string& getName() const { return _name; }
|
||||
|
@ -366,28 +322,50 @@ public:
|
|||
const std::string& getModel() const { return _model; }
|
||||
void setModel(const std::string& model) { _model = model; }
|
||||
|
||||
const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; }
|
||||
glm::mat4 getTexCoordTransform(uint i) const { return _texcoordTransforms[i]; }
|
||||
glm::vec2 getLightmapParams() const { return _lightmapParams; }
|
||||
glm::vec2 getMaterialParams() const { return _materialParams; }
|
||||
|
||||
bool getDefaultFallthrough() const { return _defaultFallthrough; }
|
||||
void setDefaultFallthrough(bool defaultFallthrough) { _defaultFallthrough = defaultFallthrough; }
|
||||
|
||||
enum ExtraFlagBit {
|
||||
TEXCOORDTRANSFORM0 = MaterialKey::NUM_FLAGS,
|
||||
TEXCOORDTRANSFORM1,
|
||||
LIGHTMAP_PARAMS,
|
||||
MATERIAL_PARAMS,
|
||||
|
||||
NUM_TOTAL_FLAGS
|
||||
};
|
||||
std::unordered_map<uint, bool> getPropertyFallthroughs() { return _propertyFallthroughs; }
|
||||
bool getPropertyFallthrough(uint property) { return _propertyFallthroughs[property]; }
|
||||
void setPropertyDoesFallthrough(uint property) { _propertyFallthroughs[property] = true; }
|
||||
|
||||
protected:
|
||||
std::string _name { "" };
|
||||
|
||||
private:
|
||||
mutable MaterialKey _key;
|
||||
mutable UniformBufferView _schemaBuffer;
|
||||
mutable gpu::TextureTablePointer _textureTable{ std::make_shared<gpu::TextureTable>() };
|
||||
std::string _model { "hifi_pbr" };
|
||||
mutable MaterialKey _key { 0 };
|
||||
|
||||
// Material properties
|
||||
glm::vec3 _emissive { DEFAULT_EMISSIVE };
|
||||
float _opacity { DEFAULT_OPACITY };
|
||||
glm::vec3 _albedo { DEFAULT_ALBEDO };
|
||||
float _roughness { DEFAULT_ROUGHNESS };
|
||||
float _metallic { DEFAULT_METALLIC };
|
||||
float _scattering { DEFAULT_SCATTERING };
|
||||
std::array<glm::mat4, NUM_TEXCOORD_TRANSFORMS> _texcoordTransforms;
|
||||
glm::vec2 _lightmapParams { 0.0, 1.0 };
|
||||
glm::vec2 _materialParams { 0.0, 1.0 };
|
||||
TextureMaps _textureMaps;
|
||||
|
||||
bool _defaultFallthrough { false };
|
||||
std::unordered_map<uint, bool> _propertyFallthroughs { NUM_TOTAL_FLAGS };
|
||||
|
||||
mutable QMutex _textureMapsMutex { QMutex::Recursive };
|
||||
mutable size_t _textureSize { 0 };
|
||||
mutable int _textureCount { 0 };
|
||||
mutable bool _hasCalculatedTextureInfo { false };
|
||||
bool calculateMaterialInfo() const;
|
||||
|
||||
std::string _model { "hifi_pbr" };
|
||||
|
||||
};
|
||||
typedef std::shared_ptr< Material > MaterialPointer;
|
||||
typedef std::shared_ptr<Material> MaterialPointer;
|
||||
|
||||
class MaterialLayer {
|
||||
public:
|
||||
|
@ -403,9 +381,18 @@ public:
|
|||
return left.priority < right.priority;
|
||||
}
|
||||
};
|
||||
typedef std::priority_queue<MaterialLayer, std::vector<MaterialLayer>, MaterialLayerCompare> MaterialLayerQueue;
|
||||
|
||||
class MultiMaterial : public std::priority_queue<MaterialLayer, std::vector<MaterialLayer>, MaterialLayerCompare> {
|
||||
class MultiMaterial : public MaterialLayerQueue {
|
||||
public:
|
||||
MultiMaterial();
|
||||
|
||||
void push(const MaterialLayer& value) {
|
||||
MaterialLayerQueue::push(value);
|
||||
_hasCalculatedTextureInfo = false;
|
||||
_needsUpdate = true;
|
||||
}
|
||||
|
||||
bool remove(const MaterialPointer& value) {
|
||||
auto it = c.begin();
|
||||
while (it != c.end()) {
|
||||
|
@ -417,11 +404,78 @@ public:
|
|||
if (it != c.end()) {
|
||||
c.erase(it);
|
||||
std::make_heap(c.begin(), c.end(), comp);
|
||||
_hasCalculatedTextureInfo = false;
|
||||
_needsUpdate = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Schema to access the attribute values of the material
|
||||
class Schema {
|
||||
public:
|
||||
glm::vec3 _emissive { Material::DEFAULT_EMISSIVE }; // No Emissive
|
||||
float _opacity { Material::DEFAULT_OPACITY }; // Opacity = 1 => Not Transparent
|
||||
|
||||
glm::vec3 _albedo { Material::DEFAULT_ALBEDO }; // Grey albedo => isAlbedo
|
||||
float _roughness { Material::DEFAULT_ROUGHNESS }; // Roughness = 1 => Not Glossy
|
||||
|
||||
float _metallic { Material::DEFAULT_METALLIC }; // Not Metallic
|
||||
float _scattering { Material::DEFAULT_SCATTERING }; // Scattering info
|
||||
#if defined(__clang__)
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
glm::vec2 _spare { 0.0f }; // Padding
|
||||
|
||||
uint32_t _key { 0 }; // a copy of the materialKey
|
||||
#if defined(__clang__)
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
glm::vec3 _spare2 { 0.0f };
|
||||
|
||||
// for alignment beauty, Material size == Mat4x4
|
||||
|
||||
// Texture Coord Transform Array
|
||||
glm::mat4 _texcoordTransforms[Material::NUM_TEXCOORD_TRANSFORMS];
|
||||
|
||||
glm::vec2 _lightmapParams { 0.0, 1.0 };
|
||||
|
||||
// x: material mode (0 for UV, 1 for PROJECTED)
|
||||
// y: 1 for texture repeat, 0 for discard outside of 0 - 1
|
||||
glm::vec2 _materialParams { 0.0, 1.0 };
|
||||
|
||||
Schema() {
|
||||
for (auto& transform : _texcoordTransforms) {
|
||||
transform = glm::mat4();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
gpu::BufferView& getSchemaBuffer() { return _schemaBuffer; }
|
||||
graphics::MaterialKey getMaterialKey() const { return graphics::MaterialKey(_schemaBuffer.get<graphics::MultiMaterial::Schema>()._key); }
|
||||
const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; }
|
||||
|
||||
bool needsUpdate() const { return _needsUpdate; }
|
||||
void setNeedsUpdate(bool needsUpdate) { _needsUpdate = needsUpdate; }
|
||||
|
||||
void setTexturesLoading(bool value) { _texturesLoading = value; }
|
||||
bool areTexturesLoading() const { return _texturesLoading; }
|
||||
|
||||
int getTextureCount() const { calculateMaterialInfo(); return _textureCount; }
|
||||
size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; }
|
||||
bool hasTextureInfo() const { return _hasCalculatedTextureInfo; }
|
||||
|
||||
private:
|
||||
gpu::BufferView _schemaBuffer;
|
||||
gpu::TextureTablePointer _textureTable { std::make_shared<gpu::TextureTable>() };
|
||||
bool _needsUpdate { false };
|
||||
bool _texturesLoading { false };
|
||||
|
||||
mutable size_t _textureSize { 0 };
|
||||
mutable int _textureCount { 0 };
|
||||
mutable bool _hasCalculatedTextureInfo { false };
|
||||
void calculateMaterialInfo() const;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -111,146 +111,300 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater
|
|||
/**jsdoc
|
||||
* A material such as may be used by a {@link Entities.EntityType|Material} entity.
|
||||
* @typedef {object} Material
|
||||
* @property {string} name="" - A name for the material.
|
||||
* @property {string} model="hifi_pbr" - <em>Currently not used.</em>
|
||||
* @property {Color|RGBS} emissive - The emissive color, i.e., the color that the material emits. A {@link Color} value
|
||||
* is treated as sRGB. A {@link RGBS} value can be either RGB or sRGB.
|
||||
* @property {number} opacity=1.0 - The opacity, <code>0.0</code> – <code>1.0</code>.
|
||||
* @property {boolean} unlit=false - If <code>true</code>, the material is not lit.
|
||||
* @property {Color|RGBS} albedo - The albedo color. A {@link Color} value is treated as sRGB. A {@link RGBS} value can
|
||||
* be either RGB or sRGB.
|
||||
* @property {number} roughness - The roughness, <code>0.0</code> – <code>1.0</code>.
|
||||
* @property {number} metallic - The metallicness, <code>0.0</code> – <code>1.0</code>.
|
||||
* @property {number} scattering - The scattering, <code>0.0</code> – <code>1.0</code>.
|
||||
* @property {string} emissiveMap - URL of emissive texture image.
|
||||
* @property {string} albedoMap - URL of albedo texture image.
|
||||
* @property {string} model="hifi_pbr" - Different material models support different properties and rendering modes.
|
||||
* Supported models are: "hifi_pbr"
|
||||
* @property {string} name="" - A name for the material. Supported by all material models.
|
||||
* @property {Color|RGBS|string} emissive - The emissive color, i.e., the color that the material emits. A {@link Color} value
|
||||
* is treated as sRGB. A {@link RGBS} value can be either RGB or sRGB. Set to <code>"fallthrough"</code> to fallthrough to
|
||||
* the material below. "hifi_pbr" model only.
|
||||
* @property {number|string} opacity=1.0 - The opacity, <code>0.0</code> – <code>1.0</code>. Set to <code>"fallthrough"</code> to fallthrough to
|
||||
* the material below. "hifi_pbr" model only.
|
||||
* @property {boolean|string} unlit=false - If <code>true</code>, the material is not lit. Set to <code>"fallthrough"</code> to fallthrough to
|
||||
* the material below. "hifi_pbr" model only.
|
||||
* @property {Color|RGBS|string} albedo - The albedo color. A {@link Color} value is treated as sRGB. A {@link RGBS} value can
|
||||
* be either RGB or sRGB. Set to <code>"fallthrough"</code> to fallthrough to the material below. Set to <code>"fallthrough"</code> to fallthrough to
|
||||
* the material below. "hifi_pbr" model only.
|
||||
* @property {number|string} roughness - The roughness, <code>0.0</code> – <code>1.0</code>. Set to <code>"fallthrough"</code> to fallthrough to
|
||||
* the material below. "hifi_pbr" model only.
|
||||
* @property {number|string} metallic - The metallicness, <code>0.0</code> – <code>1.0</code>. Set to <code>"fallthrough"</code> to fallthrough to
|
||||
* the material below. "hifi_pbr" model only.
|
||||
* @property {number|string} scattering - The scattering, <code>0.0</code> – <code>1.0</code>. Set to <code>"fallthrough"</code> to fallthrough to
|
||||
* the material below. "hifi_pbr" model only.
|
||||
* @property {string} emissiveMap - URL of emissive texture image. Set to <code>"fallthrough"</code> to fallthrough to
|
||||
* the material below. "hifi_pbr" model only.
|
||||
* @property {string} albedoMap - URL of albedo texture image. Set to <code>"fallthrough"</code> to fallthrough to
|
||||
* the material below. "hifi_pbr" model only.
|
||||
* @property {string} opacityMap - URL of opacity texture image. Set value the same as the <code>albedoMap</code> value for
|
||||
* transparency.
|
||||
* @property {string} roughnessMap - URL of roughness texture image. Can use this or <code>glossMap</code>, but not both.
|
||||
* @property {string} glossMap - URL of gloss texture image. Can use this or <code>roughnessMap</code>, but not both.
|
||||
* @property {string} metallicMap - URL of metallic texture image. Can use this or <code>specularMap</code>, but not both.
|
||||
* @property {string} specularMap - URL of specular texture image. Can use this or <code>metallicMap</code>, but not both.
|
||||
* @property {string} normalMap - URL of normal texture image. Can use this or <code>bumpMap</code>, but not both.
|
||||
* @property {string} bumpMap - URL of bump texture image. Can use this or <code>normalMap</code>, but not both.
|
||||
* @property {string} occlusionMap - URL of occlusion texture image.
|
||||
* transparency. "hifi_pbr" model only.
|
||||
* @property {string} roughnessMap - URL of roughness texture image. Can use this or <code>glossMap</code>, but not both. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} glossMap - URL of gloss texture image. Can use this or <code>roughnessMap</code>, but not both. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} metallicMap - URL of metallic texture image. Can use this or <code>specularMap</code>, but not both. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} specularMap - URL of specular texture image. Can use this or <code>metallicMap</code>, but not both. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} normalMap - URL of normal texture image. Can use this or <code>bumpMap</code>, but not both. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} bumpMap - URL of bump texture image. Can use this or <code>normalMap</code>, but not both. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} occlusionMap - URL of occlusion texture image. Set to <code>"fallthrough"</code> to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} scatteringMap - URL of scattering texture image. Only used if <code>normalMap</code> or
|
||||
* <code>bumpMap</code> is specified.
|
||||
* @property {string} lightMap - URL of light map texture image. <em>Currently not used.</em>
|
||||
* <code>bumpMap</code> is specified. Set to <code>"fallthrough"</code> to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} lightMap - URL of light map texture image. <em>Currently not used.</em>. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} texCoordTransform0 - The transform to use for all of the maps besides occlusionMap and lightMap. Currently unused. Set to
|
||||
* <code>"fallthrough"</code> to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} texCoordTransform1 - The transform to use for occlusionMap and lightMap. Currently unused. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} lightmapParams - Parameters for controlling how lightMap is used. Currently unused. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {string} materialParams - Parameters for controlling the material projection and repition. Currently unused. Set to <code>"fallthrough"</code>
|
||||
* to fallthrough to the material below. "hifi_pbr" model only.
|
||||
* @property {bool} defaultFallthrough=false - If <code>true</code>, all properties will fallthrough to the material below unless they are set. If
|
||||
* <code>false</code>, they will respect the individual properties' fallthrough state. "hifi_pbr" model only.
|
||||
*/
|
||||
// Note: See MaterialEntityItem.h for default values used in practice.
|
||||
std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl) {
|
||||
std::string name = "";
|
||||
std::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>();
|
||||
for (auto& key : materialJSON.keys()) {
|
||||
if (key == "name") {
|
||||
auto nameJSON = materialJSON.value(key);
|
||||
if (nameJSON.isString()) {
|
||||
name = nameJSON.toString().toStdString();
|
||||
}
|
||||
} else if (key == "model") {
|
||||
auto modelJSON = materialJSON.value(key);
|
||||
if (modelJSON.isString()) {
|
||||
material->setModel(modelJSON.toString().toStdString());
|
||||
}
|
||||
} else if (key == "emissive") {
|
||||
glm::vec3 color;
|
||||
bool isSRGB;
|
||||
bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB);
|
||||
if (valid) {
|
||||
material->setEmissive(color, isSRGB);
|
||||
}
|
||||
} else if (key == "opacity") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isDouble()) {
|
||||
material->setOpacity(value.toDouble());
|
||||
}
|
||||
} else if (key == "unlit") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isBool()) {
|
||||
material->setUnlit(value.toBool());
|
||||
}
|
||||
} else if (key == "albedo") {
|
||||
glm::vec3 color;
|
||||
bool isSRGB;
|
||||
bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB);
|
||||
if (valid) {
|
||||
material->setAlbedo(color, isSRGB);
|
||||
}
|
||||
} else if (key == "roughness") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isDouble()) {
|
||||
material->setRoughness(value.toDouble());
|
||||
}
|
||||
} else if (key == "metallic") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isDouble()) {
|
||||
material->setMetallic(value.toDouble());
|
||||
}
|
||||
} else if (key == "scattering") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isDouble()) {
|
||||
material->setScattering(value.toDouble());
|
||||
}
|
||||
} else if (key == "emissiveMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setEmissiveMap(baseUrl.resolved(value.toString()));
|
||||
}
|
||||
} else if (key == "albedoMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
QString urlString = value.toString();
|
||||
bool useAlphaChannel = false;
|
||||
auto opacityMap = materialJSON.find("opacityMap");
|
||||
if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == urlString) {
|
||||
useAlphaChannel = true;
|
||||
|
||||
const std::string HIFI_PBR = "hifi_pbr";
|
||||
std::string modelString = HIFI_PBR;
|
||||
auto modelJSONIter = materialJSON.find("model");
|
||||
if (modelJSONIter != materialJSON.end() && modelJSONIter.value().isString()) {
|
||||
modelString = modelJSONIter.value().toString().toStdString();
|
||||
material->setModel(modelString);
|
||||
}
|
||||
|
||||
if (modelString == HIFI_PBR) {
|
||||
const QString FALLTHROUGH("fallthrough");
|
||||
for (auto& key : materialJSON.keys()) {
|
||||
if (key == "name") {
|
||||
auto nameJSON = materialJSON.value(key);
|
||||
if (nameJSON.isString()) {
|
||||
name = nameJSON.toString().toStdString();
|
||||
}
|
||||
} else if (key == "model") {
|
||||
auto modelJSON = materialJSON.value(key);
|
||||
if (modelJSON.isString()) {
|
||||
material->setModel(modelJSON.toString().toStdString());
|
||||
}
|
||||
} else if (key == "emissive") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString() && value.toString() == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::EMISSIVE_VAL_BIT);
|
||||
} else {
|
||||
glm::vec3 color;
|
||||
bool isSRGB;
|
||||
bool valid = parseJSONColor(value, color, isSRGB);
|
||||
if (valid) {
|
||||
material->setEmissive(color, isSRGB);
|
||||
}
|
||||
}
|
||||
} else if (key == "opacity") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString() && value.toString() == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::OPACITY_VAL_BIT);
|
||||
} else if (value.isDouble()) {
|
||||
material->setOpacity(value.toDouble());
|
||||
}
|
||||
} else if (key == "unlit") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString() && value.toString() == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::UNLIT_VAL_BIT);
|
||||
} else if (value.isBool()) {
|
||||
material->setUnlit(value.toBool());
|
||||
}
|
||||
} else if (key == "albedo") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString() && value.toString() == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::ALBEDO_VAL_BIT);
|
||||
} else {
|
||||
glm::vec3 color;
|
||||
bool isSRGB;
|
||||
bool valid = parseJSONColor(value, color, isSRGB);
|
||||
if (valid) {
|
||||
material->setAlbedo(color, isSRGB);
|
||||
}
|
||||
}
|
||||
} else if (key == "roughness") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString() && value.toString() == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::GLOSSY_VAL_BIT);
|
||||
} else if (value.isDouble()) {
|
||||
material->setRoughness(value.toDouble());
|
||||
}
|
||||
} else if (key == "metallic") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString() && value.toString() == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::METALLIC_VAL_BIT);
|
||||
} else if (value.isDouble()) {
|
||||
material->setMetallic(value.toDouble());
|
||||
}
|
||||
} else if (key == "scattering") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString() && value.toString() == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::SCATTERING_VAL_BIT);
|
||||
} else if (value.isDouble()) {
|
||||
material->setScattering(value.toDouble());
|
||||
}
|
||||
} else if (key == "emissiveMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::EMISSIVE_MAP_BIT);
|
||||
} else {
|
||||
material->setEmissiveMap(baseUrl.resolved(valueString));
|
||||
}
|
||||
}
|
||||
} else if (key == "albedoMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
QString valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::ALBEDO_MAP_BIT);
|
||||
} else {
|
||||
bool useAlphaChannel = false;
|
||||
auto opacityMap = materialJSON.find("opacityMap");
|
||||
if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == valueString) {
|
||||
useAlphaChannel = true;
|
||||
}
|
||||
material->setAlbedoMap(baseUrl.resolved(valueString), useAlphaChannel);
|
||||
}
|
||||
}
|
||||
} else if (key == "roughnessMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::ROUGHNESS_MAP_BIT);
|
||||
} else {
|
||||
material->setRoughnessMap(baseUrl.resolved(valueString), false);
|
||||
}
|
||||
}
|
||||
} else if (key == "glossMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::ROUGHNESS_MAP_BIT);
|
||||
} else {
|
||||
material->setRoughnessMap(baseUrl.resolved(valueString), true);
|
||||
}
|
||||
}
|
||||
} else if (key == "metallicMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::METALLIC_MAP_BIT);
|
||||
} else {
|
||||
material->setMetallicMap(baseUrl.resolved(valueString), false);
|
||||
}
|
||||
}
|
||||
} else if (key == "specularMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::METALLIC_MAP_BIT);
|
||||
} else {
|
||||
material->setMetallicMap(baseUrl.resolved(valueString), true);
|
||||
}
|
||||
}
|
||||
} else if (key == "normalMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::NORMAL_MAP_BIT);
|
||||
} else {
|
||||
material->setNormalMap(baseUrl.resolved(valueString), false);
|
||||
}
|
||||
}
|
||||
} else if (key == "bumpMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::NORMAL_MAP_BIT);
|
||||
} else {
|
||||
material->setNormalMap(baseUrl.resolved(valueString), true);
|
||||
}
|
||||
}
|
||||
} else if (key == "occlusionMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::OCCLUSION_MAP_BIT);
|
||||
} else {
|
||||
material->setOcclusionMap(baseUrl.resolved(valueString));
|
||||
}
|
||||
}
|
||||
} else if (key == "scatteringMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::SCATTERING_MAP_BIT);
|
||||
} else {
|
||||
material->setScatteringMap(baseUrl.resolved(valueString));
|
||||
}
|
||||
}
|
||||
} else if (key == "lightMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::LIGHTMAP_MAP_BIT);
|
||||
} else {
|
||||
material->setLightmapMap(baseUrl.resolved(valueString));
|
||||
}
|
||||
}
|
||||
} else if (key == "texCoordTransform0") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::Material::ExtraFlagBit::TEXCOORDTRANSFORM0);
|
||||
}
|
||||
}
|
||||
// TODO: implement texCoordTransform0
|
||||
} else if (key == "texCoordTransform1") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::Material::ExtraFlagBit::TEXCOORDTRANSFORM1);
|
||||
}
|
||||
}
|
||||
// TODO: implement texCoordTransform1
|
||||
} else if (key == "lightmapParams") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::Material::ExtraFlagBit::LIGHTMAP_PARAMS);
|
||||
}
|
||||
}
|
||||
// TODO: implement lightmapParams
|
||||
} else if (key == "materialParams") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
auto valueString = value.toString();
|
||||
if (valueString == FALLTHROUGH) {
|
||||
material->setPropertyDoesFallthrough(graphics::Material::ExtraFlagBit::MATERIAL_PARAMS);
|
||||
}
|
||||
}
|
||||
// TODO: implement materialParams
|
||||
} else if (key == "defaultFallthrough") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isBool()) {
|
||||
material->setDefaultFallthrough(value.toBool());
|
||||
}
|
||||
material->setAlbedoMap(baseUrl.resolved(urlString), useAlphaChannel);
|
||||
}
|
||||
} else if (key == "roughnessMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setRoughnessMap(baseUrl.resolved(value.toString()), false);
|
||||
}
|
||||
} else if (key == "glossMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setRoughnessMap(baseUrl.resolved(value.toString()), true);
|
||||
}
|
||||
} else if (key == "metallicMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setMetallicMap(baseUrl.resolved(value.toString()), false);
|
||||
}
|
||||
} else if (key == "specularMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setMetallicMap(baseUrl.resolved(value.toString()), true);
|
||||
}
|
||||
} else if (key == "normalMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setNormalMap(baseUrl.resolved(value.toString()), false);
|
||||
}
|
||||
} else if (key == "bumpMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setNormalMap(baseUrl.resolved(value.toString()), true);
|
||||
}
|
||||
} else if (key == "occlusionMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setOcclusionMap(baseUrl.resolved(value.toString()));
|
||||
}
|
||||
} else if (key == "scatteringMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setScatteringMap(baseUrl.resolved(value.toString()));
|
||||
}
|
||||
} else if (key == "lightMap") {
|
||||
auto value = materialJSON.value(key);
|
||||
if (value.isString()) {
|
||||
material->setLightmapMap(baseUrl.resolved(value.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,8 +49,6 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr
|
|||
}
|
||||
}
|
||||
|
||||
const graphics::MaterialPointer MeshPartPayload::DEFAULT_MATERIAL = std::make_shared<graphics::Material>();
|
||||
|
||||
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material) {
|
||||
updateMeshPart(mesh, partIndex);
|
||||
addMaterial(graphics::MaterialLayer(material, 0));
|
||||
|
@ -85,11 +83,13 @@ void MeshPartPayload::updateKey(const render::ItemKey& key) {
|
|||
ItemKey::Builder builder(key);
|
||||
builder.withTypeShape();
|
||||
|
||||
if (topMaterialExists()) {
|
||||
auto matKey = _drawMaterials.top().material->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
if (_drawMaterials.needsUpdate()) {
|
||||
RenderPipelines::updateMultiMaterial(_drawMaterials);
|
||||
}
|
||||
|
||||
auto matKey = _drawMaterials.getMaterialKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
|
||||
_itemKey = builder.build();
|
||||
|
@ -104,10 +104,7 @@ Item::Bound MeshPartPayload::getBound() const {
|
|||
}
|
||||
|
||||
ShapeKey MeshPartPayload::getShapeKey() const {
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
if (topMaterialExists()) {
|
||||
drawMaterialKey = _drawMaterials.top().material->getKey();
|
||||
}
|
||||
graphics::MaterialKey drawMaterialKey = _drawMaterials.getMaterialKey();
|
||||
|
||||
ShapeKey::Builder builder;
|
||||
builder.withMaterial();
|
||||
|
@ -158,7 +155,7 @@ void MeshPartPayload::render(RenderArgs* args) {
|
|||
|
||||
// apply material properties
|
||||
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
|
||||
RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
|
||||
RenderPipelines::bindMaterials(_drawMaterials, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
|
@ -332,11 +329,13 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
|
|||
builder.withDeformed();
|
||||
}
|
||||
|
||||
if (topMaterialExists()) {
|
||||
auto matKey = _drawMaterials.top().material->getKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
if (_drawMaterials.needsUpdate()) {
|
||||
RenderPipelines::updateMultiMaterial(_drawMaterials);
|
||||
}
|
||||
|
||||
auto matKey = _drawMaterials.getMaterialKey();
|
||||
if (matKey.isTranslucent()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
|
||||
_itemKey = builder.build();
|
||||
|
@ -348,11 +347,12 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode pr
|
|||
return;
|
||||
}
|
||||
|
||||
graphics::MaterialKey drawMaterialKey;
|
||||
if (topMaterialExists()) {
|
||||
drawMaterialKey = _drawMaterials.top().material->getKey();
|
||||
if (_drawMaterials.needsUpdate()) {
|
||||
RenderPipelines::updateMultiMaterial(_drawMaterials);
|
||||
}
|
||||
|
||||
graphics::MaterialKey drawMaterialKey = _drawMaterials.getMaterialKey();
|
||||
|
||||
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||
bool hasTangents = drawMaterialKey.isNormalMap() && _hasTangents;
|
||||
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
||||
|
@ -435,7 +435,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
|||
|
||||
// apply material properties
|
||||
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
|
||||
RenderPipelines::bindMaterial(!_drawMaterials.empty() ? _drawMaterials.top().material : DEFAULT_MATERIAL, batch, args->_enableTexturing);
|
||||
RenderPipelines::bindMaterials(_drawMaterials, batch, args->_enableTexturing);
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,18 +66,15 @@ public:
|
|||
graphics::Mesh::Part _drawPart;
|
||||
|
||||
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
|
||||
size_t getMaterialTextureSize() { return topMaterialExists() ? _drawMaterials.top().material->getTextureSize() : 0; }
|
||||
int getMaterialTextureCount() { return topMaterialExists() ? _drawMaterials.top().material->getTextureCount() : 0; }
|
||||
bool hasTextureInfo() const { return topMaterialExists() ? _drawMaterials.top().material->hasTextureInfo() : false; }
|
||||
size_t getMaterialTextureSize() { return _drawMaterials.getTextureSize(); }
|
||||
int getMaterialTextureCount() { return _drawMaterials.getTextureCount(); }
|
||||
bool hasTextureInfo() const { return _drawMaterials.hasTextureInfo(); }
|
||||
|
||||
void addMaterial(graphics::MaterialLayer material);
|
||||
void removeMaterial(graphics::MaterialPointer material);
|
||||
|
||||
protected:
|
||||
static const graphics::MaterialPointer DEFAULT_MATERIAL;
|
||||
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
|
||||
|
||||
bool topMaterialExists() const { return !_drawMaterials.empty() && _drawMaterials.top().material; }
|
||||
};
|
||||
|
||||
namespace render {
|
||||
|
|
|
@ -308,24 +308,33 @@ void addPlumberPipeline(ShapePlumber& plumber,
|
|||
|
||||
void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch, RenderArgs* args) {
|
||||
// Set a default albedo map
|
||||
batch.setResourceTexture(gr::Texture::MaterialAlbedo,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
batch.setResourceTexture(gr::Texture::MaterialAlbedo, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
|
||||
// Set a default material
|
||||
if (pipeline.locations->materialBufferUnit) {
|
||||
// Create a default schema
|
||||
static bool isMaterialSet = false;
|
||||
static graphics::Material material;
|
||||
if (!isMaterialSet) {
|
||||
material.setAlbedo(vec3(1.0f));
|
||||
material.setOpacity(1.0f);
|
||||
material.setMetallic(0.1f);
|
||||
material.setRoughness(0.9f);
|
||||
isMaterialSet = true;
|
||||
}
|
||||
static gpu::BufferView schemaBuffer;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
graphics::MultiMaterial::Schema schema;
|
||||
graphics::MaterialKey schemaKey;
|
||||
|
||||
// Set a default schema
|
||||
batch.setUniformBuffer(gr::Buffer::Material, material.getSchemaBuffer());
|
||||
schema._albedo = vec3(1.0f);
|
||||
schema._opacity = 1.0f;
|
||||
schema._metallic = 0.1f;
|
||||
schema._roughness = 0.9f;
|
||||
|
||||
schemaKey.setAlbedo(true);
|
||||
schemaKey.setTranslucentFactor(false);
|
||||
schemaKey.setMetallic(true);
|
||||
schemaKey.setGlossy(true);
|
||||
schema._key = (uint32_t)schemaKey._flags.to_ulong();
|
||||
|
||||
auto schemaSize = sizeof(graphics::MultiMaterial::Schema);
|
||||
schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(schemaSize, (const gpu::Byte*) &schema, schemaSize));
|
||||
});
|
||||
|
||||
batch.setUniformBuffer(gr::Buffer::Material, schemaBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,103 +373,400 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, con
|
|||
gpu::Shader::createProgram(deformed_model_shadow_fade_dq), state, extraBatchSetter, itemSetter);
|
||||
}
|
||||
|
||||
// FIXME find a better way to setup the default textures
|
||||
void RenderPipelines::bindMaterial(const graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures) {
|
||||
if (!material) {
|
||||
void RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures) {
|
||||
graphics::MultiMaterial multiMaterial;
|
||||
multiMaterial.push(graphics::MaterialLayer(material, 0));
|
||||
bindMaterials(multiMaterial, batch, enableTextures);
|
||||
}
|
||||
|
||||
void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial) {
|
||||
auto& schemaBuffer = multiMaterial.getSchemaBuffer();
|
||||
|
||||
if (multiMaterial.size() == 0) {
|
||||
schemaBuffer.edit<graphics::MultiMaterial::Schema>() = graphics::MultiMaterial::Schema();
|
||||
return;
|
||||
}
|
||||
|
||||
auto& drawMaterialTextures = multiMaterial.getTextureTable();
|
||||
multiMaterial.setTexturesLoading(false);
|
||||
|
||||
// The total list of things we need to look for
|
||||
static std::set<uint> allFlags;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
for (int i = 0; i < graphics::Material::NUM_TOTAL_FLAGS; i++) {
|
||||
// The opacity mask/map are derived from the albedo map
|
||||
if (i != graphics::MaterialKey::OPACITY_MASK_MAP_BIT &&
|
||||
i != graphics::MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT) {
|
||||
allFlags.insert(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
graphics::MultiMaterial materials = multiMaterial;
|
||||
graphics::MultiMaterial::Schema schema;
|
||||
graphics::MaterialKey schemaKey;
|
||||
|
||||
std::set<uint> flagsToCheck = allFlags;
|
||||
std::set<uint> flagsToSetDefault;
|
||||
|
||||
while (!materials.empty()) {
|
||||
auto material = materials.top().material;
|
||||
if (!material) {
|
||||
break;
|
||||
}
|
||||
materials.pop();
|
||||
|
||||
bool defaultFallthrough = material->getDefaultFallthrough();
|
||||
const auto& materialKey = material->getKey();
|
||||
const auto& textureMaps = material->getTextureMaps();
|
||||
|
||||
auto it = flagsToCheck.begin();
|
||||
while (it != flagsToCheck.end()) {
|
||||
auto flag = *it;
|
||||
bool fallthrough = defaultFallthrough || material->getPropertyFallthrough(flag);
|
||||
|
||||
bool wasSet = false;
|
||||
bool forceDefault = false;
|
||||
switch (flag) {
|
||||
case graphics::MaterialKey::EMISSIVE_VAL_BIT:
|
||||
if (materialKey.isEmissive()) {
|
||||
schema._emissive = material->getEmissive(false);
|
||||
schemaKey.setEmissive(true);
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::UNLIT_VAL_BIT:
|
||||
if (materialKey.isUnlit()) {
|
||||
schemaKey.setUnlit(true);
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::ALBEDO_VAL_BIT:
|
||||
if (materialKey.isAlbedo()) {
|
||||
schema._albedo = material->getAlbedo(false);
|
||||
schemaKey.setAlbedo(true);
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::METALLIC_VAL_BIT:
|
||||
if (materialKey.isMetallic()) {
|
||||
schema._metallic = material->getMetallic();
|
||||
schemaKey.setMetallic(true);
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::GLOSSY_VAL_BIT:
|
||||
if (materialKey.isRough() || materialKey.isGlossy()) {
|
||||
schema._roughness = material->getRoughness();
|
||||
schemaKey.setGlossy(materialKey.isGlossy());
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::OPACITY_VAL_BIT:
|
||||
if (materialKey.isTranslucentFactor()) {
|
||||
schema._opacity = material->getOpacity();
|
||||
schemaKey.setTranslucentFactor(true);
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::SCATTERING_VAL_BIT:
|
||||
if (materialKey.isScattering()) {
|
||||
schema._scattering = material->getScattering();
|
||||
schemaKey.setScattering(true);
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::ALBEDO_MAP_BIT:
|
||||
if (materialKey.isAlbedoMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP);
|
||||
if (itr != textureMaps.end()) {
|
||||
if (itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, itr->second->getTextureView());
|
||||
wasSet = true;
|
||||
} else {
|
||||
multiMaterial.setTexturesLoading(true);
|
||||
forceDefault = true;
|
||||
}
|
||||
} else {
|
||||
forceDefault = true;
|
||||
}
|
||||
schemaKey.setAlbedoMap(true);
|
||||
schemaKey.setOpacityMaskMap(materialKey.isOpacityMaskMap());
|
||||
schemaKey.setTranslucentMap(materialKey.isTranslucentMap());
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::METALLIC_MAP_BIT:
|
||||
if (materialKey.isMetallicMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP);
|
||||
if (itr != textureMaps.end()) {
|
||||
if (itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialMetallic, itr->second->getTextureView());
|
||||
wasSet = true;
|
||||
} else {
|
||||
multiMaterial.setTexturesLoading(true);
|
||||
forceDefault = true;
|
||||
}
|
||||
} else {
|
||||
forceDefault = true;
|
||||
}
|
||||
schemaKey.setMetallicMap(true);
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::ROUGHNESS_MAP_BIT:
|
||||
if (materialKey.isRoughnessMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP);
|
||||
if (itr != textureMaps.end()) {
|
||||
if (itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialRoughness, itr->second->getTextureView());
|
||||
wasSet = true;
|
||||
} else {
|
||||
multiMaterial.setTexturesLoading(true);
|
||||
forceDefault = true;
|
||||
}
|
||||
} else {
|
||||
forceDefault = true;
|
||||
}
|
||||
schemaKey.setRoughnessMap(true);
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::NORMAL_MAP_BIT:
|
||||
if (materialKey.isNormalMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP);
|
||||
if (itr != textureMaps.end()) {
|
||||
if (itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialNormal, itr->second->getTextureView());
|
||||
wasSet = true;
|
||||
} else {
|
||||
multiMaterial.setTexturesLoading(true);
|
||||
forceDefault = true;
|
||||
}
|
||||
} else {
|
||||
forceDefault = true;
|
||||
}
|
||||
schemaKey.setNormalMap(true);
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::OCCLUSION_MAP_BIT:
|
||||
if (materialKey.isOcclusionMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP);
|
||||
if (itr != textureMaps.end()) {
|
||||
if (itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialOcclusion, itr->second->getTextureView());
|
||||
wasSet = true;
|
||||
} else {
|
||||
multiMaterial.setTexturesLoading(true);
|
||||
forceDefault = true;
|
||||
}
|
||||
} else {
|
||||
forceDefault = true;
|
||||
}
|
||||
schemaKey.setOcclusionMap(true);
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::SCATTERING_MAP_BIT:
|
||||
if (materialKey.isScatteringMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP);
|
||||
if (itr != textureMaps.end()) {
|
||||
if (itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialScattering, itr->second->getTextureView());
|
||||
wasSet = true;
|
||||
} else {
|
||||
multiMaterial.setTexturesLoading(true);
|
||||
forceDefault = true;
|
||||
}
|
||||
} else {
|
||||
forceDefault = true;
|
||||
}
|
||||
schemaKey.setScattering(true);
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::EMISSIVE_MAP_BIT:
|
||||
// Lightmap takes precendence over emissive map for legacy reasons
|
||||
if (materialKey.isEmissiveMap() && !materialKey.isLightmapMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP);
|
||||
if (itr != textureMaps.end()) {
|
||||
if (itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView());
|
||||
wasSet = true;
|
||||
} else {
|
||||
multiMaterial.setTexturesLoading(true);
|
||||
forceDefault = true;
|
||||
}
|
||||
} else {
|
||||
forceDefault = true;
|
||||
}
|
||||
schemaKey.setEmissiveMap(true);
|
||||
} else if (materialKey.isLightmapMap()) {
|
||||
// We'll set this later when we check the lightmap
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::LIGHTMAP_MAP_BIT:
|
||||
if (materialKey.isLightmapMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP);
|
||||
if (itr != textureMaps.end()) {
|
||||
if (itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView());
|
||||
wasSet = true;
|
||||
} else {
|
||||
multiMaterial.setTexturesLoading(true);
|
||||
forceDefault = true;
|
||||
}
|
||||
} else {
|
||||
forceDefault = true;
|
||||
}
|
||||
schemaKey.setLightmapMap(true);
|
||||
}
|
||||
break;
|
||||
case graphics::Material::TEXCOORDTRANSFORM0:
|
||||
if (!fallthrough) {
|
||||
schema._texcoordTransforms[0] = material->getTexCoordTransform(0);
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::Material::TEXCOORDTRANSFORM1:
|
||||
if (!fallthrough) {
|
||||
schema._texcoordTransforms[1] = material->getTexCoordTransform(1);
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::Material::LIGHTMAP_PARAMS:
|
||||
if (!fallthrough) {
|
||||
schema._lightmapParams = material->getLightmapParams();
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
case graphics::Material::MATERIAL_PARAMS:
|
||||
if (!fallthrough) {
|
||||
schema._materialParams = material->getMaterialParams();
|
||||
wasSet = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (wasSet) {
|
||||
flagsToCheck.erase(it++);
|
||||
} else if (forceDefault || !fallthrough) {
|
||||
flagsToSetDefault.insert(flag);
|
||||
flagsToCheck.erase(it++);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if (flagsToCheck.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto flagBit : flagsToCheck) {
|
||||
flagsToSetDefault.insert(flagBit);
|
||||
}
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
// Handle defaults
|
||||
for (auto flag : flagsToSetDefault) {
|
||||
switch (flag) {
|
||||
case graphics::MaterialKey::EMISSIVE_VAL_BIT:
|
||||
case graphics::MaterialKey::UNLIT_VAL_BIT:
|
||||
case graphics::MaterialKey::ALBEDO_VAL_BIT:
|
||||
case graphics::MaterialKey::METALLIC_VAL_BIT:
|
||||
case graphics::MaterialKey::GLOSSY_VAL_BIT:
|
||||
case graphics::MaterialKey::OPACITY_VAL_BIT:
|
||||
case graphics::MaterialKey::SCATTERING_VAL_BIT:
|
||||
case graphics::Material::TEXCOORDTRANSFORM0:
|
||||
case graphics::Material::TEXCOORDTRANSFORM1:
|
||||
case graphics::Material::LIGHTMAP_PARAMS:
|
||||
case graphics::Material::MATERIAL_PARAMS:
|
||||
// these are initialized to the correct default values in Schema()
|
||||
break;
|
||||
case graphics::MaterialKey::ALBEDO_MAP_BIT:
|
||||
if (schemaKey.isAlbedoMap()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, textureCache->getWhiteTexture());
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::METALLIC_MAP_BIT:
|
||||
if (schemaKey.isMetallicMap()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialMetallic, textureCache->getBlackTexture());
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::ROUGHNESS_MAP_BIT:
|
||||
if (schemaKey.isRoughnessMap()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialRoughness, textureCache->getWhiteTexture());
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::NORMAL_MAP_BIT:
|
||||
if (schemaKey.isNormalMap()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialNormal, textureCache->getBlueTexture());
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::OCCLUSION_MAP_BIT:
|
||||
if (schemaKey.isOcclusionMap()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialOcclusion, textureCache->getWhiteTexture());
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::SCATTERING_MAP_BIT:
|
||||
if (schemaKey.isScatteringMap()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialScattering, textureCache->getWhiteTexture());
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::EMISSIVE_MAP_BIT:
|
||||
if (schemaKey.isEmissiveMap() && !schemaKey.isLightmapMap()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getGrayTexture());
|
||||
}
|
||||
break;
|
||||
case graphics::MaterialKey::LIGHTMAP_MAP_BIT:
|
||||
if (schemaKey.isLightmapMap()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getBlackTexture());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
schema._key = (uint32_t)schemaKey._flags.to_ulong();
|
||||
schemaBuffer.edit<graphics::MultiMaterial::Schema>() = schema;
|
||||
multiMaterial.setNeedsUpdate(false);
|
||||
}
|
||||
|
||||
void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures) {
|
||||
if (multiMaterial.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (multiMaterial.needsUpdate() || multiMaterial.areTexturesLoading()) {
|
||||
updateMultiMaterial(multiMaterial);
|
||||
}
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
batch.setUniformBuffer(gr::Buffer::Material, material->getSchemaBuffer());
|
||||
static gpu::TextureTablePointer defaultMaterialTextures = std::make_shared<gpu::TextureTable>();
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [textureCache] {
|
||||
defaultMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, textureCache->getWhiteTexture());
|
||||
defaultMaterialTextures->setTexture(gr::Texture::MaterialMetallic, textureCache->getBlackTexture());
|
||||
defaultMaterialTextures->setTexture(gr::Texture::MaterialRoughness, textureCache->getWhiteTexture());
|
||||
defaultMaterialTextures->setTexture(gr::Texture::MaterialNormal, textureCache->getBlueTexture());
|
||||
defaultMaterialTextures->setTexture(gr::Texture::MaterialOcclusion, textureCache->getWhiteTexture());
|
||||
defaultMaterialTextures->setTexture(gr::Texture::MaterialScattering, textureCache->getWhiteTexture());
|
||||
// MaterialEmissiveLightmap has to be set later
|
||||
});
|
||||
|
||||
const auto& materialKey = material->getKey();
|
||||
const auto& textureMaps = material->getTextureMaps();
|
||||
|
||||
int numUnlit = 0;
|
||||
if (materialKey.isUnlit()) {
|
||||
numUnlit++;
|
||||
}
|
||||
|
||||
const auto& drawMaterialTextures = material->getTextureTable();
|
||||
|
||||
// Albedo
|
||||
if (materialKey.isAlbedoMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP);
|
||||
if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, itr->second->getTextureView());
|
||||
} else {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, textureCache->getWhiteTexture());
|
||||
auto& schemaBuffer = multiMaterial.getSchemaBuffer();
|
||||
batch.setUniformBuffer(gr::Buffer::Material, schemaBuffer);
|
||||
if (enableTextures) {
|
||||
batch.setResourceTextureTable(multiMaterial.getTextureTable());
|
||||
} else {
|
||||
auto key = multiMaterial.getMaterialKey();
|
||||
if (key.isLightmapMap()) {
|
||||
defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getBlackTexture());
|
||||
} else if (key.isEmissiveMap()) {
|
||||
defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getGrayTexture());
|
||||
}
|
||||
batch.setResourceTextureTable(defaultMaterialTextures);
|
||||
}
|
||||
|
||||
// Roughness map
|
||||
if (materialKey.isRoughnessMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP);
|
||||
if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialRoughness, itr->second->getTextureView());
|
||||
} else {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialRoughness, textureCache->getWhiteTexture());
|
||||
}
|
||||
}
|
||||
|
||||
// Normal map
|
||||
if (materialKey.isNormalMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP);
|
||||
if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialNormal, itr->second->getTextureView());
|
||||
} else {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialNormal, textureCache->getBlueTexture());
|
||||
}
|
||||
}
|
||||
|
||||
// Metallic map
|
||||
if (materialKey.isMetallicMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP);
|
||||
if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialMetallic, itr->second->getTextureView());
|
||||
} else {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialMetallic, textureCache->getBlackTexture());
|
||||
}
|
||||
}
|
||||
|
||||
// Occlusion map
|
||||
if (materialKey.isOcclusionMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP);
|
||||
if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialOcclusion, itr->second->getTextureView());
|
||||
} else {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialOcclusion, textureCache->getWhiteTexture());
|
||||
}
|
||||
}
|
||||
|
||||
// Scattering map
|
||||
if (materialKey.isScatteringMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP);
|
||||
if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialScattering, itr->second->getTextureView());
|
||||
} else {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialScattering, textureCache->getWhiteTexture());
|
||||
}
|
||||
}
|
||||
|
||||
// Emissive / Lightmap
|
||||
if (materialKey.isLightmapMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP);
|
||||
|
||||
if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView());
|
||||
} else {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getGrayTexture());
|
||||
}
|
||||
} else if (materialKey.isEmissiveMap()) {
|
||||
auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP);
|
||||
if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, itr->second->getTextureView());
|
||||
} else {
|
||||
drawMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getBlackTexture());
|
||||
}
|
||||
}
|
||||
|
||||
batch.setResourceTextureTable(material->getTextureTable());
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
|
||||
class RenderPipelines {
|
||||
public:
|
||||
static void bindMaterial(const graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures);
|
||||
static void bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures);
|
||||
static void updateMultiMaterial(graphics::MultiMaterial& multiMaterial);
|
||||
static void bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures);
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue