Merge pull request #805 from HifiExperiments/mtoon

MToon materials
This commit is contained in:
Julian Groß 2024-02-13 01:03:06 +01:00 committed by GitHub
commit cb05ae8f72
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 3038 additions and 1017 deletions

View file

@ -4,6 +4,7 @@
// //
// Created by Brad Hefta-Gaub on 12/6/13. // Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc. // Copyright 2013 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -196,6 +197,8 @@ ItemKey EntityRenderer::getKey() {
builder.withInvisible(); builder.withInvisible();
} }
updateItemKeyBuilderFromMaterials(builder);
return builder; return builder;
} }
@ -221,6 +224,20 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set<QUuid>& co
return true; return true;
} }
HighlightStyle EntityRenderer::getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const {
std::lock_guard<std::mutex> lock(_materialsLock);
auto materials = _materials.find("0");
if (materials != _materials.end()) {
glm::vec3 position;
withReadLock([&] {
position = _renderTransform.getTranslation();
});
return HighlightStyle::calculateOutlineStyle(materials->second.getOutlineWidthMode(), materials->second.getOutlineWidth(),
materials->second.getOutline(), position, viewFrustum, height);
}
return HighlightStyle();
}
void EntityRenderer::render(RenderArgs* args) { void EntityRenderer::render(RenderArgs* args) {
if (!isValidRenderItem()) { if (!isValidRenderItem()) {
return; return;
@ -510,7 +527,7 @@ EntityRenderer::Pipeline EntityRenderer::getPipelineType(const graphics::MultiMa
} }
graphics::MaterialKey drawMaterialKey = materials.getMaterialKey(); graphics::MaterialKey drawMaterialKey = materials.getMaterialKey();
if (drawMaterialKey.isEmissive() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) { if (materials.isMToon() || drawMaterialKey.isEmissive() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
return Pipeline::MATERIAL; return Pipeline::MATERIAL;
} }
@ -630,6 +647,26 @@ Item::Bound EntityRenderer::getMaterialBound(RenderArgs* args) {
return EntityRenderer::getBound(args); return EntityRenderer::getBound(args);
} }
void EntityRenderer::updateItemKeyBuilderFromMaterials(ItemKey::Builder& builder) {
MaterialMap::iterator materials;
{
std::lock_guard<std::mutex> lock(_materialsLock);
materials = _materials.find("0");
if (materials != _materials.end()) {
if (materials->second.shouldUpdate()) {
RenderPipelines::updateMultiMaterial(materials->second);
}
} else {
return;
}
}
if (materials->second.hasOutline()) {
builder.withOutline();
}
}
void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& builder) { void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& builder) {
MaterialMap::iterator materials; MaterialMap::iterator materials;
{ {
@ -656,7 +693,7 @@ void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& build
builder.withCullFaceMode(materials->second.getCullFaceMode()); builder.withCullFaceMode(materials->second.getCullFaceMode());
graphics::MaterialKey drawMaterialKey = materials->second.getMaterialKey(); graphics::MaterialKey drawMaterialKey = materials->second.getMaterialKey();
if (drawMaterialKey.isUnlit()) { if (!materials->second.isMToon() && drawMaterialKey.isUnlit()) {
builder.withUnlit(); builder.withUnlit();
} }
@ -666,8 +703,12 @@ void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& build
if (drawMaterialKey.isNormalMap()) { if (drawMaterialKey.isNormalMap()) {
builder.withTangents(); builder.withTangents();
} }
if (drawMaterialKey.isLightMap()) { if (!materials->second.isMToon()) {
builder.withLightMap(); if (drawMaterialKey.isLightMap()) {
builder.withLightMap();
}
} else {
builder.withMToon();
} }
} else if (pipelineType == Pipeline::PROCEDURAL) { } else if (pipelineType == Pipeline::PROCEDURAL) {
builder.withOwnPipeline(); builder.withOwnPipeline();

View file

@ -4,6 +4,7 @@
// //
// Created by Brad Hefta-Gaub on 12/6/13. // Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc. // Copyright 2013 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -13,6 +14,8 @@
#define hifi_RenderableEntityItem_h #define hifi_RenderableEntityItem_h
#include <render/Scene.h> #include <render/Scene.h>
#include <render/HighlightStyle.h>
#include <EntityItem.h> #include <EntityItem.h>
#include <Sound.h> #include <Sound.h>
#include "AbstractViewStateInterface.h" #include "AbstractViewStateInterface.h"
@ -74,6 +77,7 @@ public:
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
virtual Item::Bound getBound(RenderArgs* args) override; virtual Item::Bound getBound(RenderArgs* args) override;
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override; bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override;
virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const override;
protected: protected:
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); } virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
@ -131,6 +135,7 @@ protected:
void updateMaterials(bool baseMaterialChanged = false); void updateMaterials(bool baseMaterialChanged = false);
bool materialsTransparent() const; bool materialsTransparent() const;
Item::Bound getMaterialBound(RenderArgs* args); Item::Bound getMaterialBound(RenderArgs* args);
void updateItemKeyBuilderFromMaterials(ItemKey::Builder& builder);
void updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& builder); void updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& builder);
Item::Bound _bound; Item::Bound _bound;

View file

@ -130,8 +130,7 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
materials = _materials["0"]; materials = _materials["0"];
} }
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>(); glm::vec4 color = materials.getColor();
glm::vec4 color = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created); color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
if (!_texture || !_texture->isLoaded() || color.a == 0.0f) { if (!_texture || !_texture->isLoaded() || color.a == 0.0f) {

View file

@ -1,6 +1,7 @@
// //
// Created by Sam Gondelman on 1/18/2018 // Created by Sam Gondelman on 1/18/2018
// Copyright 2018 High Fidelity, Inc. // Copyright 2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -219,7 +220,7 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
ItemKey MaterialEntityRenderer::getKey() { ItemKey MaterialEntityRenderer::getKey() {
auto builder = ItemKey::Builder().withTypeShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); auto builder = ItemKey::Builder().withTypeShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
if (!_visible) { if (!_visible || !_parentID.isNull()) {
builder.withInvisible(); builder.withInvisible();
} }
@ -229,6 +230,10 @@ ItemKey MaterialEntityRenderer::getKey() {
if (matKey.isTranslucent()) { if (matKey.isTranslucent()) {
builder.withTransparent(); builder.withTransparent();
} }
if (drawMaterial->getOutlineWidthMode() != NetworkMToonMaterial::OutlineWidthMode::OUTLINE_NONE && drawMaterial->getOutlineWidth() > 0.0f) {
builder.withOutline();
}
} }
return builder.build(); return builder.build();
@ -258,11 +263,16 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
if (drawMaterialKey.isNormalMap()) { if (drawMaterialKey.isNormalMap()) {
builder.withTangents(); builder.withTangents();
} }
if (drawMaterialKey.isLightMap()) {
builder.withLightMap(); if (drawMaterial && drawMaterial->isMToon()) {
} builder.withMToon();
if (drawMaterialKey.isUnlit()) { } else {
builder.withUnlit(); if (drawMaterialKey.isLightMap()) {
builder.withLightMap();
}
if (drawMaterialKey.isUnlit()) {
builder.withUnlit();
}
} }
} }
@ -273,6 +283,18 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
return builder.build(); return builder.build();
} }
HighlightStyle MaterialEntityRenderer::getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const {
if (const auto drawMaterial = getMaterial()) {
glm::vec3 position;
withReadLock([&] {
position = _renderTransform.getTranslation();
});
return HighlightStyle::calculateOutlineStyle(drawMaterial->getOutlineWidthMode(), drawMaterial->getOutlineWidth(),
drawMaterial->getOutline(), position, viewFrustum, height);
}
return HighlightStyle();
}
void MaterialEntityRenderer::doRender(RenderArgs* args) { void MaterialEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render"); PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);

View file

@ -1,6 +1,7 @@
// //
// Created by Sam Gondelman on 1/18/2018 // Created by Sam Gondelman on 1/18/2018
// Copyright 2018 High Fidelity, Inc. // Copyright 2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -32,6 +33,7 @@ private:
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override; virtual void doRender(RenderArgs* args) override;
virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const override;
ItemKey getKey() override; ItemKey getKey() override;
ShapeKey getShapeKey() override; ShapeKey getShapeKey() override;

View file

@ -99,8 +99,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
materials = _materials["0"]; materials = _materials["0"];
} }
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>(); glm::vec4 outColor = materials.getColor();
glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created); outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
if (outColor.a == 0.0f) { if (outColor.a == 0.0f) {
@ -178,7 +177,7 @@ scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel() {
result.appendMaterials(_materials); result.appendMaterials(_materials);
auto materials = _materials.find("0"); auto materials = _materials.find("0");
if (materials != _materials.end()) { if (materials != _materials.end()) {
vertexColor = ColorUtils::tosRGBVec3(materials->second.getSchemaBuffer().get<graphics::MultiMaterial::Schema>()._albedo); vertexColor = materials->second.getColor();
} }
} }
if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) { if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) {

View file

@ -147,8 +147,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
materials = _materials["0"]; materials = _materials["0"];
} }
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>(); glm::vec4 backgroundColor = materials.getColor();
glm::vec4 backgroundColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created); backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
if (backgroundColor.a <= 0.0f) { if (backgroundColor.a <= 0.0f) {

View file

@ -52,35 +52,55 @@ namespace scriptable {
ScriptableMaterial(const ScriptableMaterial& material) { *this = material; } ScriptableMaterial(const ScriptableMaterial& material) { *this = material; }
ScriptableMaterial& operator=(const ScriptableMaterial& material); ScriptableMaterial& operator=(const ScriptableMaterial& material);
QString name; QString name { "" };
QString model; QString model { "" };
float opacity; float opacity { 0.0f };
float roughness; float roughness { 0.0f };
float metallic; float metallic { 0.0f };
float scattering; float scattering { 0.0f };
bool unlit; bool unlit { false };
glm::vec3 emissive; glm::vec3 emissive { 0.0f };
glm::vec3 albedo; glm::vec3 albedo { 0.0f };
QString emissiveMap; QString emissiveMap { "" };
QString albedoMap; QString albedoMap { "" };
QString opacityMap; QString opacityMap { "" };
QString opacityMapMode; QString opacityMapMode { "" };
float opacityCutoff; float opacityCutoff { 0.0f };
QString metallicMap; QString metallicMap { "" };
QString specularMap; QString specularMap { "" };
QString roughnessMap; QString roughnessMap { "" };
QString glossMap; QString glossMap { "" };
QString normalMap; QString normalMap { "" };
QString bumpMap; QString bumpMap { "" };
QString occlusionMap; QString occlusionMap { "" };
QString lightMap; QString lightMap { "" };
QString scatteringMap; QString scatteringMap { "" };
std::array<glm::mat4, graphics::Material::NUM_TEXCOORD_TRANSFORMS> texCoordTransforms; std::array<glm::mat4, graphics::Material::NUM_TEXCOORD_TRANSFORMS> texCoordTransforms;
QString cullFaceMode; QString cullFaceMode { "" };
bool defaultFallthrough; bool defaultFallthrough { false };
std::unordered_map<uint, bool> propertyFallthroughs; // not actually exposed to script std::unordered_map<uint, bool> propertyFallthroughs; // not actually exposed to script
QString procedural; QString procedural { "" };
glm::vec3 shade { 0.0f };
QString shadeMap { "" };
float shadingShift { 0.0f };
QString shadingShiftMap { "" };
float shadingToony { 0.0f };
glm::vec3 matcap { 0.0f };
QString matcapMap { "" };
glm::vec3 parametricRim { 0.0f };
float parametricRimFresnelPower { 0.0f };
float parametricRimLift { 0.0f };
QString rimMap { "" };
float rimLightingMix { 0.0f };
QString outlineWidthMode { "" };
float outlineWidth { 0.0f };
glm::vec3 outline { 0.0f };
QString uvAnimationMaskMap { "" };
float uvAnimationScrollXSpeed { 0.0f };
float uvAnimationScrollYSpeed { 0.0f };
float uvAnimationRotationSpeed { 0.0f };
graphics::MaterialKey key { 0 }; graphics::MaterialKey key { 0 };
}; };
@ -88,7 +108,7 @@ namespace scriptable {
/*@jsdoc /*@jsdoc
* A material layer. * A material layer.
* @typedef {object} Graphics.MaterialLayer * @typedef {object} Graphics.MaterialLayer
* @property {Graphics.Material} material - The layer's material. * @property {Entities.Material} material - The layer's material.
* @property {number} priority - The priority of the layer. If multiple materials are applied to a mesh part, only the * @property {number} priority - The priority of the layer. If multiple materials are applied to a mesh part, only the
* layer with the highest priority is applied, with materials of the same priority randomly assigned. * layer with the highest priority is applied, with materials of the same priority randomly assigned.
*/ */

View file

@ -369,120 +369,6 @@ namespace scriptable {
return true; return true;
} }
/*@jsdoc
* A material in a {@link GraphicsModel}.
* @typedef {object} Graphics.Material
* @property {string} name - The name of the material.
* @property {string} model - Different material models support different properties and rendering modes. Supported models
* are: <code>"hifi_pbr"</code> and <code>"hifi_shader_simple"</code>.
* @property {Vec3|string} [albedo] - The albedo color. Component values are in the range <code>0.0</code> &ndash;
* <code>1.0</code>.
* If <code>"fallthrough"</code> then it falls through to the material below.
* @property {number|string} [opacity] - The opacity, range <code>0.0</code> &ndash; <code>1.0</code>.
* If <code>"fallthrough"</code> then it falls through to the material below.
*
* @property {number|string} [opacityCutoff] - The opacity cutoff threshold used to determine the opaque texels of the
* <code>opacityMap</code> when <code>opacityMapMode</code> is <code>"OPACITY_MAP_MASK"</code>. Range <code>0.0</code>
* &ndash; <code>1.0</code>.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {number|string} [roughness] - The roughness, range <code>0.0</code> &ndash; <code>1.0</code>.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {number|string} [metallic] - The metallicness, range <code>0.0</code> &ndash; <code>1.0</code>.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {number|string} [scattering] - The scattering, range <code>0.0</code> &ndash; <code>1.0</code>.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {boolean|string} [unlit] - <code>true</code> if the material is unaffected by lighting, <code>false</code> if it
* it is lit by the key light and local lights.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {Vec3|string} [emissive] - The emissive color, i.e., the color that the material emits. Component values are
* in the range <code>0.0</code> &ndash; <code>1.0</code>.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {string} [albedoMap] - The URL of the albedo texture image.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {string} [opacityMap] - The URL of the opacity texture image.
* <code>"hifi_pbr"</code> model only.
* @property {string} [opacityMapMode] - The mode defining the interpretation of the opacity map. Values can be:
* <ul>
* <li><code>"OPACITY_MAP_OPAQUE"</code> for ignoring the opacity map information.</li>
* <li><code>"OPACITY_MAP_MASK"</code> for using the <code>opacityMap</code> as a mask, where only the texel greater
* than <code>opacityCutoff</code> are visible and rendered opaque.</li>
* <li><code>"OPACITY_MAP_BLEND"</code> for using the <code>opacityMap</code> for alpha blending the material surface
* with the background.</li>
* </ul>
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {string} [occlusionMap] - The URL of the occlusion texture image.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {string} [lightMap] - The URL of the light map texture image.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {string} [lightmapParams] - Parameters for controlling how <code>lightMap</code> is used.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* <p><em>Currently not used.</em></p>
* @property {string} [scatteringMap] - The URL of the scattering texture image.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {string} [emissiveMap] - The URL of the emissive texture image.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {string} [metallicMap] - The URL of the metallic texture image.
* If <code>"fallthrough"</code> then it and <code>specularMap</code> fall through to the material below.
* Only use one of <code>metallicMap</code> and <code>specularMap</code>.
* <code>"hifi_pbr"</code> model only.
* @property {string} [specularMap] - The URL of the specular texture image.
* Only use one of <code>metallicMap</code> and <code>specularMap</code>.
* <code>"hifi_pbr"</code> model only.
* @property {string} [roughnessMap] - The URL of the roughness texture image.
* If <code>"fallthrough"</code> then it and <code>glossMap</code> fall through to the material below.
* Only use one of <code>roughnessMap</code> and <code>glossMap</code>.
* <code>"hifi_pbr"</code> model only.
* @property {string} [glossMap] - The URL of the gloss texture image.
* Only use one of <code>roughnessMap</code> and <code>glossMap</code>.
* <code>"hifi_pbr"</code> model only.
* @property {string} [normalMap] - The URL of the normal texture image.
* If <code>"fallthrough"</code> then it and <code>bumpMap</code> fall through to the material below.
* Only use one of <code>normalMap</code> and <code>bumpMap</code>.
* <code>"hifi_pbr"</code> model only.
* @property {string} [bumpMap] - The URL of the bump texture image.
* Only use one of <code>normalMap</code> and <code>bumpMap</code>.
* <code>"hifi_pbr"</code> model only.
* @property {string} [materialParams] - Parameters for controlling the material projection and repetition.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* <p><em>Currently not used.</em></p>
* @property {string} [cullFaceMode="CULL_BACK"] - Specifies Which faces of the geometry to render. Values can be:
* <ul>
* <li><code>"CULL_NONE"</code> to render both sides of the geometry.</li>
* <li><code>"CULL_FRONT"</code> to cull the front faces of the geometry.</li>
* <li><code>"CULL_BACK"</code> (the default) to cull the back faces of the geometry.</li>
* </ul>
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {Mat4|string} [texCoordTransform0] - The transform to use for all of the maps apart from
* <code>occlusionMap</code> and <code>lightMap</code>.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
* @property {Mat4|string} [texCoordTransform1] - The transform to use for <code>occlusionMap</code> and
* <code>lightMap</code>.
* If <code>"fallthrough"</code> then it falls through to the material below.
* <code>"hifi_pbr"</code> model only.
*
* @property {string} procedural - The definition of a procedural shader material.
* <code>"hifi_shader_simple"</code> model only.
* <p><em>Currently not used.</em></p>
*
* @property {boolean} defaultFallthrough - <code>true</code> if all properties fall through to the material below unless
* they are set, <code>false</code> if properties respect their individual fall-through settings.
*/
ScriptValue scriptableMaterialToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterial &material) { ScriptValue scriptableMaterialToScriptValue(ScriptEngine* engine, const scriptable::ScriptableMaterial &material) {
ScriptValue obj = engine->newObject(); ScriptValue obj = engine->newObject();
obj.setProperty("name", material.name); obj.setProperty("name", material.name);
@ -503,7 +389,7 @@ namespace scriptable {
obj.setProperty("albedo", vec3ColorToScriptValue(engine, material.albedo)); obj.setProperty("albedo", vec3ColorToScriptValue(engine, material.albedo));
} }
if (material.model.toStdString() == graphics::Material::HIFI_PBR) { if (material.model.toStdString() == graphics::Material::HIFI_PBR || material.model.toStdString() == graphics::Material::VRM_MTOON) {
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_CUTOFF_VAL_BIT)) { if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OPACITY_CUTOFF_VAL_BIT)) {
obj.setProperty("opacityCutoff", FALLTHROUGH); obj.setProperty("opacityCutoff", FALLTHROUGH);
} else if (material.key.isOpacityCutoff()) { } else if (material.key.isOpacityCutoff()) {
@ -516,30 +402,6 @@ namespace scriptable {
obj.setProperty("opacityMapMode", material.opacityMapMode); obj.setProperty("opacityMapMode", material.opacityMapMode);
} }
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT)) {
obj.setProperty("roughness", FALLTHROUGH);
} else if (material.key.isGlossy()) {
obj.setProperty("roughness", material.roughness);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT)) {
obj.setProperty("metallic", FALLTHROUGH);
} else if (material.key.isMetallic()) {
obj.setProperty("metallic", material.metallic);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT)) {
obj.setProperty("scattering", FALLTHROUGH);
} else if (material.key.isScattering()) {
obj.setProperty("scattering", material.scattering);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT)) {
obj.setProperty("unlit", FALLTHROUGH);
} else if (material.key.isUnlit()) {
obj.setProperty("unlit", material.unlit);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_VAL_BIT)) { if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EMISSIVE_VAL_BIT)) {
obj.setProperty("emissive", FALLTHROUGH); obj.setProperty("emissive", FALLTHROUGH);
} else if (material.key.isEmissive()) { } else if (material.key.isEmissive()) {
@ -562,41 +424,6 @@ namespace scriptable {
obj.setProperty("opacityMap", material.opacityMap); obj.setProperty("opacityMap", material.opacityMap);
} }
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT)) {
obj.setProperty("occlusionMap", FALLTHROUGH);
} else if (!material.occlusionMap.isEmpty()) {
obj.setProperty("occlusionMap", material.occlusionMap);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::LIGHT_MAP_BIT)) {
obj.setProperty("lightMap", FALLTHROUGH);
} else if (!material.lightMap.isEmpty()) {
obj.setProperty("lightMap", material.lightMap);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT)) {
obj.setProperty("scatteringMap", FALLTHROUGH);
} else if (!material.scatteringMap.isEmpty()) {
obj.setProperty("scatteringMap", material.scatteringMap);
}
// Only set one of each of these
if (hasPropertyFallthroughs && 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 (hasPropertyFallthroughs && 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 (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::NORMAL_MAP_BIT)) { if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::NORMAL_MAP_BIT)) {
obj.setProperty("normalMap", FALLTHROUGH); obj.setProperty("normalMap", FALLTHROUGH);
} else if (!material.normalMap.isEmpty()) { } else if (!material.normalMap.isEmpty()) {
@ -616,10 +443,7 @@ namespace scriptable {
obj.setProperty("texCoordTransform1", mat4toScriptValue(engine, material.texCoordTransforms[1])); obj.setProperty("texCoordTransform1", mat4toScriptValue(engine, material.texCoordTransforms[1]));
} }
// These need to be implemented, but set the fallthrough for now // This needs to be implemented, but set the fallthrough for now
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::LIGHTMAP_PARAMS)) {
obj.setProperty("lightmapParams", FALLTHROUGH);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::MATERIAL_PARAMS)) { if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::MATERIAL_PARAMS)) {
obj.setProperty("materialParams", FALLTHROUGH); obj.setProperty("materialParams", FALLTHROUGH);
} }
@ -629,6 +453,196 @@ namespace scriptable {
} else if (!material.cullFaceMode.isEmpty()) { } else if (!material.cullFaceMode.isEmpty()) {
obj.setProperty("cullFaceMode", material.cullFaceMode); obj.setProperty("cullFaceMode", material.cullFaceMode);
} }
if (material.model.toStdString() == graphics::Material::HIFI_PBR) {
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT)) {
obj.setProperty("roughness", FALLTHROUGH);
} else if (material.key.isGlossy()) {
obj.setProperty("roughness", material.roughness);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT)) {
obj.setProperty("metallic", FALLTHROUGH);
} else if (material.key.isMetallic()) {
obj.setProperty("metallic", material.metallic);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT)) {
obj.setProperty("scattering", FALLTHROUGH);
} else if (material.key.isScattering()) {
obj.setProperty("scattering", material.scattering);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT)) {
obj.setProperty("unlit", FALLTHROUGH);
} else if (material.key.isUnlit()) {
obj.setProperty("unlit", material.unlit);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT)) {
obj.setProperty("occlusionMap", FALLTHROUGH);
} else if (!material.occlusionMap.isEmpty()) {
obj.setProperty("occlusionMap", material.occlusionMap);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::LIGHT_MAP_BIT)) {
obj.setProperty("lightMap", FALLTHROUGH);
} else if (!material.lightMap.isEmpty()) {
obj.setProperty("lightMap", material.lightMap);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT)) {
obj.setProperty("scatteringMap", FALLTHROUGH);
} else if (!material.scatteringMap.isEmpty()) {
obj.setProperty("scatteringMap", material.scatteringMap);
}
// Only set one of each of these
if (hasPropertyFallthroughs && 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 (hasPropertyFallthroughs && 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);
}
// This needs to be implemented, but set the fallthrough for now
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::LIGHTMAP_PARAMS)) {
obj.setProperty("lightmapParams", FALLTHROUGH);
}
} else {
// See the mappings in ProceduralMatericalCache.h
// SHADE_VAL_BIT = graphics::MaterialKey::FlagBit::UNLIT_VAL_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::UNLIT_VAL_BIT)) {
obj.setProperty("shade", FALLTHROUGH);
} else if (material.key._flags[graphics::MaterialKey::UNLIT_VAL_BIT]) {
obj.setProperty("shade", vec3ColorToScriptValue(engine, material.shade));
}
// SHADE_MAP_BIT = graphics::MaterialKey::FlagBit::ROUGHNESS_MAP_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::ROUGHNESS_MAP_BIT)) {
obj.setProperty("shadeMap", FALLTHROUGH);
} else if (!material.shadeMap.isEmpty()) {
obj.setProperty("shadeMap", material.shadeMap);
}
// SHADING_SHIFT_VAL_BIT = graphics::MaterialKey::FlagBit::METALLIC_VAL_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_VAL_BIT)) {
obj.setProperty("shadingShift", FALLTHROUGH);
} else if (material.key._flags[graphics::MaterialKey::METALLIC_VAL_BIT]) {
obj.setProperty("shadingShift", material.shadingShift);
}
// SHADING_SHIFT_MAP_BIT = graphics::MaterialKey::FlagBit::METALLIC_MAP_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT)) {
obj.setProperty("shadingShiftMap", FALLTHROUGH);
} else if (!material.shadingShiftMap.isEmpty()) {
obj.setProperty("shadingShiftMap", material.shadingShiftMap);
}
// SHADING_TOONY_VAL_BIT = graphics::MaterialKey::FlagBit::GLOSSY_VAL_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::GLOSSY_VAL_BIT)) {
obj.setProperty("shadingToony", FALLTHROUGH);
} else if (material.key._flags[graphics::MaterialKey::GLOSSY_VAL_BIT]) {
obj.setProperty("shadingToony", material.shadingToony);
}
// MATCAP_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_1_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EXTRA_1_BIT)) {
obj.setProperty("matcap", FALLTHROUGH);
} else if (material.key._flags[graphics::MaterialKey::EXTRA_1_BIT]) {
obj.setProperty("matcap", vec3ColorToScriptValue(engine, material.matcap));
}
// MATCAP_MAP_BIT = graphics::MaterialKey::FlagBit::OCCLUSION_MAP_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT)) {
obj.setProperty("matcapMap", FALLTHROUGH);
} else if (!material.matcapMap.isEmpty()) {
obj.setProperty("matcapMap", material.matcapMap);
}
// PARAMETRIC_RIM_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_2_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EXTRA_2_BIT)) {
obj.setProperty("parametricRim", FALLTHROUGH);
} else if (material.key._flags[graphics::MaterialKey::EXTRA_2_BIT]) {
obj.setProperty("parametricRim", vec3ColorToScriptValue(engine, material.parametricRim));
}
// PARAMETRIC_RIM_POWER_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_3_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EXTRA_3_BIT)) {
obj.setProperty("parametricRimFresnelPower", FALLTHROUGH);
} else if (material.key._flags[graphics::MaterialKey::EXTRA_3_BIT]) {
obj.setProperty("parametricRimFresnelPower", material.parametricRimFresnelPower);
}
// PARAMETRIC_RIM_LIFT_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_4_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EXTRA_4_BIT)) {
obj.setProperty("parametricRimLift", FALLTHROUGH);
} else if (material.key._flags[graphics::MaterialKey::EXTRA_4_BIT]) {
obj.setProperty("parametricRimLift", material.parametricRimLift);
}
// RIM_MAP_BIT = graphics::MaterialKey::FlagBit::SCATTERING_MAP_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT)) {
obj.setProperty("rimMap", FALLTHROUGH);
} else if (!material.rimMap.isEmpty()) {
obj.setProperty("rimMap", material.rimMap);
}
// RIM_LIGHTING_MIX_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_5_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::EXTRA_5_BIT)) {
obj.setProperty("rimLightingMix", FALLTHROUGH);
} else if (material.key._flags[graphics::MaterialKey::EXTRA_5_BIT]) {
obj.setProperty("rimLightingMix", material.rimLightingMix);
}
// UV_ANIMATION_MASK_MAP_BIT = graphics::MaterialKey::FlagBit::LIGHT_MAP_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::LIGHT_MAP_BIT)) {
obj.setProperty("uvAnimationMaskMap", FALLTHROUGH);
} else if (!material.uvAnimationMaskMap.isEmpty()) {
obj.setProperty("uvAnimationMaskMap", material.uvAnimationMaskMap);
}
// UV_ANIMATION_SCROLL_VAL_BIT = graphics::MaterialKey::FlagBit::SCATTERING_VAL_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_VAL_BIT)) {
obj.setProperty("uvAnimationScrollXSpeed", FALLTHROUGH);
obj.setProperty("uvAnimationScrollYSpeed", FALLTHROUGH);
obj.setProperty("uvAnimationRotationSpeed", FALLTHROUGH);
} else if (material.key._flags[graphics::MaterialKey::SCATTERING_VAL_BIT]) {
obj.setProperty("uvAnimationScrollXSpeed", material.uvAnimationScrollXSpeed);
obj.setProperty("uvAnimationScrollYSpeed", material.uvAnimationScrollYSpeed);
obj.setProperty("uvAnimationRotationSpeed", material.uvAnimationRotationSpeed);
}
// OUTLINE_WIDTH_MODE_VAL_BIT = graphics::Material::ExtraFlagBit::EXTRA_1_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::EXTRA_1_BIT)) {
obj.setProperty("outlineWidthMode", FALLTHROUGH);
} else {
obj.setProperty("outlineWidthMode", material.outlineWidthMode);
}
// OUTLINE_WIDTH_VAL_BIT = graphics::Material::ExtraFlagBit::EXTRA_2_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::EXTRA_2_BIT)) {
obj.setProperty("outlineWidth", FALLTHROUGH);
} else {
obj.setProperty("outlineWidth", material.outlineWidth);
}
// OUTLINE_VAL_BIT = graphics::Material::ExtraFlagBit::EXTRA_3_BIT
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::EXTRA_3_BIT)) {
obj.setProperty("outline", FALLTHROUGH);
} else {
obj.setProperty("outline", vec3ColorToScriptValue(engine, material.outline));
}
}
} else if (material.model.toStdString() == graphics::Material::HIFI_SHADER_SIMPLE) { } else if (material.model.toStdString() == graphics::Material::HIFI_SHADER_SIMPLE) {
obj.setProperty("procedural", material.procedural); obj.setProperty("procedural", material.procedural);
} }

View file

@ -27,27 +27,50 @@ scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const
opacity = material.opacity; opacity = material.opacity;
albedo = material.albedo; albedo = material.albedo;
if (model.toStdString() == graphics::Material::HIFI_PBR) { if (model.toStdString() == graphics::Material::HIFI_PBR || model.toStdString() == graphics::Material::VRM_MTOON) {
opacityCutoff = material.opacityCutoff; opacityCutoff = material.opacityCutoff;
opacityMapMode = material.opacityMapMode; opacityMapMode = material.opacityMapMode;
roughness = material.roughness;
metallic = material.metallic;
scattering = material.scattering;
unlit = material.unlit;
emissive = material.emissive; emissive = material.emissive;
emissiveMap = material.emissiveMap; emissiveMap = material.emissiveMap;
albedoMap = material.albedoMap; albedoMap = material.albedoMap;
opacityMap = material.opacityMap; opacityMap = material.opacityMap;
metallicMap = material.metallicMap;
specularMap = material.specularMap;
roughnessMap = material.roughnessMap;
glossMap = material.glossMap;
normalMap = material.normalMap; normalMap = material.normalMap;
bumpMap = material.bumpMap; bumpMap = material.bumpMap;
occlusionMap = material.occlusionMap;
lightMap = material.lightMap;
scatteringMap = material.scatteringMap;
cullFaceMode = material.cullFaceMode; cullFaceMode = material.cullFaceMode;
if (model.toStdString() == graphics::Material::HIFI_PBR) {
roughness = material.roughness;
metallic = material.metallic;
scattering = material.scattering;
unlit = material.unlit;
metallicMap = material.metallicMap;
specularMap = material.specularMap;
roughnessMap = material.roughnessMap;
glossMap = material.glossMap;
occlusionMap = material.occlusionMap;
lightMap = material.lightMap;
scatteringMap = material.scatteringMap;
} else {
shade = material.shade;
shadeMap = material.shadeMap;
shadingShift = material.shadingShift;
shadingShiftMap = material.shadingShiftMap;
shadingToony = material.shadingToony;
matcap = material.matcap;
matcapMap = material.matcapMap;
parametricRim = material.parametricRim;
parametricRimFresnelPower = material.parametricRimFresnelPower;
parametricRimLift = material.parametricRimLift;
rimMap = material.rimMap;
rimLightingMix = material.rimLightingMix;
outlineWidthMode = material.outlineWidthMode;
outlineWidth = material.outlineWidth;
outline = material.outline;
uvAnimationMaskMap = material.uvAnimationMaskMap;
uvAnimationScrollXSpeed = material.uvAnimationScrollXSpeed;
uvAnimationScrollYSpeed = material.uvAnimationScrollYSpeed;
uvAnimationRotationSpeed = material.uvAnimationRotationSpeed;
}
} else if (model.toStdString() == graphics::Material::HIFI_SHADER_SIMPLE) { } else if (model.toStdString() == graphics::Material::HIFI_SHADER_SIMPLE) {
procedural = material.procedural; procedural = material.procedural;
} }
@ -67,13 +90,9 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPoint
opacity = material->getOpacity(); opacity = material->getOpacity();
albedo = material->getAlbedo(); albedo = material->getAlbedo();
if (model.toStdString() == graphics::Material::HIFI_PBR) { if (model.toStdString() == graphics::Material::HIFI_PBR || model.toStdString() == graphics::Material::VRM_MTOON) {
opacityCutoff = material->getOpacityCutoff(); opacityCutoff = material->getOpacityCutoff();
opacityMapMode = QString(graphics::MaterialKey::getOpacityMapModeName(material->getOpacityMapMode()).c_str()); opacityMapMode = QString(graphics::MaterialKey::getOpacityMapModeName(material->getOpacityMapMode()).c_str());
roughness = material->getRoughness();
metallic = material->getMetallic();
scattering = material->getScattering();
unlit = material->isUnlit();
emissive = material->getEmissive(); emissive = material->getEmissive();
auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP); auto map = material->getTextureMap(graphics::Material::MapChannel::EMISSIVE_MAP);
@ -89,24 +108,6 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPoint
} }
} }
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); map = material->getTextureMap(graphics::Material::MapChannel::NORMAL_MAP);
if (map && map->getTextureSource()) { if (map && map->getTextureSource()) {
if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) { if (map->getTextureSource()->getType() == image::TextureUsage::Type::NORMAL_TEXTURE) {
@ -116,26 +117,92 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPoint
} }
} }
map = material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP);
if (map && map->getTextureSource()) {
occlusionMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::LIGHT_MAP);
if (map && map->getTextureSource()) {
lightMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP);
if (map && map->getTextureSource()) {
scatteringMap = map->getTextureSource()->getUrl().toString();
}
for (int i = 0; i < graphics::Material::NUM_TEXCOORD_TRANSFORMS; i++) { for (int i = 0; i < graphics::Material::NUM_TEXCOORD_TRANSFORMS; i++) {
texCoordTransforms[i] = material->getTexCoordTransform(i); texCoordTransforms[i] = material->getTexCoordTransform(i);
} }
cullFaceMode = QString(graphics::MaterialKey::getCullFaceModeName(material->getCullFaceMode()).c_str()); cullFaceMode = QString(graphics::MaterialKey::getCullFaceModeName(material->getCullFaceMode()).c_str());
if (model.toStdString() == graphics::Material::HIFI_PBR) {
roughness = material->getRoughness();
metallic = material->getMetallic();
scattering = material->getScattering();
unlit = material->isUnlit();
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::OCCLUSION_MAP);
if (map && map->getTextureSource()) {
occlusionMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::LIGHT_MAP);
if (map && map->getTextureSource()) {
lightMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP);
if (map && map->getTextureSource()) {
scatteringMap = map->getTextureSource()->getUrl().toString();
}
} else {
shade = material->getShade();
shadingShift = material->getShadingShift();
shadingToony = material->getShadingToony();
matcap = material->getMatcap();
parametricRim = material->getParametricRim();
parametricRimFresnelPower = material->getParametricRimFresnelPower();
parametricRimLift = material->getParametricRimLift();
rimLightingMix = material->getRimLightingMix();
outlineWidthMode = material->getOutlineWidthMode();
outlineWidth = material->getOutlineWidth();
outline = material->getOutline();
uvAnimationScrollXSpeed = material->getUVAnimationScrollXSpeed();
uvAnimationScrollYSpeed = material->getUVAnimationScrollYSpeed();
uvAnimationRotationSpeed = material->getUVAnimationRotationSpeed();
// See the mappings in ProceduralMatericalCache.h
map = material->getTextureMap(graphics::Material::MapChannel::ROUGHNESS_MAP);
if (map && map->getTextureSource()) {
shadeMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::METALLIC_MAP);
if (map && map->getTextureSource()) {
shadingShiftMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::OCCLUSION_MAP);
if (map && map->getTextureSource()) {
matcapMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::SCATTERING_MAP);
if (map && map->getTextureSource()) {
rimMap = map->getTextureSource()->getUrl().toString();
}
map = material->getTextureMap(graphics::Material::MapChannel::LIGHT_MAP);
if (map && map->getTextureSource()) {
uvAnimationMaskMap = map->getTextureSource()->getUrl().toString();
}
}
} else if (model.toStdString() == graphics::Material::HIFI_SHADER_SIMPLE) { } else if (model.toStdString() == graphics::Material::HIFI_SHADER_SIMPLE) {
procedural = material->getProceduralString(); procedural = material->getProceduralString();
} }

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 12/10/2014. // Created by Sam Gateau on 12/10/2014.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -60,7 +61,8 @@ bool MaterialKey::getCullFaceModeFromName(const std::string& modeName, CullFaceM
} }
const std::string Material::HIFI_PBR { "hifi_pbr" }; const std::string Material::HIFI_PBR { "hifi_pbr" };
const std::string Material::HIFI_SHADER_SIMPLE { "hifi_shader_simple" }; const std::string Material::HIFI_SHADER_SIMPLE{ "hifi_shader_simple" };
const std::string Material::VRM_MTOON { "vrm_mtoon" };
Material::Material() { Material::Material() {
for (int i = 0; i < NUM_TOTAL_FLAGS; i++) { for (int i = 0; i < NUM_TOTAL_FLAGS; i++) {
@ -70,8 +72,8 @@ Material::Material() {
Material::Material(const Material& material) : Material::Material(const Material& material) :
_name(material._name), _name(material._name),
_model(material._model),
_key(material._key), _key(material._key),
_model(material._model),
_emissive(material._emissive), _emissive(material._emissive),
_opacity(material._opacity), _opacity(material._opacity),
_albedo(material._albedo), _albedo(material._albedo),
@ -258,6 +260,17 @@ void Material::setTextureTransforms(const Transform& transform, MaterialMappingM
_materialParams = glm::vec2(mode, repeat); _materialParams = glm::vec2(mode, repeat);
} }
const glm::vec3 Material::DEFAULT_SHADE = glm::vec3(0.0f);
const float Material::DEFAULT_SHADING_SHIFT = 0.0f;
const float Material::DEFAULT_SHADING_TOONY = 0.9f;
const glm::vec3 Material::DEFAULT_MATCAP = glm::vec3(1.0f);
const glm::vec3 Material::DEFAULT_PARAMETRIC_RIM = glm::vec3(0.0f);
const float Material::DEFAULT_PARAMETRIC_RIM_FRESNEL_POWER = 5.0f;
const float Material::DEFAULT_PARAMETRIC_RIM_LIFT = 0.0f;
const float Material::DEFAULT_RIM_LIGHTING_MIX = 1.0f;
const float Material::DEFAULT_UV_ANIMATION_SCROLL_SPEED = 0.0f;
const glm::vec3 Material::DEFAULT_OUTLINE = glm::vec3(0.0f);
MultiMaterial::MultiMaterial() { MultiMaterial::MultiMaterial() {
Schema schema; Schema schema;
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema, sizeof(Schema))); _schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema, sizeof(Schema)));
@ -311,3 +324,30 @@ bool MultiMaterial::anyReferenceMaterialsOrTexturesChanged() const {
return false; return false;
} }
void MultiMaterial::setisMToon(bool isMToon) {
if (isMToon != _isMToon) {
if (isMToon) {
MToonSchema toonSchema;
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(MToonSchema), (const gpu::Byte*) &toonSchema, sizeof(MToonSchema)));
} else {
Schema schema;
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema, sizeof(Schema)));
}
}
_isMToon = isMToon;
}
void MultiMaterial::setMToonTime() {
assert(_isMToon);
// Some objects, like material entities, don't have persistent MultiMaterials to store this in, so we just store it once statically
static uint64_t mtoonStartTime;
static std::once_flag once;
std::call_once(once, [] {
mtoonStartTime = usecTimestampNow();
});
// Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds
_schemaBuffer.edit<graphics::MultiMaterial::MToonSchema>()._time = (float)((usecTimestampNow() - mtoonStartTime) / USECS_PER_MSEC) / MSECS_PER_SECOND;
}

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 12/10/2014. // Created by Sam Gateau on 12/10/2014.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -34,6 +35,7 @@ typedef std::shared_ptr< TextureMap > TextureMapPointer;
// Material Key is a coarse trait description of a material used to classify the materials // Material Key is a coarse trait description of a material used to classify the materials
class MaterialKey { class MaterialKey {
public: public:
// Be careful changing these, they need to match up with the bits in graphics/Material.slh
enum FlagBit { enum FlagBit {
EMISSIVE_VAL_BIT = 0, EMISSIVE_VAL_BIT = 0,
UNLIT_VAL_BIT, UNLIT_VAL_BIT,
@ -57,6 +59,12 @@ public:
LIGHT_MAP_BIT, LIGHT_MAP_BIT,
SCATTERING_MAP_BIT, SCATTERING_MAP_BIT,
EXTRA_1_BIT,
EXTRA_2_BIT,
EXTRA_3_BIT,
EXTRA_4_BIT,
EXTRA_5_BIT,
NUM_FLAGS, NUM_FLAGS,
}; };
typedef std::bitset<NUM_FLAGS> Flags; typedef std::bitset<NUM_FLAGS> Flags;
@ -419,6 +427,10 @@ public:
MATERIAL_PARAMS, MATERIAL_PARAMS,
CULL_FACE_MODE, CULL_FACE_MODE,
EXTRA_1_BIT,
EXTRA_2_BIT,
EXTRA_3_BIT,
NUM_TOTAL_FLAGS NUM_TOTAL_FLAGS
}; };
std::unordered_map<uint, bool> getPropertyFallthroughs() { return _propertyFallthroughs; } std::unordered_map<uint, bool> getPropertyFallthroughs() { return _propertyFallthroughs; }
@ -432,15 +444,43 @@ public:
virtual bool isReference() const { return false; } virtual bool isReference() const { return false; }
virtual bool isMToon() const { return false; }
static const glm::vec3 DEFAULT_SHADE;
virtual glm::vec3 getShade(bool SRGB = true) const { return glm::vec3(0.0f); }
static const float DEFAULT_SHADING_SHIFT;
virtual float getShadingShift() const { return 0.0f; }
static const float DEFAULT_SHADING_TOONY;
virtual float getShadingToony() const { return 0.0f; }
static const glm::vec3 DEFAULT_MATCAP;
virtual glm::vec3 getMatcap(bool SRGB = true) const { return glm::vec3(0.0f); }
static const glm::vec3 DEFAULT_PARAMETRIC_RIM;
virtual glm::vec3 getParametricRim(bool SRGB = true) const { return glm::vec3(0.0f); }
static const float DEFAULT_PARAMETRIC_RIM_FRESNEL_POWER;
virtual float getParametricRimFresnelPower() const { return 0.0f; }
static const float DEFAULT_PARAMETRIC_RIM_LIFT;
virtual float getParametricRimLift() const { return 0.0f; }
static const float DEFAULT_RIM_LIGHTING_MIX;
virtual float getRimLightingMix() const { return 0.0f; }
static const float DEFAULT_UV_ANIMATION_SCROLL_SPEED;
virtual float getUVAnimationScrollXSpeed() const { return 0.0f; }
virtual float getUVAnimationScrollYSpeed() const { return 0.0f; }
virtual float getUVAnimationRotationSpeed() const { return 0.0f; }
static const glm::vec3 DEFAULT_OUTLINE;
virtual uint8_t getOutlineWidthMode() { return 0; }
virtual float getOutlineWidth() { return 0.0f; }
virtual glm::vec3 getOutline(bool SRGB = true) const { return glm::vec3(0.0f); }
static const std::string HIFI_PBR; static const std::string HIFI_PBR;
static const std::string HIFI_SHADER_SIMPLE; static const std::string HIFI_SHADER_SIMPLE;
static const std::string VRM_MTOON;
protected: protected:
std::string _name { "" }; std::string _name { "" };
mutable MaterialKey _key { 0 };
private: private:
std::string _model { HIFI_PBR }; std::string _model { HIFI_PBR };
mutable MaterialKey _key { 0 };
// Material properties // Material properties
glm::vec3 _emissive { DEFAULT_EMISSIVE }; glm::vec3 _emissive { DEFAULT_EMISSIVE };
@ -525,12 +565,12 @@ public:
// Texture Coord Transform Array // Texture Coord Transform Array
glm::mat4 _texcoordTransforms[Material::NUM_TEXCOORD_TRANSFORMS]; glm::mat4 _texcoordTransforms[Material::NUM_TEXCOORD_TRANSFORMS];
glm::vec2 _lightmapParams { 0.0, 1.0 };
// x: material mode (0 for UV, 1 for PROJECTED) // x: material mode (0 for UV, 1 for PROJECTED)
// y: 1 for texture repeat, 0 for discard outside of 0 - 1 // y: 1 for texture repeat, 0 for discard outside of 0 - 1
glm::vec2 _materialParams { 0.0, 1.0 }; glm::vec2 _materialParams { 0.0, 1.0 };
glm::vec2 _lightmapParams { 0.0, 1.0 };
Schema() { Schema() {
for (auto& transform : _texcoordTransforms) { for (auto& transform : _texcoordTransforms) {
transform = glm::mat4(); transform = glm::mat4();
@ -538,8 +578,68 @@ public:
} }
}; };
class MToonSchema {
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 _opacityCutoff { Material::DEFAULT_OPACITY_CUTOFF }; // Opacity cutoff applyed when using opacityMap as Mask
glm::vec3 _shade { Material::DEFAULT_SHADE };
float _shadingShift { Material::DEFAULT_SHADING_SHIFT };
glm::vec3 _matcap { Material::DEFAULT_MATCAP };
float _shadingToony { Material::DEFAULT_SHADING_TOONY };
glm::vec3 _parametricRim { Material::DEFAULT_PARAMETRIC_RIM };
float _parametricRimFresnelPower { Material::DEFAULT_PARAMETRIC_RIM_FRESNEL_POWER };
float _parametricRimLift { Material::DEFAULT_PARAMETRIC_RIM_LIFT };
float _rimLightingMix { Material::DEFAULT_RIM_LIGHTING_MIX };
glm::vec2 _uvAnimationScrollSpeed { Material::DEFAULT_UV_ANIMATION_SCROLL_SPEED };
float _uvAnimationScrollRotationSpeed { Material::DEFAULT_UV_ANIMATION_SCROLL_SPEED };
float _time { 0.0f };
uint32_t _key { 0 }; // a copy of the materialKey
float _spare { 0.0f };
// Texture Coord Transform Array
glm::mat4 _texcoordTransforms[Material::NUM_TEXCOORD_TRANSFORMS];
// 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 };
MToonSchema() {
for (auto& transform : _texcoordTransforms) {
transform = glm::mat4();
}
}
};
gpu::BufferView& getSchemaBuffer() { return _schemaBuffer; } gpu::BufferView& getSchemaBuffer() { return _schemaBuffer; }
graphics::MaterialKey getMaterialKey() const { return graphics::MaterialKey(_schemaBuffer.get<graphics::MultiMaterial::Schema>()._key); } graphics::MaterialKey getMaterialKey() const {
if (_isMToon) {
return graphics::MaterialKey(_schemaBuffer.get<graphics::MultiMaterial::MToonSchema>()._key);
} else {
return graphics::MaterialKey(_schemaBuffer.get<graphics::MultiMaterial::Schema>()._key);
}
}
glm::vec4 getColor() const {
glm::vec3 albedo;
float opacity;
if (_isMToon) {
const auto& schema = _schemaBuffer.get<graphics::MultiMaterial::MToonSchema>();
albedo = schema._albedo;
opacity = schema._opacity;
} else {
const auto& schema = _schemaBuffer.get<graphics::MultiMaterial::Schema>();
albedo = schema._albedo;
opacity = schema._opacity;
}
return glm::vec4(ColorUtils::tosRGBVec3(albedo), opacity);
}
const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; } const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; }
void setCullFaceMode(graphics::MaterialKey::CullFaceMode cullFaceMode) { _cullFaceMode = cullFaceMode; } void setCullFaceMode(graphics::MaterialKey::CullFaceMode cullFaceMode) { _cullFaceMode = cullFaceMode; }
@ -559,6 +659,18 @@ public:
void addReferenceTexture(const std::function<gpu::TexturePointer()>& textureOperator); void addReferenceTexture(const std::function<gpu::TexturePointer()>& textureOperator);
void addReferenceMaterial(const std::function<graphics::MaterialPointer()>& materialOperator); void addReferenceMaterial(const std::function<graphics::MaterialPointer()>& materialOperator);
void setisMToon(bool isMToon);
bool isMToon() const { return _isMToon; }
void setMToonTime();
bool hasOutline() const { return _outlineWidthMode != 0 && _outlineWidth > 0.0f; }
uint8_t getOutlineWidthMode() const { return _outlineWidthMode; }
float getOutlineWidth() const { return _outlineWidth; }
glm::vec3 getOutline() const { return _outline; }
void resetOutline() { _outlineWidthMode = 0; _outlineWidth = 0.0f; _outline = glm::vec3(0.0f); }
void setOutlineWidthMode(uint8_t mode) { _outlineWidthMode = mode; }
void setOutlineWidth(float width) { _outlineWidth = width; }
void setOutline(const glm::vec3& outline) { _outline = outline; }
private: private:
gpu::BufferView _schemaBuffer; gpu::BufferView _schemaBuffer;
graphics::MaterialKey::CullFaceMode _cullFaceMode { graphics::Material::DEFAULT_CULL_FACE_MODE }; graphics::MaterialKey::CullFaceMode _cullFaceMode { graphics::Material::DEFAULT_CULL_FACE_MODE };
@ -576,6 +688,11 @@ private:
std::vector<std::pair<std::function<gpu::TexturePointer()>, gpu::TexturePointer>> _referenceTextures; std::vector<std::pair<std::function<gpu::TexturePointer()>, gpu::TexturePointer>> _referenceTextures;
std::vector<std::pair<std::function<graphics::MaterialPointer()>, graphics::MaterialPointer>> _referenceMaterials; std::vector<std::pair<std::function<graphics::MaterialPointer()>, graphics::MaterialPointer>> _referenceMaterials;
bool _isMToon { false };
uint8_t _outlineWidthMode { 0 };
float _outlineWidth { 0.0f };
glm::vec3 _outline { graphics::Material::DEFAULT_OUTLINE };
}; };
}; };

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 12/16/14. // Created by Sam Gateau on 12/16/14.
// Copyright 2013 High Fidelity, Inc. // Copyright 2013 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -18,8 +19,10 @@ const int MAX_TEXCOORDS = 2;
struct TexMapArray { struct TexMapArray {
mat4 _texcoordTransforms0; mat4 _texcoordTransforms0;
mat4 _texcoordTransforms1; mat4 _texcoordTransforms1;
vec2 _lightmapParams;
vec2 _materialParams; vec2 _materialParams;
<@if not HIFI_USE_MTOON@>
vec2 _lightmapParams;
<@endif@>
}; };
<@func declareMaterialTexMapArrayBuffer()@> <@func declareMaterialTexMapArrayBuffer()@>
@ -45,11 +48,24 @@ struct TexMapArray {
// The material values (at least the material key) must be precisely bitwise accurate // The material values (at least the material key) must be precisely bitwise accurate
// to what is provided by the uniform buffer, or the material key has the wrong bits // to what is provided by the uniform buffer, or the material key has the wrong bits
<@if not HIFI_USE_MTOON@>
struct Material { struct Material {
vec4 _emissiveOpacity; vec4 _emissiveOpacity;
vec4 _albedoRoughness; vec4 _albedoRoughness;
vec4 _metallicScatteringOpacityCutoffKey; vec4 _metallicScatteringOpacityCutoffKey;
}; };
<@else@>
struct Material {
vec4 _emissiveOpacity;
vec4 _albedoOpacityCutoff;
vec4 _shadeShadingShift;
vec4 _matcapShadingToony;
vec4 _parametricRimAndFresnelPower;
vec4 _parametricRimLiftMixUVAnimationScrollSpeedXY;
vec4 _uvAnimationScrollRotationSpeedTimeKeySpare;
};
<@endif@>
LAYOUT_STD140(binding=GRAPHICS_BUFFER_MATERIAL) uniform materialBuffer { LAYOUT_STD140(binding=GRAPHICS_BUFFER_MATERIAL) uniform materialBuffer {
Material _mat; Material _mat;
@ -63,39 +79,91 @@ TexMapArray getTexMapArray() {
return _texMapArray; return _texMapArray;
} }
vec3 getMaterialEmissive(Material m) { return m._emissiveOpacity.rgb; } <@if not HIFI_USE_MTOON@>
float getMaterialOpacity(Material m) { return m._emissiveOpacity.a; } vec3 getMaterialEmissive(Material m) { return m._emissiveOpacity.rgb; }
float getMaterialOpacity(Material m) { return m._emissiveOpacity.a; }
vec3 getMaterialAlbedo(Material m) { return m._albedoRoughness.rgb; } vec3 getMaterialAlbedo(Material m) { return m._albedoRoughness.rgb; }
float getMaterialRoughness(Material m) { return m._albedoRoughness.a; } float getMaterialRoughness(Material m) { return m._albedoRoughness.a; }
float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); } float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); }
float getMaterialMetallic(Material m) { return m._metallicScatteringOpacityCutoffKey.x; } float getMaterialMetallic(Material m) { return m._metallicScatteringOpacityCutoffKey.x; }
float getMaterialScattering(Material m) { return m._metallicScatteringOpacityCutoffKey.y; } float getMaterialScattering(Material m) { return m._metallicScatteringOpacityCutoffKey.y; }
float getMaterialOpacityCutoff(Material m) { return m._metallicScatteringOpacityCutoffKey.z; } float getMaterialOpacityCutoff(Material m) { return m._metallicScatteringOpacityCutoffKey.z; }
BITFIELD getMaterialKey(Material m) { return floatBitsToInt(m._metallicScatteringOpacityCutoffKey.w); } BITFIELD getMaterialKey(Material m) { return floatBitsToInt(m._metallicScatteringOpacityCutoffKey.w); }
const BITFIELD EMISSIVE_VAL_BIT = 0x00000001; const BITFIELD EMISSIVE_VAL_BIT = 0x00000001;
const BITFIELD UNLIT_VAL_BIT = 0x00000002; const BITFIELD UNLIT_VAL_BIT = 0x00000002;
const BITFIELD ALBEDO_VAL_BIT = 0x00000004; const BITFIELD ALBEDO_VAL_BIT = 0x00000004;
const BITFIELD METALLIC_VAL_BIT = 0x00000008; const BITFIELD METALLIC_VAL_BIT = 0x00000008;
const BITFIELD GLOSSY_VAL_BIT = 0x00000010; const BITFIELD GLOSSY_VAL_BIT = 0x00000010;
const BITFIELD OPACITY_VAL_BIT = 0x00000020; const BITFIELD OPACITY_VAL_BIT = 0x00000020;
const BITFIELD OPACITY_MASK_MAP_BIT = 0x00000040; const BITFIELD OPACITY_MASK_MAP_BIT = 0x00000040;
const BITFIELD OPACITY_TRANSLUCENT_MAP_BIT = 0x00000080; const BITFIELD OPACITY_TRANSLUCENT_MAP_BIT = 0x00000080;
const BITFIELD OPACITY_MAP_MODE_BIT = 0x00000100; const BITFIELD OPACITY_MAP_MODE_BIT = 0x00000100;
const BITFIELD OPACITY_CUTOFF_VAL_BIT = 0x00000200; const BITFIELD OPACITY_CUTOFF_VAL_BIT = 0x00000200;
const BITFIELD SCATTERING_VAL_BIT = 0x00000400; const BITFIELD SCATTERING_VAL_BIT = 0x00000400;
const BITFIELD EMISSIVE_MAP_BIT = 0x00000800; const BITFIELD EMISSIVE_MAP_BIT = 0x00000800;
const BITFIELD ALBEDO_MAP_BIT = 0x00001000; const BITFIELD ALBEDO_MAP_BIT = 0x00001000;
const BITFIELD METALLIC_MAP_BIT = 0x00002000; const BITFIELD METALLIC_MAP_BIT = 0x00002000;
const BITFIELD ROUGHNESS_MAP_BIT = 0x00004000; const BITFIELD ROUGHNESS_MAP_BIT = 0x00004000;
const BITFIELD NORMAL_MAP_BIT = 0x00008000; const BITFIELD NORMAL_MAP_BIT = 0x00008000;
const BITFIELD OCCLUSION_MAP_BIT = 0x00010000; const BITFIELD OCCLUSION_MAP_BIT = 0x00010000;
const BITFIELD LIGHTMAP_MAP_BIT = 0x00020000; const BITFIELD LIGHTMAP_MAP_BIT = 0x00020000;
const BITFIELD SCATTERING_MAP_BIT = 0x00040000; const BITFIELD SCATTERING_MAP_BIT = 0x00040000;
<@else@>
vec3 getMaterialEmissive(Material m) { return m._emissiveOpacity.rgb; }
float getMaterialOpacity(Material m) { return m._emissiveOpacity.a; }
vec3 getMaterialAlbedo(Material m) { return m._albedoOpacityCutoff.rgb; }
float getMaterialOpacityCutoff(Material m) { return m._albedoOpacityCutoff.z; }
vec3 getMaterialShade(Material m) { return m._shadeShadingShift.rgb; }
float getMaterialShadingShift(Material m) { return m._shadeShadingShift.a; }
vec3 getMaterialMatcap(Material m) { return m._matcapShadingToony.rgb; }
float getMaterialShadingToony(Material m) { return m._matcapShadingToony.a; }
vec3 getMaterialParametricRim(Material m) { return m._parametricRimAndFresnelPower.rgb; }
float getMaterialParametricRimFresnelPower(Material m) { return m._parametricRimAndFresnelPower.a; }
float getMaterialParametricRimLift(Material m) { return m._parametricRimLiftMixUVAnimationScrollSpeedXY.r; }
float getMaterialRimLightingMix(Material m) { return m._parametricRimLiftMixUVAnimationScrollSpeedXY.g; }
vec3 getMaterialUVScrollSpeed(Material m) { return vec3(m._parametricRimLiftMixUVAnimationScrollSpeedXY.ba, m._uvAnimationScrollRotationSpeedTimeKeySpare.r); }
float getMaterialTime(Material m) { return m._uvAnimationScrollRotationSpeedTimeKeySpare.g; }
BITFIELD getMaterialKey(Material m) { return floatBitsToInt(m._uvAnimationScrollRotationSpeedTimeKeySpare.b); }
const BITFIELD EMISSIVE_VAL_BIT = 0x00000001;
const BITFIELD SHADE_VAL_BIT = 0x00000002;
const BITFIELD ALBEDO_VAL_BIT = 0x00000004;
const BITFIELD SHADING_SHIFT_VAL_BIT = 0x00000008;
const BITFIELD SHADING_TOONY_VAL_BIT = 0x00000010;
const BITFIELD OPACITY_VAL_BIT = 0x00000020;
const BITFIELD OPACITY_MASK_MAP_BIT = 0x00000040;
const BITFIELD OPACITY_TRANSLUCENT_MAP_BIT = 0x00000080;
const BITFIELD OPACITY_MAP_MODE_BIT = 0x00000100;
const BITFIELD OPACITY_CUTOFF_VAL_BIT = 0x00000200;
const BITFIELD UV_ANIMATION_SCROLL_VAL_BIT = 0x00000400;
const BITFIELD EMISSIVE_MAP_BIT = 0x00000800;
const BITFIELD ALBEDO_MAP_BIT = 0x00001000;
const BITFIELD SHADING_SHIFT_MAP_BIT = 0x00002000;
const BITFIELD SHADE_MAP_BIT = 0x00004000;
const BITFIELD NORMAL_MAP_BIT = 0x00008000;
const BITFIELD MATCAP_MAP_BIT = 0x00010000;
const BITFIELD UV_ANIMATION_MASK_MAP_BIT = 0x00020000;
const BITFIELD RIM_MAP_BIT = 0x00040000;
const BITFIELD MATCAP_VAL_BIT = 0x00080000;
const BITFIELD PARAMETRIC_RIM_VAL_BIT = 0x00100000;
const BITFIELD PARAMETRIC_RIM_POWER_VAL_BIT = 0x00200000;
const BITFIELD PARAMETRIC_RIM_LIFT_VAL_BIT = 0x00400000;
const BITFIELD RIM_LIGHTING_MIX_VAL_BIT = 0x00800000;
<@endif@>
<@endif@> <@endif@>

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 2/22/16 // Created by Sam Gateau on 2/22/16
// Copyright 2016 High Fidelity, Inc. // Copyright 2016 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -14,10 +15,70 @@
<@include graphics/ShaderConstants.h@> <@include graphics/ShaderConstants.h@>
<@include graphics/Material.slh@> <@include graphics/Material.slh@>
<@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@>
#define TAA_TEXTURE_LOD_BIAS -1.0 #define TAA_TEXTURE_LOD_BIAS -1.0
<@func evalMaterialNormalLOD(fragPosES, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
{
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
// attenuate the normal map divergence from the mesh normal based on distance
// The attenuation range [30,100] meters from the eye is arbitrary for now
vec3 localNormal = mix(<$fetchedNormal$>, vec3(0.0, 1.0, 0.0), smoothstep(30.0, 100.0, (-<$fragPosES$>).z));
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
}
<@endfunc@>
<@func evalMaterialAlbedo(fetchedAlbedo, materialAlbedo, matKey, albedo)@>
{
<$albedo$>.xyz = mix(vec3(1.0), <$materialAlbedo$>, float((<$matKey$> & ALBEDO_VAL_BIT) != 0));
<$albedo$>.xyz *= mix(vec3(1.0), <$fetchedAlbedo$>.xyz, float((<$matKey$> & ALBEDO_MAP_BIT) != 0));
}
<@endfunc@>
<@func evalMaterialOpacityMask(fetchedOpacity, materialOpacityCutoff, materialOpacity, matKey, opacity)@>
{
// This path only valid for opaque or texel opaque material
<$opacity$> = mix(<$materialOpacity$>,
step(<$materialOpacityCutoff$>, <$fetchedOpacity$>),
float((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0));
}
<@endfunc@>
<@func evalMaterialOpacity(fetchedOpacity, materialOpacityCutoff, materialOpacity, matKey, opacity)@>
{
// This path only valid for transparent material
<$opacity$> = mix(<$fetchedOpacity$>,
step(<$materialOpacityCutoff$>, <$fetchedOpacity$>),
float((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0))
* <$materialOpacity$>;
}
<@endfunc@>
<@func evalMaterialEmissive(fetchedEmissive, materialEmissive, matKey, emissive)@>
{
<$emissive$> = mix(<$materialEmissive$>, <$fetchedEmissive$>, float((<$matKey$> & EMISSIVE_MAP_BIT) != 0));
}
<@endfunc@>
<@func discardTransparent(opacity)@>
{
if (<$opacity$> < 1.0) {
discard;
}
}
<@endfunc@>
<@func discardInvisible(opacity)@>
{
if (<$opacity$> <= 0.0) {
discard;
}
}
<@endfunc@>
<@if not HIFI_USE_MTOON@>
<@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@>
<@include gpu/TextureTable.slh@> <@include gpu/TextureTable.slh@>
#ifdef GPU_TEXTURE_TABLE_BINDLESS #ifdef GPU_TEXTURE_TABLE_BINDLESS
@ -41,14 +102,6 @@ vec4 fetchAlbedoMap(vec2 uv) {
} }
<@endif@> <@endif@>
<@if withRoughness@>
#define roughnessMap 4
float fetchRoughnessMap(vec2 uv) {
// Should take into account TAA_TEXTURE_LOD_BIAS?
return tableTexValue(matTex, roughnessMap, uv).r;
}
<@endif@>
<@if withNormal@> <@if withNormal@>
#define normalMap 1 #define normalMap 1
vec3 fetchNormalMap(vec2 uv) { vec3 fetchNormalMap(vec2 uv) {
@ -73,6 +126,14 @@ vec3 fetchEmissiveMap(vec2 uv) {
} }
<@endif@> <@endif@>
<@if withRoughness@>
#define roughnessMap 4
float fetchRoughnessMap(vec2 uv) {
// Should take into account TAA_TEXTURE_LOD_BIAS?
return tableTexValue(matTex, roughnessMap, uv).r;
}
<@endif@>
<@if withOcclusion@> <@if withOcclusion@>
#define occlusionMap 5 #define occlusionMap 5
float fetchOcclusionMap(vec2 uv) { float fetchOcclusionMap(vec2 uv) {
@ -98,13 +159,6 @@ vec4 fetchAlbedoMap(vec2 uv) {
} }
<@endif@> <@endif@>
<@if withRoughness@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS) uniform sampler2D roughnessMap;
float fetchRoughnessMap(vec2 uv) {
return (texture(roughnessMap, uv, TAA_TEXTURE_LOD_BIAS).r);
}
<@endif@>
<@if withNormal@> <@if withNormal@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap; LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap;
vec3 fetchNormalMap(vec2 uv) { vec3 fetchNormalMap(vec2 uv) {
@ -129,6 +183,13 @@ vec3 fetchEmissiveMap(vec2 uv) {
} }
<@endif@> <@endif@>
<@if withRoughness@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS) uniform sampler2D roughnessMap;
float fetchRoughnessMap(vec2 uv) {
return (texture(roughnessMap, uv, TAA_TEXTURE_LOD_BIAS).r);
}
<@endif@>
<@if withOcclusion@> <@if withOcclusion@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_OCCLUSION) uniform sampler2D occlusionMap; LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_OCCLUSION) uniform sampler2D occlusionMap;
float fetchOcclusionMap(vec2 uv) { float fetchOcclusionMap(vec2 uv) {
@ -183,7 +244,6 @@ float fetchScatteringMap(vec2 uv) {
<@endfunc@> <@endfunc@>
<@func declareMaterialLightmap()@> <@func declareMaterialLightmap()@>
<$declareMaterialTexMapArrayBuffer()$> <$declareMaterialTexMapArrayBuffer()$>
@ -195,59 +255,6 @@ vec3 fetchLightMap(vec2 uv) {
} }
<@endfunc@> <@endfunc@>
<@func evalMaterialNormalLOD(fragPosES, fetchedNormal, interpolatedNormal, interpolatedTangent, normal)@>
{
vec3 normalizedNormal = normalize(<$interpolatedNormal$>.xyz);
vec3 normalizedTangent = normalize(<$interpolatedTangent$>.xyz);
vec3 normalizedBitangent = cross(normalizedNormal, normalizedTangent);
// attenuate the normal map divergence from the mesh normal based on distance
// The attenuation range [30,100] meters from the eye is arbitrary for now
vec3 localNormal = mix(<$fetchedNormal$>, vec3(0.0, 1.0, 0.0), smoothstep(30.0, 100.0, (-<$fragPosES$>).z));
<$normal$> = vec3(normalizedBitangent * localNormal.x + normalizedNormal * localNormal.y + normalizedTangent * localNormal.z);
}
<@endfunc@>
<@func evalMaterialAlbedo(fetchedAlbedo, materialAlbedo, matKey, albedo)@>
{
<$albedo$>.xyz = mix(vec3(1.0), <$materialAlbedo$>, float((<$matKey$> & ALBEDO_VAL_BIT) != 0));
<$albedo$>.xyz *= mix(vec3(1.0), <$fetchedAlbedo$>.xyz, float((<$matKey$> & ALBEDO_MAP_BIT) != 0));
}
<@endfunc@>
<@func evalMaterialOpacityMask(fetchedOpacity, materialOpacityCutoff, materialOpacity, matKey, opacity)@>
{
// This path only valid for opaque or texel opaque material
<$opacity$> = mix(<$materialOpacity$>,
step(<$materialOpacityCutoff$>, <$fetchedOpacity$>),
float((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0));
}
<@endfunc@>
<@func evalMaterialOpacity(fetchedOpacity, materialOpacityCutoff, materialOpacity, matKey, opacity)@>
{
// This path only valid for transparent material
<$opacity$> = mix(<$fetchedOpacity$>,
step(<$materialOpacityCutoff$>, <$fetchedOpacity$>),
float((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0))
* <$materialOpacity$>;
}
<@endfunc@>
<@func discardTransparent(opacity)@>
{
if (<$opacity$> < 1.0) {
discard;
}
}
<@endfunc@>
<@func discardInvisible(opacity)@>
{
if (<$opacity$> <= 0.0) {
discard;
}
}
<@endfunc@>
<@func evalMaterialRoughness(fetchedRoughness, materialRoughness, matKey, roughness)@> <@func evalMaterialRoughness(fetchedRoughness, materialRoughness, matKey, roughness)@>
{ {
<$roughness$> = mix(<$materialRoughness$>, <$fetchedRoughness$>, float((<$matKey$> & ROUGHNESS_MAP_BIT) != 0)); <$roughness$> = mix(<$materialRoughness$>, <$fetchedRoughness$>, float((<$matKey$> & ROUGHNESS_MAP_BIT) != 0));
@ -260,12 +267,6 @@ vec3 fetchLightMap(vec2 uv) {
} }
<@endfunc@> <@endfunc@>
<@func evalMaterialEmissive(fetchedEmissive, materialEmissive, matKey, emissive)@>
{
<$emissive$> = mix(<$materialEmissive$>, <$fetchedEmissive$>, float((<$matKey$> & EMISSIVE_MAP_BIT) != 0));
}
<@endfunc@>
<@func evalMaterialOcclusion(fetchedOcclusion, matKey, occlusion)@> <@func evalMaterialOcclusion(fetchedOcclusion, matKey, occlusion)@>
{ {
<$occlusion$> = <$fetchedOcclusion$>; <$occlusion$> = <$fetchedOcclusion$>;
@ -277,5 +278,214 @@ vec3 fetchLightMap(vec2 uv) {
<$scattering$> = mix(<$materialScattering$>, <$fetchedScattering$>, float((<$matKey$> & SCATTERING_MAP_BIT) != 0)); <$scattering$> = mix(<$materialScattering$>, <$fetchedScattering$>, float((<$matKey$> & SCATTERING_MAP_BIT) != 0));
} }
<@endfunc@> <@endfunc@>
<@else@>
<@func declareMToonMaterialTextures(withAlbedo, withNormal, withShade, withEmissive, withShadingShift, withMatcap, withRim, withUVAnimationMask)@>
<@endif@> <@include gpu/TextureTable.slh@>
#ifdef GPU_TEXTURE_TABLE_BINDLESS
TextureTable(0, matTex);
<!
ALBEDO = 0,
NORMAL, 1
SHADE, 2
EMISSIVE, 3
SHADING_SHIFT, 4
MATCAP, 5
RIM, 6
UV_ANIMATION_MASK, 7
!>
<@if withAlbedo@>
#define albedoMap 0
vec4 fetchAlbedoMap(vec2 uv) {
return tableTexValue(matTex, albedoMap, uv);
}
<@endif@>
<@if withNormal@>
#define normalMap 1
vec3 fetchNormalMap(vec2 uv) {
return tableTexValue(matTex, normalMap, uv).xyz;
}
<@endif@>
<@if withShade@>
#define shadeMap 2
vec3 fetchShadeMap(vec2 uv) {
return tableTexValue(matTex, shadeMap, uv).rgb;
}
<@endif@>
<@if withEmissive@>
#define emissiveMap 3
vec3 fetchEmissiveMap(vec2 uv) {
return tableTexValue(matTex, emissiveMap, uv).rgb;
}
<@endif@>
<@if withShadingShift@>
#define shadingShiftMap 4
float fetchShadingShiftMap(vec2 uv) {
return tableTexValue(matTex, shadingShiftMap, uv).r;
}
<@endif@>
<@if withMatcap@>
#define matcapMap 5
vec3 fetchMatcapMap(vec2 uv) {
return tableTexValue(matTex, matcapMap, uv).rgb;
}
<@endif@>
<@if withRim@>
#define rimMap 6
vec3 fetchRimMap(vec2 uv) {
return tableTexValue(matTex, rimMap, uv).rgb;
}
<@endif@>
<@if withUVAnimationMask@>
#define uvAnimationMaskMap 7
float fetchUVAnimationMaskMap(vec2 uv) {
return tableTexValue(matTex, uvAnimationMaskMap, uv).r;
}
<@endif@>
#else
<@if withAlbedo@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_ALBEDO) uniform sampler2D albedoMap;
vec4 fetchAlbedoMap(vec2 uv) {
return texture(albedoMap, uv, TAA_TEXTURE_LOD_BIAS);
}
<@endif@>
<@if withNormal@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap;
vec3 fetchNormalMap(vec2 uv) {
// unpack normal, swizzle to get into hifi tangent space with Y axis pointing out
vec2 t = 2.0 * (texture(normalMap, uv, TAA_TEXTURE_LOD_BIAS).rg - vec2(0.5, 0.5));
vec2 t2 = t*t;
return vec3(t.x, sqrt(max(0.0, 1.0 - t2.x - t2.y)), t.y);
}
<@endif@>
<@if withShade@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_SHADE) uniform sampler2D shadeMap;
vec3 fetchShadeMap(vec2 uv) {
return texture(shadeMap, uv, TAA_TEXTURE_LOD_BIAS).rgb;
}
<@endif@>
<@if withEmissive@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap;
vec3 fetchEmissiveMap(vec2 uv) {
return texture(emissiveMap, uv, TAA_TEXTURE_LOD_BIAS).rgb;
}
<@endif@>
<@if withShadingShift@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_SHADING_SHIFT) uniform sampler2D shadingShiftMap;
float fetchShadingShiftMap(vec2 uv) {
return texture(shadingShiftMap, uv, TAA_TEXTURE_LOD_BIAS).r;
}
<@endif@>
<@if withMatcap@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MATCAP) uniform sampler2D matcapMap;
vec3 fetchMatcapMap(vec2 uv) {
return texture(matcapMap, uv, TAA_TEXTURE_LOD_BIAS).rgb;
}
<@endif@>
<@if withRim@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_RIM) uniform sampler2D rimMap;
vec3 fetchRimMap(vec2 uv) {
return texture(rimMap, uv, TAA_TEXTURE_LOD_BIAS).rgb;
}
<@endif@>
<@if withUVAnimationMask@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_UV_ANIMATION_MASK) uniform sampler2D uvAnimationMaskMap;
float fetchUVAnimationMaskMap(vec2 uv) {
return texture(uvAnimationMaskMap, uv, TAA_TEXTURE_LOD_BIAS).r;
}
<@endif@>
#endif
<@endfunc@>
<@func fetchMToonMaterialTexturesCoord0(matKey, texcoord0, albedo, normal, shade, emissive, shadingShift, rim, uvScrollSpeed, time)@>
if (getTexMapArray()._materialParams.y != 1.0 && clamp(<$texcoord0$>, vec2(0.0), vec2(1.0)) != <$texcoord0$>) {
discard;
}
vec2 texCoord = <$texcoord0$>;
<@if uvScrollSpeed and time@>
if ((<$matKey$> & UV_ANIMATION_SCROLL_VAL_BIT) != 0) {
<$uvScrollSpeed$> *= mix(1.0, fetchUVAnimationMaskMap(texCoord), float((<$matKey$> & UV_ANIMATION_MASK_MAP_BIT) != 0));
<$uvScrollSpeed$> *= time;
float cosTime = cos(<$uvScrollSpeed$>.z);
float sinTime = sin(<$uvScrollSpeed$>.z);
texCoord = (mat3(cosTime, sinTime, 0, -sinTime, cosTime, 0, 0, 0, 1) * vec3(texCoord - vec2(0.5), 1.0)).xy + vec2(0.5) + <$uvScrollSpeed$>.xy;
}
<@endif@>
<@if albedo@>
vec4 <$albedo$> = mix(vec4(1.0), fetchAlbedoMap(texCoord), float((<$matKey$> & (ALBEDO_MAP_BIT | OPACITY_MASK_MAP_BIT | OPACITY_TRANSLUCENT_MAP_BIT)) != 0));
<@endif@>
<@if normal@>
vec3 <$normal$> = mix(vec3(0.0, 1.0, 0.0), fetchNormalMap(texCoord), float((<$matKey$> & NORMAL_MAP_BIT) != 0));
<@endif@>
<@if shade@>
vec3 <$shade$> = float((<$matKey$> & SHADE_MAP_BIT) != 0) * fetchShadeMap(texCoord);
<@endif@>
<@if emissive@>
vec3 <$emissive$> = float((<$matKey$> & EMISSIVE_MAP_BIT) != 0) * fetchEmissiveMap(texCoord);
<@endif@>
<@if shadingShift@>
float <$shadingShift$> = float((<$matKey$> & SHADING_SHIFT_MAP_BIT) != 0) * fetchShadingShiftMap(texCoord);
<@endif@>
<@if rim@>
vec3 <$rim$> = mix(vec3(1.0), fetchRimMap(texCoord), float((<$matKey$> & RIM_MAP_BIT) != 0));
<@endif@>
<@endfunc@>
<@func evalMaterialShade(fetchedShade, materialShade, matKey, shade)@>
{
<$shade$> = mix(vec3(1.0), <$materialShade$>, float((<$matKey$> & SHADE_VAL_BIT) != 0));
<$shade$> *= mix(vec3(1.0), <$fetchedShade$>.rgb, float((<$matKey$> & SHADE_MAP_BIT) != 0));
}
<@endfunc@>
<@func evalMaterialShadingShift(fetchedShadingShift, materialShadingShift, matKey, shadingShift)@>
{
<$shadingShift$> = mix(0.0, <$materialShadingShift$>, float((<$matKey$> & SHADING_SHIFT_VAL_BIT) != 0));
<$shadingShift$> += mix(0.0, <$fetchedShadingShift$>.r, float((<$matKey$> & SHADING_SHIFT_MAP_BIT) != 0));
}
<@endfunc@>
<@func evalMaterialMatcap(texcoord0, materialMatcap, matKey, matcap)@>
{
if ((<$matKey$> & (MATCAP_VAL_BIT | MATCAP_MAP_BIT)) == 0) {
<$matcap$> = vec3(0.0);
} else {
<$matcap$> = mix(vec3(1.0), <$materialMatcap$>, float((<$matKey$> & MATCAP_VAL_BIT) != 0));
<$matcap$> *= mix(vec3(1.0), fetchMatcapMap(<$texcoord0$>), float((<$matKey$> & MATCAP_MAP_BIT) != 0));
}
}
<@endfunc@>
<@func evalMaterialUVScrollSpeed(fetchedUVScrollMask, materialUVScrollMask, matKey, uvScrollSpeed)@>
{
<$uvScrollSpeed$> = mix(vec3(1.0), <$materialUVScrollMask$>, float((<$matKey$> & UV_ANIMATION_MASK_MAP_BIT) != 0));
<$uvScrollSpeed$> *= mix(1.0, <$fetchedUVScrollMask$>.r, float((<$matKey$> & UV_ANIMATION_MASK_MAP_BIT) != 0));
}
<@endfunc@>
<@endif@>
<@endif@>

View file

@ -1,6 +1,7 @@
// <! // <!
// Created by Bradley Austin Davis on 2018/05/25 // Created by Bradley Austin Davis on 2018/05/25
// Copyright 2013-2018 High Fidelity, Inc. // Copyright 2013-2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -28,6 +29,13 @@
#define GRAPHICS_TEXTURE_MATERIAL_OCCLUSION 5 #define GRAPHICS_TEXTURE_MATERIAL_OCCLUSION 5
#define GRAPHICS_TEXTURE_MATERIAL_SCATTERING 6 #define GRAPHICS_TEXTURE_MATERIAL_SCATTERING 6
// Keep aligned with procedural/ProceduralMaterialCache.h
#define GRAPHICS_TEXTURE_MATERIAL_SHADE GRAPHICS_TEXTURE_MATERIAL_METALLIC
#define GRAPHICS_TEXTURE_MATERIAL_SHADING_SHIFT GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS
#define GRAPHICS_TEXTURE_MATERIAL_MATCAP GRAPHICS_TEXTURE_MATERIAL_OCCLUSION
#define GRAPHICS_TEXTURE_MATERIAL_RIM GRAPHICS_TEXTURE_MATERIAL_SCATTERING
#define GRAPHICS_TEXTURE_MATERIAL_UV_ANIMATION_MASK 7
// Make sure these match the ones in render-utils/ShaderConstants.h // Make sure these match the ones in render-utils/ShaderConstants.h
#define GRAPHICS_TEXTURE_SKYBOX 11 #define GRAPHICS_TEXTURE_SKYBOX 11
#define GRAPHICS_BUFFER_SKYBOX_PARAMS 5 #define GRAPHICS_BUFFER_SKYBOX_PARAMS 5
@ -59,7 +67,13 @@ enum Texture {
MaterialRoughness = GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS, MaterialRoughness = GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS,
MaterialOcclusion = GRAPHICS_TEXTURE_MATERIAL_OCCLUSION, MaterialOcclusion = GRAPHICS_TEXTURE_MATERIAL_OCCLUSION,
MaterialScattering = GRAPHICS_TEXTURE_MATERIAL_SCATTERING, MaterialScattering = GRAPHICS_TEXTURE_MATERIAL_SCATTERING,
Skybox = GRAPHICS_TEXTURE_SKYBOX Skybox = GRAPHICS_TEXTURE_SKYBOX,
MaterialShade = GRAPHICS_TEXTURE_MATERIAL_SHADE,
MaterialShadingShift = GRAPHICS_TEXTURE_MATERIAL_SHADING_SHIFT,
MaterialMatcap = GRAPHICS_TEXTURE_MATERIAL_MATCAP,
MaterialRim = GRAPHICS_TEXTURE_MATERIAL_RIM,
MaterialUVAnimationMask = GRAPHICS_TEXTURE_MATERIAL_UV_ANIMATION_MASK,
}; };
} // namespace texture } // namespace texture

View file

@ -1,6 +1,7 @@
// //
// Created by Sam Gondelman on 2/9/2018 // Created by Sam Gondelman on 2/9/2018
// Copyright 2018 High Fidelity, Inc. // Copyright 2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -128,36 +129,35 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseMaterialF
* @typedef {object} Entities.Material * @typedef {object} Entities.Material
* @property {string} name="" - A name for the material. Supported by all material models. * @property {string} name="" - A name for the material. Supported by all material models.
* @property {string} model="hifi_pbr" - Different material models support different properties and rendering modes. * @property {string} model="hifi_pbr" - Different material models support different properties and rendering modes.
* Supported models are: <code>"hifi_pbr"</code>, <code>"hifi_shader_simple"</code>. * Supported models are: <code>"hifi_pbr"</code>, <code>"hifi_shader_simple"</code>, and <code>"vrm_mtoon"</code>.
* @property {ColorFloat|RGBS|string} emissive - The emissive color, i.e., the color that the material emits. A * @property {ColorFloat|RGBS|string} emissive - The emissive color, i.e., the color that the material emits. A
* {@link ColorFloat} value is treated as sRGB and must have component values in the range <code>0.0</code> &ndash; * {@link ColorFloat} value is treated as sRGB and must have component values in the range <code>0.0</code> &ndash;
* <code>1.0</code>. A {@link RGBS} value can be either RGB or sRGB. * <code>1.0</code>. A {@link RGBS} value can be either RGB or sRGB.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>,
* <code>"vrm_mtoon"</code>.
* @property {number|string} opacity=1.0 - The opacity, range <code>0.0</code> &ndash; <code>1.0</code>. * @property {number|string} opacity=1.0 - The opacity, range <code>0.0</code> &ndash; <code>1.0</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> and * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: all.
* <code>"hifi_shader_simple"</code> models only.
* @property {boolean|string} unlit=false - <code>true</code> if the material is unaffected by lighting, <code>false</code> if * @property {boolean|string} unlit=false - <code>true</code> if the material is unaffected by lighting, <code>false</code> if
* it is lit by the key light and local lights. * it is lit by the key light and local lights.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {ColorFloat|RGBS|string} albedo - The albedo color. A {@link ColorFloat} value is treated as sRGB and must have * @property {ColorFloat|RGBS|string} albedo - The albedo color. A {@link ColorFloat} value is treated as sRGB and must have
* component values in the range <code>0.0</code> &ndash; <code>1.0</code>. A {@link RGBS} value can be either RGB or sRGB. * component values in the range <code>0.0</code> &ndash; <code>1.0</code>. A {@link RGBS} value can be either RGB or sRGB.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> and * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: all.
* <code>"hifi_shader_simple"</code> models only.
* @property {number|string} roughness - The roughness, range <code>0.0</code> &ndash; <code>1.0</code>. * @property {number|string} roughness - The roughness, range <code>0.0</code> &ndash; <code>1.0</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {number|string} metallic - The metallicness, range <code>0.0</code> &ndash; <code>1.0</code>. * @property {number|string} metallic - The metallicness, range <code>0.0</code> &ndash; <code>1.0</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {number|string} scattering - The scattering, range <code>0.0</code> &ndash; <code>1.0</code>. * @property {number|string} scattering - The scattering, range <code>0.0</code> &ndash; <code>1.0</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {string} emissiveMap - The URL of the emissive texture image, or an entity ID. An entity ID may be that of an * @property {string} emissiveMap - The URL of the emissive texture image, or an entity ID. An entity ID may be that of an
* Image or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. * Image or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>,
* <code>"hifi_pbr"</code> model only. * <code>"vrm_mtoon"</code>.
* @property {string} albedoMap - The URL of the albedo texture image, or an entity ID. An entity ID may be that of an Image * @property {string} albedoMap - The URL of the albedo texture image, or an entity ID. An entity ID may be that of an Image
* or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> * or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>,
* model only. * <code>"vrm_mtoon"</code>.
* @property {string} opacityMap - The URL of the opacity texture image, or an entity ID. An entity ID may be that of an Image * @property {string} opacityMap - The URL of the opacity texture image, or an entity ID. An entity ID may be that of an Image
* or Web entity. Set the value the same as the <code>albedoMap</code> value for transparency. * or Web entity. Set the value the same as the <code>albedoMap</code> value for transparency. Supported models: <code>"hifi_pbr"</code>,
* <code>"hifi_pbr"</code> model only. * <code>"vrm_mtoon"</code>.
* @property {string} opacityMapMode - The mode defining the interpretation of the opacity map. Values can be: * @property {string} opacityMapMode - The mode defining the interpretation of the opacity map. Values can be:
* <ul> * <ul>
* <li><code>"OPACITY_MAP_OPAQUE"</code> for ignoring the opacity map information.</li> * <li><code>"OPACITY_MAP_OPAQUE"</code> for ignoring the opacity map information.</li>
@ -166,67 +166,113 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseMaterialF
* <li><code>"OPACITY_MAP_BLEND"</code> for using the <code>opacityMap</code> for alpha blending the material surface * <li><code>"OPACITY_MAP_BLEND"</code> for using the <code>opacityMap</code> for alpha blending the material surface
* with the background.</li> * with the background.</li>
* </ul> * </ul>
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: all.
* @property {number|string} opacityCutoff - The opacity cutoff threshold used to determine the opaque texels of the * @property {number|string} opacityCutoff - The opacity cutoff threshold used to determine the opaque texels of the
* <code>opacityMap</code> when <code>opacityMapMode</code> is <code>"OPACITY_MAP_MASK"</code>. Range <code>0.0</code> * <code>opacityMap</code> when <code>opacityMapMode</code> is <code>"OPACITY_MAP_MASK"</code>. Range <code>0.0</code>
* &ndash; <code>1.0</code>. * &ndash; <code>1.0</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: all.
* @property {string} cullFaceMode="CULL_BACK" - The mode defining which side of the geometry should be rendered. Values can be: * @property {string} cullFaceMode="CULL_BACK" - The mode defining which side of the geometry should be rendered. Values can be:
* <ul> * <ul>
* <li><code>"CULL_NONE"</code> to render both sides of the geometry.</li> * <li><code>"CULL_NONE"</code> to render both sides of the geometry.</li>
* <li><code>"CULL_FRONT"</code> to cull the front faces of the geometry.</li> * <li><code>"CULL_FRONT"</code> to cull the front faces of the geometry.</li>
* <li><code>"CULL_BACK"</code> (the default) to cull the back faces of the geometry.</li> * <li><code>"CULL_BACK"</code> (the default) to cull the back faces of the geometry.</li>
* </ul> * </ul>
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: all.
* @property {string} cullFaceMode - The mode defining which side of the geometry should be rendered. Values can be:
* <ul>
* <li><code>"CULL_NONE"</code> for rendering both sides of the geometry.</li>
* <li><code>"CULL_FRONT"</code> for culling the front faces of the geometry.</li>
* <li><code>"CULL_BACK"</code> (the default) for culling the back faces of the geometry.</li>
* </ul>
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only.
* @property {string} roughnessMap - The URL of the roughness texture image. You can use this or <code>glossMap</code>, but not * @property {string} roughnessMap - The URL of the roughness texture image. You can use this or <code>glossMap</code>, but not
* both. * both.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {string} glossMap - The URL of the gloss texture image. You can use this or <code>roughnessMap</code>, but not * @property {string} glossMap - The URL of the gloss texture image. You can use this or <code>roughnessMap</code>, but not
* both. * both.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {string} metallicMap - The URL of the metallic texture image, or an entity ID. An entity ID may be that of an * @property {string} metallicMap - The URL of the metallic texture image, or an entity ID. An entity ID may be that of an
* Image or Web entity. You can use this or <code>specularMap</code>, but not both. * Image or Web entity. You can use this or <code>specularMap</code>, but not both.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {string} specularMap - The URL of the specular texture image, or an entity ID. An entity ID may be that of an * @property {string} specularMap - The URL of the specular texture image, or an entity ID. An entity ID may be that of an
* Image or Web entity. You can use this or <code>metallicMap</code>, but not both. * Image or Web entity. You can use this or <code>metallicMap</code>, but not both.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {string} normalMap - The URL of the normal texture image, or an entity ID. An entity ID may be that of an Image * @property {string} normalMap - The URL of the normal texture image, or an entity ID. An entity ID may be that of an Image
* or Web entity. You can use this or <code>bumpMap</code>, but not both. Set to <code>"fallthrough"</code> to fall * or Web entity. You can use this or <code>bumpMap</code>, but not both. Set to <code>"fallthrough"</code> to fall
* through to the material below. <code>"hifi_pbr"</code> model only. * through to the material below. Supported models: <code>"hifi_pbr"</code>, <code>"vrm_mtoon"</code>.
* @property {string} bumpMap - The URL of the bump texture image, or an entity ID. An entity ID may be that of an Image * @property {string} bumpMap - The URL of the bump texture image, or an entity ID. An entity ID may be that of an Image
* or Web entity. You can use this or <code>normalMap</code>, but not both. Set to <code>"fallthrough"</code> to * or Web entity. You can use this or <code>normalMap</code>, but not both. Set to <code>"fallthrough"</code> to
* fall through to the material below. <code>"hifi_pbr"</code> model only. * fall through to the material below. Supported models: <code>"hifi_pbr"</code>, <code>"vrm_mtoon"</code>.
* @property {string} occlusionMap - The URL of the occlusion texture image, or an entity ID. An entity ID may be that of * @property {string} occlusionMap - The URL of the occlusion texture image, or an entity ID. An entity ID may be that of
* an Image or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. * an Image or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below.
* <code>"hifi_pbr"</code> model only. * Supported models: <code>"hifi_pbr"</code>.
* @property {string} scatteringMap - The URL of the scattering texture image, or an entity ID. An entity ID may be that of an * @property {string} scatteringMap - The URL of the scattering texture image, or an entity ID. An entity ID may be that of an
* Image or Web entity. Only used if <code>normalMap</code> or <code>bumpMap</code> is specified. * Image or Web entity. Only used if <code>normalMap</code> or <code>bumpMap</code> is specified.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {string} lightMap - The URL of the light map texture image, or an entity ID. An entity ID may be that of an Image * @property {string} lightMap - The URL of the light map texture image, or an entity ID. An entity ID may be that of an Image
* or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> * or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* model only.
* @property {Mat4|string} texCoordTransform0 - The transform to use for all of the maps apart from <code>occlusionMap</code> * @property {Mat4|string} texCoordTransform0 - The transform to use for all of the maps apart from <code>occlusionMap</code>
* and <code>lightMap</code>. * and <code>lightMap</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>, <code>"vrm_mtoon"</code>.
* @property {Mat4|string} texCoordTransform1 - The transform to use for <code>occlusionMap</code> and <code>lightMap</code>. * @property {Mat4|string} texCoordTransform1 - The transform to use for <code>occlusionMap</code> and <code>lightMap</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>, <code>"vrm_mtoon"</code>.
* @property {string} lightmapParams - Parameters for controlling how <code>lightMap</code> is used. * @property {string} lightmapParams - Parameters for controlling how <code>lightMap</code> is used.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* <p><em>Currently not used.</em></p> * <p><em>Currently not used.</em></p>
* @property {string} materialParams - Parameters for controlling the material projection and repetition. * @property {string} materialParams - Parameters for controlling the material projection and repetition.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only. * Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>, <code>"vrm_mtoon"</code>.
* <p><em>Currently not used.</em></p> * <p><em>Currently not used.</em></p>
* @property {boolean} defaultFallthrough=false - <code>true</code> if all properties fall through to the material below * @property {boolean} defaultFallthrough=false - <code>true</code> if all properties fall through to the material below
* unless they are set, <code>false</code> if properties respect their individual fall-through settings. * unless they are set, <code>false</code> if properties respect their individual fall-through settings.
* <code>"hifi_pbr"</code> and <code>"hifi_shader_simple"</code> models only. * Supported models: all.
* @property {ProceduralData} procedural - The definition of a procedural shader material. <code>"hifi_shader_simple"</code> model only. * @property {ProceduralData} procedural - The definition of a procedural shader material. Supported models: <code>"hifi_shader_simple"</code>.
* @property {ColorFloat|RGBS|string} shade - The shade color. A {@link ColorFloat} value is treated as sRGB and must have
* component values in the range <code>0.0</code> &ndash; <code>1.0</code>. A {@link RGBS} value can be either RGB or sRGB.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {string} shadeMap - The URL of the shade texture image, or an entity ID. An entity ID may be that of an
* Image or Web entity.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {number|string} shadingShift - The shading shift.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {string} shadingShiftMap - The URL of the shading shift texture image, or an entity ID. An entity ID may be that of an
* Image or Web entity.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {number|string} shadingToony - The shading toony factor. Range <code>0.0</code> &ndash; <code>1.0</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {ColorFloat|RGBS|string} matcap - The matcap color. A {@link ColorFloat} value is treated as sRGB and must have
* component values in the range <code>0.0</code> &ndash; <code>1.0</code>. A {@link RGBS} value can be either RGB or sRGB.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {string} matcapMap - The URL of the matcap texture image, or an entity ID. An entity ID may be that of an
* Image or Web entity.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {ColorFloat|RGBS|string} parametricRim - The rim color. A {@link ColorFloat} value is treated as sRGB and must have
* component values in the range <code>0.0</code> &ndash; <code>1.0</code>. A {@link RGBS} value can be either RGB or sRGB.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {number|string} parametricRimFresnelPower - The parametric rim fresnel exponent.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {number|string} parametricRimLift - The parametric rim lift factor.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {string} rimMap - The URL of the rim texture image, or an entity ID. An entity ID may be that of an
* Image or Web entity.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {number|string} rimLightingMix - How much to mix between the rim color and normal lighting. Range <code>0.0</code>
* &ndash; <code>1.0</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {string} outlineWidthMode="none" - The mode defining how to render the outline. Values can be:
* <ul>
* <li><code>"none"</code> (the default) to not render an outline.</li>
* <li><code>"worldCoordinates"</code> to render an outline with a constant world size, i.e. its apparent size depends on distance.</li>
* <li><code>"screenCoordinates"</code> to render an outline with a constant screen size, i.e. its apparent size remains constant.</li>
* </ul>
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {number|string} outlineWidth - The width of the outline, in meters if <code>outlineWidthMode</code> is <code>"worldCoordinates"</code>,
* or a ratio of the screen height if <code>outlineWidthMode</code> is <code>"screenCoordinates"</code>.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {ColorFloat|RGBS|string} outline - The outline color. A {@link ColorFloat} value is treated as sRGB and must have
* component values in the range <code>0.0</code> &ndash; <code>1.0</code>. A {@link RGBS} value can be either RGB or sRGB.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {string} uvAnimationMaskMap - The URL of the UV animation mask texture image, or an entity ID. An entity ID may be that of an
* Image or Web entity.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {number|string} uvAnimationScrollXSpeed - The speed of the UV scrolling animation in the X dimension, in UV units per second.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {number|string} uvAnimationScrollYSpeed - The speed of the UV scrolling animation in the Y dimension, in UV units per second.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
* @property {number|string} uvAnimationRotationSpeed - The speed of the UV scrolling rotation about (0.5, 0.5), in radians per second.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"vrm_mtoon"</code>.
*/ */
// Note: See MaterialEntityItem.h for default values used in practice. // Note: See MaterialEntityItem.h for default values used in practice.
std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonValue& materialJSONValue, const QUrl& baseUrl) { std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonValue& materialJSONValue, const QUrl& baseUrl) {
@ -254,8 +300,13 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
std::array<glm::mat4, graphics::Material::NUM_TEXCOORD_TRANSFORMS> texcoordTransforms; std::array<glm::mat4, graphics::Material::NUM_TEXCOORD_TRANSFORMS> texcoordTransforms;
const QString FALLTHROUGH("fallthrough"); const QString FALLTHROUGH("fallthrough");
if (modelString == graphics::Material::HIFI_PBR) { if (modelString == graphics::Material::HIFI_PBR || modelString == graphics::Material::VRM_MTOON) {
auto material = std::make_shared<NetworkMaterial>(); std::shared_ptr<NetworkMaterial> material;
if (modelString == graphics::Material::HIFI_PBR) {
material = std::make_shared<NetworkMaterial>();
} else {
material = std::make_shared<NetworkMToonMaterial>();
}
for (auto& key : materialJSON.keys()) { for (auto& key : materialJSON.keys()) {
if (key == "name") { if (key == "name") {
auto nameJSON = materialJSON.value(key); auto nameJSON = materialJSON.value(key);
@ -282,13 +333,6 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
} else if (value.isDouble()) { } else if (value.isDouble()) {
material->setOpacity(value.toDouble()); 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") { } else if (key == "albedo") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) { if (value.isString() && value.toString() == FALLTHROUGH) {
@ -301,21 +345,7 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
material->setAlbedo(color, isSRGB); material->setAlbedo(color, isSRGB);
} }
} }
} else if (key == "roughness") { } else if (key == "opacityMapMode") {
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 == "opacityMapMode") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
auto valueString = value.toString(); auto valueString = value.toString();
@ -348,14 +378,7 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
} }
} }
} }
} else if (key == "scattering") { } else if (key == "emissiveMap") {
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); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
auto valueString = value.toString(); auto valueString = value.toString();
@ -380,46 +403,6 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
material->setAlbedoMap(baseUrl.resolved(valueString), useAlphaChannel); 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") { } else if (key == "normalMap") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
@ -440,36 +423,6 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
material->setNormalMap(baseUrl.resolved(valueString), true); 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::LIGHT_MAP_BIT);
} else {
material->setLightMap(baseUrl.resolved(valueString));
}
}
} else if (key == "texCoordTransform0") { } else if (key == "texCoordTransform0") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
@ -494,15 +447,6 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
glm::mat4 transform = mat4FromVariant(valueVariant); glm::mat4 transform = mat4FromVariant(valueVariant);
texcoordTransforms[1] = transform; texcoordTransforms[1] = transform;
} }
} 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 and update JSDoc
} else if (key == "materialParams") { } else if (key == "materialParams") {
auto value = materialJSON.value(key); auto value = materialJSON.value(key);
if (value.isString()) { if (value.isString()) {
@ -518,6 +462,296 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
material->setDefaultFallthrough(value.toBool()); material->setDefaultFallthrough(value.toBool());
} }
} }
if (modelString == graphics::Material::HIFI_PBR) {
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 == "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 == "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 == "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::LIGHT_MAP_BIT);
} else {
material->setLightMap(baseUrl.resolved(valueString));
}
}
} 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 and update JSDoc
}
} else if (modelString == graphics::Material::VRM_MTOON) {
auto toonMaterial = std::static_pointer_cast<NetworkMToonMaterial>(material);
if (key == "shade") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::SHADE_VAL_BIT);
} else {
glm::vec3 color;
bool isSRGB;
bool valid = parseJSONColor(value, color, isSRGB);
if (valid) {
toonMaterial->setShade(color, isSRGB);
}
}
} else if (key == "shadeMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::SHADE_MAP_BIT);
} else {
toonMaterial->setShadeMap(baseUrl.resolved(valueString));
}
}
} else if (key == "shadingShift") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::SHADING_SHIFT_VAL_BIT);
} else if (value.isDouble()) {
toonMaterial->setShadingShift(value.toDouble());
}
} else if (key == "shadingShiftMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::SHADING_SHIFT_MAP_BIT);
} else {
toonMaterial->setShadingShiftMap(baseUrl.resolved(valueString));
}
}
} else if (key == "shadingToony") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::SHADING_TOONY_VAL_BIT);
} else if (value.isDouble()) {
toonMaterial->setShadingToony(value.toDouble());
}
} else if (key == "matcap") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::MATCAP_VAL_BIT);
} else {
glm::vec3 color;
bool isSRGB;
bool valid = parseJSONColor(value, color, isSRGB);
if (valid) {
toonMaterial->setMatcap(color, isSRGB);
}
}
} else if (key == "matcapMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::MATCAP_MAP_BIT);
} else {
toonMaterial->setMatcapMap(baseUrl.resolved(valueString));
}
}
} else if (key == "parametricRim") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::PARAMETRIC_RIM_VAL_BIT);
} else {
glm::vec3 color;
bool isSRGB;
bool valid = parseJSONColor(value, color, isSRGB);
if (valid) {
toonMaterial->setParametricRim(color, isSRGB);
}
}
} else if (key == "parametricRimFresnelPower") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::PARAMETRIC_RIM_POWER_VAL_BIT);
} else if (value.isDouble()) {
toonMaterial->setParametricRimFresnelPower(value.toDouble());
}
} else if (key == "parametricRimLift") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::PARAMETRIC_RIM_LIFT_VAL_BIT);
} else if (value.isDouble()) {
toonMaterial->setParametricRimLift(value.toDouble());
}
} else if (key == "rimMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::RIM_MAP_BIT);
} else {
toonMaterial->setRimMap(baseUrl.resolved(valueString));
}
}
} else if (key == "rimLightingMix") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::RIM_LIGHTING_MIX_VAL_BIT);
} else if (value.isDouble()) {
toonMaterial->setRimLightingMix(value.toDouble());
}
} else if (key == "uvAnimationMaskMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::UV_ANIMATION_MASK_MAP_BIT);
} else {
toonMaterial->setUVAnimationMaskMap(baseUrl.resolved(valueString));
}
}
} else if (key == "uvAnimationScrollXSpeed") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::UV_ANIMATION_SCROLL_VAL_BIT);
} else if (value.isDouble()) {
toonMaterial->setUVAnimationScrollXSpeed(value.toDouble());
}
} else if (key == "uvAnimationScrollYSpeed") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::UV_ANIMATION_SCROLL_VAL_BIT);
} else if (value.isDouble()) {
toonMaterial->setUVAnimationScrollYSpeed(value.toDouble());
}
} else if (key == "uvAnimationRotationSpeed") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::UV_ANIMATION_SCROLL_VAL_BIT);
} else if (value.isDouble()) {
toonMaterial->setUVAnimationRotationSpeed(value.toDouble());
}
} else if (key == "outlineWidthMode") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::OUTLINE_WIDTH_MODE_VAL_BIT);
} else {
NetworkMToonMaterial::OutlineWidthMode mode;
if (NetworkMToonMaterial::getOutlineWidthModeFromName(valueString.toStdString(), mode)) {
// FIXME: Outlines are currently disabled because they're buggy
//toonMaterial->setOutlineWidthMode(mode);
}
}
}
} else if (key == "outlineWidth") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::OUTLINE_WIDTH_VAL_BIT);
} else if (value.isDouble()) {
toonMaterial->setOutlineWidth(value.toDouble());
}
} else if (key == "outline") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(NetworkMToonMaterial::MToonFlagBit::OUTLINE_VAL_BIT);
} else {
glm::vec3 color;
bool isSRGB;
bool valid = parseJSONColor(value, color, isSRGB);
if (valid) {
toonMaterial->setOutline(color, isSRGB);
}
}
}
// TODO: support outlineWidthTexture and outlineLightingMix
}
} }
// Do this after the texture maps are defined, so it overrides the default transforms // Do this after the texture maps are defined, so it overrides the default transforms
@ -893,3 +1127,138 @@ bool NetworkMaterial::checkResetOpacityMap() {
} }
return false; return false;
} }
NetworkMToonMaterial::NetworkMToonMaterial(const NetworkMToonMaterial& material) :
NetworkMaterial(material),
_shade(material._shade),
_shadingShift(material._shadingShift),
_shadingToony(material._shadingToony),
_matcap(material._matcap),
_parametricRim(material._parametricRim),
_parametricRimFresnelPower(material._parametricRimFresnelPower),
_parametricRimLift(material._parametricRimLift),
_rimLightingMix(material._rimLightingMix),
_uvAnimationScrollXSpeed(material._uvAnimationScrollXSpeed),
_uvAnimationScrollYSpeed(material._uvAnimationScrollYSpeed),
_uvAnimationRotationSpeed(material._uvAnimationRotationSpeed),
_outlineWidthMode(material._outlineWidthMode),
_outlineWidth(material._outlineWidth),
_outline(material._outline)
{}
std::string NetworkMToonMaterial::getOutlineWidthModeName(OutlineWidthMode mode) {
const std::string names[3] = { "none", "worldCoordinates", "screenCoordinates" };
return names[mode];
}
bool NetworkMToonMaterial::getOutlineWidthModeFromName(const std::string& modeName, OutlineWidthMode& mode) {
for (int i = OUTLINE_NONE; i < NUM_OUTLINE_MODES; i++) {
mode = (OutlineWidthMode)i;
if (modeName == getOutlineWidthModeName(mode)) {
return true;
}
}
return false;
}
void NetworkMToonMaterial::setShadeMap(const QUrl& url) {
auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, (MapChannel) MToonMapChannel::SHADE_MAP);
if (map) {
setTextureMap((MapChannel) MToonMapChannel::SHADE_MAP, map);
}
}
void NetworkMToonMaterial::setShadingShiftMap(const QUrl& url) {
auto map = fetchTextureMap(url, image::TextureUsage::ROUGHNESS_TEXTURE, (MapChannel) MToonMapChannel::SHADING_SHIFT_MAP);
if (map) {
setTextureMap((MapChannel) MToonMapChannel::SHADING_SHIFT_MAP, map);
}
}
void NetworkMToonMaterial::setMatcapMap(const QUrl& url) {
auto map = fetchTextureMap(url, image::TextureUsage::EMISSIVE_TEXTURE, (MapChannel)MToonMapChannel::MATCAP_MAP);
if (map) {
setTextureMap((MapChannel) MToonMapChannel::MATCAP_MAP, map);
}
}
void NetworkMToonMaterial::setRimMap(const QUrl& url) {
auto map = fetchTextureMap(url, image::TextureUsage::ALBEDO_TEXTURE, (MapChannel)MToonMapChannel::RIM_MAP);
if (map) {
setTextureMap((MapChannel) MToonMapChannel::RIM_MAP, map);
}
}
void NetworkMToonMaterial::setUVAnimationMaskMap(const QUrl& url) {
auto map = fetchTextureMap(url, image::TextureUsage::ROUGHNESS_TEXTURE, (MapChannel)MToonMapChannel::UV_ANIMATION_MASK_MAP);
if (map) {
setTextureMap((MapChannel) MToonMapChannel::UV_ANIMATION_MASK_MAP, map);
}
}
void NetworkMToonMaterial::setShade(const glm::vec3& shade, bool isSRGB) {
_key._flags.set(NetworkMToonMaterial::MToonFlagBit::SHADE_VAL_BIT, true);
_shade = (isSRGB ? ColorUtils::sRGBToLinearVec3(shade) : shade);
}
void NetworkMToonMaterial::setShadingShift(float shadingShift) {
_key._flags.set(NetworkMToonMaterial::MToonFlagBit::SHADING_SHIFT_VAL_BIT, true);
_shadingShift = shadingShift;
}
void NetworkMToonMaterial::setShadingToony(float shadingToony) {
_key._flags.set(NetworkMToonMaterial::MToonFlagBit::SHADING_TOONY_VAL_BIT, true);
_shadingToony = shadingToony;
}
void NetworkMToonMaterial::setMatcap(const glm::vec3& matcap, bool isSRGB) {
_key._flags.set(MToonFlagBit::MATCAP_VAL_BIT, true);
_matcap = (isSRGB ? ColorUtils::sRGBToLinearVec3(matcap) : matcap);
}
void NetworkMToonMaterial::setParametricRim(const glm::vec3& parametricRim, bool isSRGB) {
_key._flags.set(MToonFlagBit::PARAMETRIC_RIM_VAL_BIT, true);
_parametricRim = (isSRGB ? ColorUtils::sRGBToLinearVec3(parametricRim) : parametricRim);
}
void NetworkMToonMaterial::setParametricRimFresnelPower(float parametricRimFresnelPower) {
_key._flags.set(MToonFlagBit::PARAMETRIC_RIM_POWER_VAL_BIT, true);
_parametricRimFresnelPower = parametricRimFresnelPower;
}
void NetworkMToonMaterial::setParametricRimLift(float parametricRimLift) {
_key._flags.set(MToonFlagBit::PARAMETRIC_RIM_LIFT_VAL_BIT, true);
_parametricRimLift = parametricRimLift;
}
void NetworkMToonMaterial::setRimLightingMix(float rimLightingMix) {
_key._flags.set(MToonFlagBit::RIM_LIGHTING_MIX_VAL_BIT, true);
_rimLightingMix = rimLightingMix;
}
void NetworkMToonMaterial::setUVAnimationScrollXSpeed(float uvAnimationScrollXSpeed) {
_key._flags.set(NetworkMToonMaterial::MToonFlagBit::UV_ANIMATION_SCROLL_VAL_BIT, true);
_uvAnimationScrollXSpeed = uvAnimationScrollXSpeed;
}
void NetworkMToonMaterial::setUVAnimationScrollYSpeed(float uvAnimationScrollYSpeed) {
_key._flags.set(NetworkMToonMaterial::MToonFlagBit::UV_ANIMATION_SCROLL_VAL_BIT, true);
_uvAnimationScrollYSpeed = uvAnimationScrollYSpeed;
}
void NetworkMToonMaterial::setUVAnimationRotationSpeed(float uvAnimationRotationSpeed) {
_key._flags.set(NetworkMToonMaterial::MToonFlagBit::UV_ANIMATION_SCROLL_VAL_BIT, true);
_uvAnimationRotationSpeed = uvAnimationRotationSpeed;
}
void NetworkMToonMaterial::setOutlineWidthMode(OutlineWidthMode mode) {
_outlineWidthMode = mode;
}
void NetworkMToonMaterial::setOutlineWidth(float width) {
_outlineWidth = width;
}
void NetworkMToonMaterial::setOutline(const glm::vec3& outline, bool isSRGB) {
_outline = (isSRGB ? ColorUtils::sRGBToLinearVec3(outline) : outline);
}

View file

@ -1,6 +1,7 @@
// //
// Created by Sam Gondelman on 2/9/2018 // Created by Sam Gondelman on 2/9/2018
// Copyright 2018 High Fidelity, Inc. // Copyright 2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -63,13 +64,14 @@ protected:
const bool& isOriginal() const { return _isOriginal; } const bool& isOriginal() const { return _isOriginal; }
private:
// Helpers for the ctors
QUrl getTextureUrl(const QUrl& baseUrl, const HFMTexture& hfmTexture);
graphics::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const HFMTexture& hfmTexture, graphics::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const HFMTexture& hfmTexture,
image::TextureUsage::Type type, MapChannel channel); image::TextureUsage::Type type, MapChannel channel);
graphics::TextureMapPointer fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel); graphics::TextureMapPointer fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel);
private:
// Helpers for the ctors
QUrl getTextureUrl(const QUrl& baseUrl, const HFMTexture& hfmTexture);
Transform _albedoTransform; Transform _albedoTransform;
Transform _lightmapTransform; Transform _lightmapTransform;
vec2 _lightmapParams; vec2 _lightmapParams;
@ -77,6 +79,120 @@ private:
bool _isOriginal { true }; bool _isOriginal { true };
}; };
class NetworkMToonMaterial : public NetworkMaterial {
public:
NetworkMToonMaterial() : NetworkMaterial() {}
NetworkMToonMaterial(const NetworkMToonMaterial& material);
enum MToonMapChannel {
// Keep aligned with graphics/ShaderConstants.h and graphics-scripting/ScriptableModel.cpp
SHADE_MAP = MapChannel::ROUGHNESS_MAP,
SHADING_SHIFT_MAP = MapChannel::METALLIC_MAP,
MATCAP_MAP = MapChannel::OCCLUSION_MAP,
RIM_MAP = MapChannel::SCATTERING_MAP,
UV_ANIMATION_MASK_MAP = MapChannel::LIGHT_MAP,
};
enum MToonFlagBit {
// Must match mappings in GraphicsScriptingInterface.cpp
SHADE_MAP_BIT = graphics::MaterialKey::FlagBit::ROUGHNESS_MAP_BIT,
SHADING_SHIFT_MAP_BIT = graphics::MaterialKey::FlagBit::METALLIC_MAP_BIT,
MATCAP_MAP_BIT = graphics::MaterialKey::FlagBit::OCCLUSION_MAP_BIT,
RIM_MAP_BIT = graphics::MaterialKey::FlagBit::SCATTERING_MAP_BIT,
UV_ANIMATION_MASK_MAP_BIT = graphics::MaterialKey::FlagBit::LIGHT_MAP_BIT,
SHADE_VAL_BIT = graphics::MaterialKey::FlagBit::UNLIT_VAL_BIT,
SHADING_SHIFT_VAL_BIT = graphics::MaterialKey::FlagBit::METALLIC_VAL_BIT,
SHADING_TOONY_VAL_BIT = graphics::MaterialKey::FlagBit::GLOSSY_VAL_BIT,
UV_ANIMATION_SCROLL_VAL_BIT = graphics::MaterialKey::FlagBit::SCATTERING_VAL_BIT,
MATCAP_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_1_BIT,
PARAMETRIC_RIM_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_2_BIT,
PARAMETRIC_RIM_POWER_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_3_BIT,
PARAMETRIC_RIM_LIFT_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_4_BIT,
RIM_LIGHTING_MIX_VAL_BIT = graphics::MaterialKey::FlagBit::EXTRA_5_BIT,
OUTLINE_WIDTH_MODE_VAL_BIT = graphics::Material::ExtraFlagBit::EXTRA_1_BIT,
OUTLINE_WIDTH_VAL_BIT = graphics::Material::ExtraFlagBit::EXTRA_2_BIT,
OUTLINE_VAL_BIT = graphics::Material::ExtraFlagBit::EXTRA_3_BIT,
};
enum OutlineWidthMode {
OUTLINE_NONE = 0,
OUTLINE_WORLD,
OUTLINE_SCREEN,
NUM_OUTLINE_MODES
};
static std::string getOutlineWidthModeName(OutlineWidthMode mode);
// find the enum value from a string, return true if match found
static bool getOutlineWidthModeFromName(const std::string& modeName, OutlineWidthMode& mode);
bool isMToon() const override { return true; }
void setShadeMap(const QUrl& url);
void setShadingShiftMap(const QUrl& url);
void setMatcapMap(const QUrl& url);
void setRimMap(const QUrl& url);
void setUVAnimationMaskMap(const QUrl& url);
void setShade(const glm::vec3& shade, bool isSRGB = true);
glm::vec3 getShade(bool SRGB = true) const override { return (SRGB ? ColorUtils::tosRGBVec3(_shade) : _shade); }
void setShadingShift(float shadeShift);
float getShadingShift() const override { return _shadingShift; }
void setShadingToony(float shadingToony);
float getShadingToony() const override { return _shadingToony; }
void setMatcap(const glm::vec3& matcap, bool isSRGB = true);
glm::vec3 getMatcap(bool SRGB = true) const override { return (SRGB ? ColorUtils::tosRGBVec3(_matcap) : _matcap); }
void setParametricRim(const glm::vec3& parametricRim, bool isSRGB = true);
glm::vec3 getParametricRim(bool SRGB = true) const override { return (SRGB ? ColorUtils::tosRGBVec3(_parametricRim) : _parametricRim); }
void setParametricRimFresnelPower(float parametricRimFresnelPower);
float getParametricRimFresnelPower() const override { return _parametricRimFresnelPower; }
void setParametricRimLift(float parametricRimLift);
float getParametricRimLift() const override { return _parametricRimLift; }
void setRimLightingMix(float rimLightingMix);
float getRimLightingMix() const override { return _rimLightingMix; }
void setUVAnimationScrollXSpeed(float uvAnimationScrollXSpeed);
float getUVAnimationScrollXSpeed() const override { return _uvAnimationScrollXSpeed; }
void setUVAnimationScrollYSpeed(float uvAnimationScrollYSpeed);
float getUVAnimationScrollYSpeed() const override { return _uvAnimationScrollYSpeed; }
void setUVAnimationRotationSpeed(float uvAnimationRotationSpeed);
float getUVAnimationRotationSpeed() const override { return _uvAnimationRotationSpeed; }
void setOutlineWidthMode(OutlineWidthMode mode);
uint8_t getOutlineWidthMode() override { return _outlineWidthMode; }
void setOutlineWidth(float width);
float getOutlineWidth() override { return _outlineWidth; }
void setOutline(const glm::vec3& outline, bool isSRGB = true);
glm::vec3 getOutline(bool SRGB = true) const override { return (SRGB ? ColorUtils::tosRGBVec3(_outline) : _outline); }
private:
glm::vec3 _shade { DEFAULT_SHADE };
float _shadingShift { DEFAULT_SHADING_SHIFT };
float _shadingToony { DEFAULT_SHADING_TOONY };
glm::vec3 _matcap { DEFAULT_MATCAP };
glm::vec3 _parametricRim { DEFAULT_PARAMETRIC_RIM };
float _parametricRimFresnelPower { DEFAULT_PARAMETRIC_RIM_FRESNEL_POWER };
float _parametricRimLift { DEFAULT_PARAMETRIC_RIM_LIFT };
float _rimLightingMix { DEFAULT_RIM_LIGHTING_MIX };
float _uvAnimationScrollXSpeed { DEFAULT_UV_ANIMATION_SCROLL_SPEED };
float _uvAnimationScrollYSpeed { DEFAULT_UV_ANIMATION_SCROLL_SPEED };
float _uvAnimationRotationSpeed { DEFAULT_UV_ANIMATION_SCROLL_SPEED };
OutlineWidthMode _outlineWidthMode { OutlineWidthMode::OUTLINE_NONE };
float _outlineWidth { 0.0f };
glm::vec3 _outline { DEFAULT_OUTLINE };
};
class NetworkMaterialResource : public Resource { class NetworkMaterialResource : public Resource {
public: public:
NetworkMaterialResource() : Resource() {} NetworkMaterialResource() : Resource() {}

View file

@ -1,6 +1,7 @@
// //
// Created by HifiExperiments on 3/14/2021 // Created by HifiExperiments on 3/14/2021
// Copyright 2021 Vircadia contributors. // Copyright 2021 Vircadia contributors.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -162,7 +163,7 @@ bool ReferenceMaterial::isReady() const {
QString ReferenceMaterial::getProceduralString() const { QString ReferenceMaterial::getProceduralString() const {
return resultWithLock<QString>([&] { return resultWithLock<QString>([&] {
auto material = getMaterial(); auto material = getProceduralMaterial();
return material ? material->getProceduralString() : QString(); return material ? material->getProceduralString() : QString();
}); });
} }
@ -212,6 +213,112 @@ void ReferenceMaterial::initializeProcedural() {
}); });
} }
// MToonMaterial
bool ReferenceMaterial::isMToon() const {
return resultWithLock<bool>([&] {
auto material = getMaterial();
return material ? material->isMToon() : false;
});
}
glm::vec3 ReferenceMaterial::getShade(bool SRGB) const {
return resultWithLock<glm::vec3>([&] {
auto material = getMToonMaterial();
return material ? material->getShade(SRGB) : glm::vec3();
});
}
float ReferenceMaterial::getShadingShift() const {
return resultWithLock<float>([&] {
auto material = getMToonMaterial();
return material ? material->getShadingShift() : 0.0f;
});
}
float ReferenceMaterial::getShadingToony() const {
return resultWithLock<float>([&] {
auto material = getMToonMaterial();
return material ? material->getShadingToony() : 0.0f;
});
}
glm::vec3 ReferenceMaterial::getMatcap(bool SRGB) const {
return resultWithLock<glm::vec3>([&] {
auto material = getMToonMaterial();
return material ? material->getMatcap(SRGB) : glm::vec3();
});
}
glm::vec3 ReferenceMaterial::getParametricRim(bool SRGB) const {
return resultWithLock<glm::vec3>([&] {
auto material = getMToonMaterial();
return material ? material->getParametricRim(SRGB) : glm::vec3();
});
}
float ReferenceMaterial::getParametricRimFresnelPower() const {
return resultWithLock<float>([&] {
auto material = getMToonMaterial();
return material ? material->getParametricRimFresnelPower() : 0.0f;
});
}
float ReferenceMaterial::getParametricRimLift() const {
return resultWithLock<float>([&] {
auto material = getMToonMaterial();
return material ? material->getParametricRimLift() : 0.0f;
});
}
float ReferenceMaterial::getRimLightingMix() const {
return resultWithLock<float>([&] {
auto material = getMToonMaterial();
return material ? material->getRimLightingMix() : 0.0f;
});
}
float ReferenceMaterial::getUVAnimationScrollXSpeed() const {
return resultWithLock<float>([&] {
auto material = getMToonMaterial();
return material ? material->getUVAnimationScrollXSpeed() : 0.0f;
});
}
float ReferenceMaterial::getUVAnimationScrollYSpeed() const {
return resultWithLock<float>([&] {
auto material = getMToonMaterial();
return material ? material->getUVAnimationScrollYSpeed() : 0.0f;
});
}
float ReferenceMaterial::getUVAnimationRotationSpeed() const {
return resultWithLock<float>([&] {
auto material = getMToonMaterial();
return material ? material->getUVAnimationRotationSpeed() : 0.0f;
});
}
uint8_t ReferenceMaterial::getOutlineWidthMode() {
return resultWithLock<uint8_t>([&] {
auto material = getMToonMaterial();
return material ? material->getOutlineWidthMode() : 0;
});
}
float ReferenceMaterial::getOutlineWidth() {
return resultWithLock<float>([&] {
auto material = getMToonMaterial();
return material ? material->getOutlineWidth() : 0.0f;
});
}
glm::vec3 ReferenceMaterial::getOutline(bool SRGB) const {
return resultWithLock<glm::vec3>([&] {
auto material = getMToonMaterial();
return material ? material->getOutline() : glm::vec3(0.0f);
});
}
void ReferenceMaterial::setMaterialForUUIDOperator(std::function<graphics::MaterialPointer(QUuid)> materialForUUIDOperator) { void ReferenceMaterial::setMaterialForUUIDOperator(std::function<graphics::MaterialPointer(QUuid)> materialForUUIDOperator) {
_unboundMaterialForUUIDOperator = materialForUUIDOperator; _unboundMaterialForUUIDOperator = materialForUUIDOperator;
} }
@ -244,6 +351,16 @@ graphics::ProceduralMaterialPointer ReferenceMaterial::getProceduralMaterial() c
return nullptr; return nullptr;
} }
std::shared_ptr<NetworkMToonMaterial> ReferenceMaterial::getMToonMaterial() const {
if (_materialForUUIDOperator) {
std::shared_ptr<NetworkMToonMaterial> result = nullptr;
if (auto material = _materialForUUIDOperator()) {
return std::static_pointer_cast<NetworkMToonMaterial>(material);
}
}
return nullptr;
}
template <typename T, typename F> template <typename T, typename F>
inline T ReferenceMaterial::resultWithLock(F&& f) const { inline T ReferenceMaterial::resultWithLock(F&& f) const {
if (_locked) { if (_locked) {

View file

@ -1,6 +1,7 @@
// //
// Created by HifiExperiments on 3/14/2021 // Created by HifiExperiments on 3/14/2021
// Copyright 2021 Vircadia contributors. // Copyright 2021 Vircadia contributors.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -52,6 +53,23 @@ public:
const uint64_t& created, const ProceduralProgramKey key = ProceduralProgramKey()) override; const uint64_t& created, const ProceduralProgramKey key = ProceduralProgramKey()) override;
void initializeProcedural() override; void initializeProcedural() override;
// MToonMaterial
bool isMToon() const override;
glm::vec3 getShade(bool SRGB = true) const override;
float getShadingShift() const override;
float getShadingToony() const override;
glm::vec3 getMatcap(bool SRGB = true) const override;
glm::vec3 getParametricRim(bool SRGB = true) const override;
float getParametricRimFresnelPower() const override;
float getParametricRimLift() const override;
float getRimLightingMix() const override;
float getUVAnimationScrollXSpeed() const override;
float getUVAnimationScrollYSpeed() const override;
float getUVAnimationRotationSpeed() const override;
uint8_t getOutlineWidthMode() override;
float getOutlineWidth() override;
glm::vec3 getOutline(bool SRGB = true) const override;
bool isReference() const override { return true; } bool isReference() const override { return true; }
std::function<graphics::MaterialPointer()> getReferenceOperator() const { return _materialForUUIDOperator; } std::function<graphics::MaterialPointer()> getReferenceOperator() const { return _materialForUUIDOperator; }
@ -65,6 +83,7 @@ private:
graphics::MaterialPointer getMaterial() const; graphics::MaterialPointer getMaterial() const;
std::shared_ptr<NetworkMaterial> getNetworkMaterial() const; std::shared_ptr<NetworkMaterial> getNetworkMaterial() const;
graphics::ProceduralMaterialPointer getProceduralMaterial() const; graphics::ProceduralMaterialPointer getProceduralMaterial() const;
std::shared_ptr<NetworkMToonMaterial> getMToonMaterial() const;
template <typename T, typename F> template <typename T, typename F>
T resultWithLock(F&& f) const; T resultWithLock(F&& f) const;

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 2/5/15. // Created by Sam Gateau on 2/5/15.
// Copyright 2013 High Fidelity, Inc. // Copyright 2013 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -286,5 +287,78 @@ vec3 evalGlobalLightingAlphaBlended(
} }
<@endfunc@> <@endfunc@>
<@if HIFI_USE_MTOON@>
<@func declareEvalGlobalLightingAlphaBlendedMToon()@>
<$declareLightingAmbient(1, 1, 1)$>
<$declareLightingDirectional()$>
float linearstep(float a, float b, float t) {
return clamp((t - a) / (b - a), 0.0, 1.0);
}
vec3 evalGlobalLightingAlphaBlendedMToon(
mat4 invViewMat, float obscurance, vec3 positionES, vec3 normalWS, vec3 albedo, vec3 fresnel, float metallic, vec3 emissive,
float roughness, float opacity, vec3 shade, float shadingShift, float shadingToony, vec3 matcap,
vec3 parametricRim, float parametricRimFresnelPower, float parametricRimLift, vec3 rim, float rimMix, BITFIELD matKey)
{
<$prepareGlobalLight(positionES, normalWS)$>
SurfaceData surfaceWS = initSurfaceData(roughness, fragNormalWS, fragEyeDirWS);
color += emissive * isEmissiveEnabled();
// Ambient
vec3 ambientDiffuse;
vec3 ambientSpecular;
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, surfaceWS, metallic, fresnel, albedo, obscurance);
color += ambientDiffuse;
color += evalSpecularWithOpacity(ambientSpecular, opacity);
// Directional MToon Shading
updateSurfaceDataWithLight(surfaceWS, lightDirection);
float shading = surfaceWS.ndotl;
shading += shadingShift; // shadingShift includes both the scalar and texture values
shading = linearstep(-1.0 + shadingToony, 1.0 - shadingToony, shading);
color += lightIrradiance * mix(albedo, shade, shading) * isDirectionalEnabled();
vec3 worldViewX = normalize(vec3(surfaceWS.eyeDir.z, 0.0, -surfaceWS.eyeDir.x));
vec3 worldViewY = cross(surfaceWS.eyeDir, worldViewX);
vec2 matcapUV = vec2(dot(worldViewX, surfaceWS.normal), dot(worldViewY, surfaceWS.normal)) * 0.495 + 0.5;
const float epsilon = 0.00001;
vec3 rimDiffuse;
<$evalMaterialMatcap(matcapUV, matcap, matKey, rimDiffuse)$>;
float rimColor = clamp(1.0 - dot(surfaceWS.normal, surfaceWS.eyeDir) + parametricRimLift, 0.0, 1.0);
rimColor = pow(rimColor, max(parametricRimFresnelPower, epsilon));
rimDiffuse += rimColor * parametricRim;
rimDiffuse *= rim;
rimDiffuse = rimDiffuse * mix(vec3(1.0), vec3(0.0), rimMix);
color += rimDiffuse;
// Haze
if (isHazeEnabled() > 0.0) {
if ((hazeParams.hazeMode & HAZE_MODE_IS_KEYLIGHT_ATTENUATED) == HAZE_MODE_IS_KEYLIGHT_ATTENUATED) {
color = computeHazeColorKeyLightAttenuation(color, lightDirection, fragPositionWS);
}
if ((hazeParams.hazeMode & HAZE_MODE_IS_ACTIVE) == HAZE_MODE_IS_ACTIVE) {
vec4 hazeColor = computeHazeColor(
positionES, // fragment position in eye coordinates
fragPositionWS, // fragment position in world coordinates
invViewMat[3].xyz, // eye position in world coordinates
lightDirection // keylight direction vector in world coordinates
);
color = mix(color.rgb, hazeColor.rgb, hazeColor.a);
}
}
return color;
}
<@endfunc@>
<@endif@>
<@endif@> <@endif@>

View file

@ -4,6 +4,7 @@
// //
// Created by Olivier Prat on 08/08/17. // Created by Olivier Prat on 08/08/17.
// Copyright 2017 High Fidelity, Inc. // Copyright 2017 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -40,6 +41,7 @@ namespace gr {
#define OUTLINE_STENCIL_MASK 1 #define OUTLINE_STENCIL_MASK 1
extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter);
extern void sortAndRenderZPassShapes(const ShapePlumberPointer& shapePlumber, const render::RenderContextPointer& renderContext, const render::ShapeBounds& inShapes, render::ItemBounds &itemBounds);
HighlightResources::HighlightResources() { HighlightResources::HighlightResources() {
} }
@ -108,10 +110,14 @@ PrepareDrawHighlight::PrepareDrawHighlight() {
} }
void PrepareDrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { void PrepareDrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
auto destinationFrameBuffer = inputs; RenderArgs* args = renderContext->args;
auto destinationFrameBuffer = inputs;
_resources->update(destinationFrameBuffer); _resources->update(destinationFrameBuffer);
outputs = _resources; outputs.edit0() = _resources;
outputs.edit1() = args->_renderMode;
args->_renderMode = RenderArgs::SHADOW_RENDER_MODE;
} }
gpu::PipelinePointer DrawHighlightMask::_stencilMaskPipeline; gpu::PipelinePointer DrawHighlightMask::_stencilMaskPipeline;
@ -188,61 +194,7 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
batch.setProjectionJitter(jitter.x, jitter.y); batch.setProjectionJitter(jitter.x, jitter.y);
batch.setViewTransform(viewMat); batch.setViewTransform(viewMat);
const std::vector<ShapeKey::Builder> keys = { sortAndRenderZPassShapes(_shapePlumber, renderContext, inShapes, itemBounds);
ShapeKey::Builder(), ShapeKey::Builder().withFade(),
ShapeKey::Builder().withDeformed(), ShapeKey::Builder().withDeformed().withFade(),
ShapeKey::Builder().withDeformed().withDualQuatSkinned(), ShapeKey::Builder().withDeformed().withDualQuatSkinned().withFade(),
ShapeKey::Builder().withOwnPipeline(), ShapeKey::Builder().withOwnPipeline().withFade(),
ShapeKey::Builder().withDeformed().withOwnPipeline(), ShapeKey::Builder().withDeformed().withOwnPipeline().withFade(),
ShapeKey::Builder().withDeformed().withDualQuatSkinned().withOwnPipeline(), ShapeKey::Builder().withDeformed().withDualQuatSkinned().withOwnPipeline().withFade(),
};
std::vector<std::vector<ShapeKey>> sortedShapeKeys(keys.size());
const int OWN_PIPELINE_INDEX = 6;
for (const auto& items : inShapes) {
itemBounds.insert(itemBounds.end(), items.second.begin(), items.second.end());
int index = items.first.hasOwnPipeline() ? OWN_PIPELINE_INDEX : 0;
if (items.first.isDeformed()) {
index += 2;
if (items.first.isDualQuatSkinned()) {
index += 2;
}
}
if (items.first.isFaded()) {
index += 1;
}
sortedShapeKeys[index].push_back(items.first);
}
// Render non-withOwnPipeline things
for (size_t i = 0; i < OWN_PIPELINE_INDEX; i++) {
auto& shapeKeys = sortedShapeKeys[i];
if (shapeKeys.size() > 0) {
const auto& shapePipeline = _shapePlumber->pickPipeline(args, keys[i]);
args->_shapePipeline = shapePipeline;
for (const auto& key : shapeKeys) {
renderShapes(renderContext, _shapePlumber, inShapes.at(key));
}
}
}
// Render withOwnPipeline things
for (size_t i = OWN_PIPELINE_INDEX; i < keys.size(); i++) {
auto& shapeKeys = sortedShapeKeys[i];
if (shapeKeys.size() > 0) {
args->_shapePipeline = nullptr;
for (const auto& key : shapeKeys) {
args->_itemShapeKey = key._flags.to_ulong();
renderShapes(renderContext, _shapePlumber, inShapes.at(key));
}
}
}
args->_shapePipeline = nullptr;
args->_batch = nullptr;
}); });
_boundsBuffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data()); _boundsBuffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data());
@ -452,13 +404,28 @@ const gpu::PipelinePointer& DebugHighlight::getDepthPipeline() {
return _depthPipeline; return _depthPipeline;
} }
void SelectionToHighlight::run(const render::RenderContextPointer& renderContext, Outputs& outputs) { void SelectionToHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
auto scene = renderContext->_scene; auto scene = renderContext->_scene;
auto highlightStage = scene->getStage<render::HighlightStage>(render::HighlightStage::getName()); auto highlightStage = scene->getStage<render::HighlightStage>(render::HighlightStage::getName());
outputs.clear(); auto outlines = inputs.get0();
auto framebuffer = inputs.get1();
outputs.edit0().clear();
outputs.edit1().clear();
_sharedParameters->_highlightIds.fill(render::HighlightStage::INVALID_INDEX); _sharedParameters->_highlightIds.fill(render::HighlightStage::INVALID_INDEX);
outputs.edit1().reserve(outlines.size());
for (auto item : outlines) {
render::HighlightStyle style = scene->getOutlineStyle(item.id, renderContext->args->getViewFrustum() , framebuffer->getHeight());
auto selectionName = "__OUTLINE_MATERIAL" + style.toString();
if (highlightStage->getHighlightIdBySelection(selectionName) == HighlightStage::INVALID_INDEX) {
HighlightStage::Index newIndex = highlightStage->addHighlight(selectionName, style);
outputs.edit1().push_back(newIndex);
}
scene->addItemToSelection(selectionName, item.id);
}
int numLayers = 0; int numLayers = 0;
auto highlightList = highlightStage->getActiveHighlightIds(); auto highlightList = highlightStage->getActiveHighlightIds();
@ -467,8 +434,8 @@ void SelectionToHighlight::run(const render::RenderContextPointer& renderContext
if (!scene->isSelectionEmpty(highlight._selectionName)) { if (!scene->isSelectionEmpty(highlight._selectionName)) {
auto highlightId = highlightStage->getHighlightIdBySelection(highlight._selectionName); auto highlightId = highlightStage->getHighlightIdBySelection(highlight._selectionName);
_sharedParameters->_highlightIds[outputs.size()] = highlightId; _sharedParameters->_highlightIds[outputs.edit0().size()] = highlightId;
outputs.emplace_back(highlight._selectionName); outputs.edit0().emplace_back(highlight._selectionName);
numLayers++; numLayers++;
if (numLayers == HighlightSharedParameters::MAX_PASS_COUNT) { if (numLayers == HighlightSharedParameters::MAX_PASS_COUNT) {
@ -500,6 +467,7 @@ void DrawHighlightTask::configure(const Config& config) {
void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) {
const auto items = inputs.getN<Inputs>(0).get<RenderFetchCullSortTask::BucketList>(); const auto items = inputs.getN<Inputs>(0).get<RenderFetchCullSortTask::BucketList>();
const auto& outlines = items[RenderFetchCullSortTask::OUTLINE];
const auto sceneFrameBuffer = inputs.getN<Inputs>(1); const auto sceneFrameBuffer = inputs.getN<Inputs>(1);
const auto primaryFramebuffer = inputs.getN<Inputs>(2); const auto primaryFramebuffer = inputs.getN<Inputs>(2);
const auto deferredFrameTransform = inputs.getN<Inputs>(3); const auto deferredFrameTransform = inputs.getN<Inputs>(3);
@ -518,16 +486,21 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren
} }
auto sharedParameters = std::make_shared<HighlightSharedParameters>(); auto sharedParameters = std::make_shared<HighlightSharedParameters>();
const auto highlightSelectionNames = task.addJob<SelectionToHighlight>("SelectionToHighlight", sharedParameters); const auto selectionToHighlightInputs = SelectionToHighlight::Inputs(outlines, primaryFramebuffer).asVarying();
const auto highlightSelectionOutputs = task.addJob<SelectionToHighlight>("SelectionToHighlight", selectionToHighlightInputs, sharedParameters);
// Prepare for highlight group rendering. // Prepare for highlight group rendering.
const auto highlightResources = task.addJob<PrepareDrawHighlight>("PrepareHighlight", primaryFramebuffer); const auto prepareOutputs = task.addJob<PrepareDrawHighlight>("PrepareHighlight", primaryFramebuffer);
const auto highlightResources = prepareOutputs.getN<PrepareDrawHighlight::Outputs>(0);
render::Varying highlight0Rect; render::Varying highlight0Rect;
const auto extractSelectionNameInput = Varying(highlightSelectionOutputs.getN<SelectionToHighlight::Outputs>(0));
for (auto i = 0; i < HighlightSharedParameters::MAX_PASS_COUNT; i++) { for (auto i = 0; i < HighlightSharedParameters::MAX_PASS_COUNT; i++) {
const auto selectionName = task.addJob<ExtractSelectionName>("ExtractSelectionName", highlightSelectionNames, i); const auto selectionName = task.addJob<ExtractSelectionName>("ExtractSelectionName", extractSelectionNameInput, i);
const auto groupItems = addSelectItemJobs(task, selectionName, items); const auto groupItems = addSelectItemJobs(task, selectionName, items);
const auto highlightedItemIDs = task.addJob<render::MetaToSubItems>("HighlightMetaToSubItemIDs", groupItems); const auto highlightedSubItemIDs = task.addJob<render::MetaToSubItems>("HighlightMetaToSubItemIDs", groupItems);
const auto appendNonMetaOutlinesInput = AppendNonMetaOutlines::Inputs(highlightedSubItemIDs, groupItems).asVarying();
const auto highlightedItemIDs = task.addJob<AppendNonMetaOutlines>("AppendNonMetaOutlines", appendNonMetaOutlinesInput);
const auto highlightedItems = task.addJob<render::IDsToBounds>("HighlightMetaToSubItems", highlightedItemIDs); const auto highlightedItems = task.addJob<render::IDsToBounds>("HighlightMetaToSubItems", highlightedItemIDs);
// Sort // Sort
@ -557,6 +530,10 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren
task.addJob<DrawHighlight>(name, drawHighlightInputs, i, sharedParameters); task.addJob<DrawHighlight>(name, drawHighlightInputs, i, sharedParameters);
} }
// Cleanup
const auto cleanupInput = HighlightCleanup::Inputs(highlightSelectionOutputs.getN<SelectionToHighlight::Outputs>(1), prepareOutputs.getN<PrepareDrawHighlight::Outputs>(1)).asVarying();
task.addJob<HighlightCleanup>("HighlightCleanup", cleanupInput);
// Debug highlight // Debug highlight
const auto debugInputs = DebugHighlight::Inputs(highlightResources, const_cast<const render::Varying&>(highlight0Rect), jitter, primaryFramebuffer).asVarying(); const auto debugInputs = DebugHighlight::Inputs(highlightResources, const_cast<const render::Varying&>(highlight0Rect), jitter, primaryFramebuffer).asVarying();
task.addJob<DebugHighlight>("HighlightDebug", debugInputs); task.addJob<DebugHighlight>("HighlightDebug", debugInputs);
@ -576,3 +553,31 @@ const render::Varying DrawHighlightTask::addSelectItemJobs(JobModel& task, const
return task.addJob<SelectItems>("TransparentSelection", selectItemInput); return task.addJob<SelectItems>("TransparentSelection", selectItemInput);
} }
void AppendNonMetaOutlines::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
auto& scene = renderContext->_scene;
outputs = inputs.get0();
const auto& groupItems = inputs.get1();
for (auto idBound : groupItems) {
auto& item = scene->getItem(idBound.id);
if (item.exist() && !item.getKey().isMeta()) {
outputs.push_back(idBound.id);
}
}
}
void HighlightCleanup::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
auto scene = renderContext->_scene;
auto highlightStage = scene->getStage<render::HighlightStage>(render::HighlightStage::getName());
for (auto index : inputs.get0()) {
std::string selectionName = highlightStage->getHighlight(index)._selectionName;
highlightStage->removeHighlight(index);
scene->removeSelection(selectionName);
}
// Reset the render mode
renderContext->args->_renderMode = inputs.get1();
}

View file

@ -4,6 +4,7 @@
// //
// Created by Olivier Prat on 08/08/17. // Created by Olivier Prat on 08/08/17.
// Copyright 2017 High Fidelity, Inc. // Copyright 2017 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -65,7 +66,7 @@ using HighlightSharedParametersPointer = std::shared_ptr<HighlightSharedParamete
class PrepareDrawHighlight { class PrepareDrawHighlight {
public: public:
using Inputs = gpu::FramebufferPointer; using Inputs = gpu::FramebufferPointer;
using Outputs = HighlightResourcesPointer; using Outputs = render::VaryingSet2<HighlightResourcesPointer, render::Args::RenderMode>;
using JobModel = render::Job::ModelIO<PrepareDrawHighlight, Inputs, Outputs>; using JobModel = render::Job::ModelIO<PrepareDrawHighlight, Inputs, Outputs>;
PrepareDrawHighlight(); PrepareDrawHighlight();
@ -81,12 +82,13 @@ private:
class SelectionToHighlight { class SelectionToHighlight {
public: public:
using Outputs = std::vector<std::string>; using Inputs = render::VaryingSet2<render::ItemBounds, gpu::FramebufferPointer>;
using JobModel = render::Job::ModelO<SelectionToHighlight, Outputs>; using Outputs = render::VaryingSet2<std::vector<std::string>, std::vector<render::HighlightStage::Index>>;
using JobModel = render::Job::ModelIO<SelectionToHighlight, Inputs, Outputs>;
SelectionToHighlight(HighlightSharedParametersPointer parameters) : _sharedParameters{ parameters } {} SelectionToHighlight(HighlightSharedParametersPointer parameters) : _sharedParameters{ parameters } {}
void run(const render::RenderContextPointer& renderContext, Outputs& outputs); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
private: private:
@ -96,7 +98,7 @@ private:
class ExtractSelectionName { class ExtractSelectionName {
public: public:
using Inputs = SelectionToHighlight::Outputs; using Inputs = std::vector<std::string>;
using Outputs = std::string; using Outputs = std::string;
using JobModel = render::Job::ModelIO<ExtractSelectionName, Inputs, Outputs>; using JobModel = render::Job::ModelIO<ExtractSelectionName, Inputs, Outputs>;
@ -209,6 +211,25 @@ private:
}; };
class AppendNonMetaOutlines {
public:
using Inputs = render::VaryingSet2<render::ItemIDs, render::ItemBounds>;
using Outputs = render::ItemIDs;
using JobModel = render::Job::ModelIO<AppendNonMetaOutlines, Inputs, Outputs>;
AppendNonMetaOutlines() {}
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
};
class HighlightCleanup {
public:
using Inputs = render::VaryingSet2<std::vector<render::HighlightStage::Index>, render::Args::RenderMode>;
using JobModel = render::Job::ModelI<HighlightCleanup, Inputs>;
HighlightCleanup() {}
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs);
};
#endif // hifi_render_utils_HighlightEffect_h #endif // hifi_render_utils_HighlightEffect_h

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 10/3/15. // Created by Sam Gateau on 10/3/15.
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -220,6 +221,10 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
builder.withSubMetaCulled(); builder.withSubMetaCulled();
} }
if (_drawMaterials.hasOutline()) {
builder.withOutline();
}
_itemKey = builder.build(); _itemKey = builder.build();
} }
@ -268,11 +273,15 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode pr
if (hasTangents) { if (hasTangents) {
builder.withTangents(); builder.withTangents();
} }
if (hasLightmap) { if (!_drawMaterials.isMToon()) {
builder.withLightMap(); if (hasLightmap) {
} builder.withLightMap();
if (isUnlit) { }
builder.withUnlit(); if (isUnlit) {
builder.withUnlit();
}
} else {
builder.withMToon();
} }
if (material) { if (material) {
builder.withCullFaceMode(material->getCullFaceMode()); builder.withCullFaceMode(material->getCullFaceMode());
@ -377,6 +386,11 @@ bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set<QUui
return true; return true;
} }
render::HighlightStyle ModelMeshPartPayload::getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const {
return render::HighlightStyle::calculateOutlineStyle(_drawMaterials.getOutlineWidthMode(), _drawMaterials.getOutlineWidth(), _drawMaterials.getOutline(),
_parentTransform.getTranslation(), viewFrustum, height);
}
void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes) { void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes) {
if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) { if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) {
auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex); auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex);
@ -426,4 +440,11 @@ template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Poin
} }
return false; return false;
} }
template <> HighlightStyle payloadGetOutlineStyle(const ModelMeshPartPayload::Pointer& payload, const ViewFrustum& viewFrustum, const size_t height) {
if (payload) {
return payload->getOutlineStyle(viewFrustum, height);
}
return HighlightStyle();
}
} }

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 10/3/15. // Created by Sam Gateau on 10/3/15.
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -17,6 +18,7 @@
#include <gpu/Batch.h> #include <gpu/Batch.h>
#include <render/Scene.h> #include <render/Scene.h>
#include <graphics/Geometry.h> #include <graphics/Geometry.h>
#include <render/HighlightStyle.h>
class ModelMeshPartPayload { class ModelMeshPartPayload {
public: public:
@ -59,6 +61,7 @@ public:
void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; } void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; }
void setBillboardMode(BillboardMode billboardMode) { _billboardMode = billboardMode; } void setBillboardMode(BillboardMode billboardMode) { _billboardMode = billboardMode; }
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const; bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const;
render::HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const;
void addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); } void addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); }
void removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); } void removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); }
@ -107,6 +110,7 @@ namespace render {
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload); template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload);
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones); template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
template <> HighlightStyle payloadGetOutlineStyle(const ModelMeshPartPayload::Pointer& payload, const ViewFrustum& viewFrustum, const size_t height);
} }
#endif // hifi_MeshPartPayload_h #endif // hifi_MeshPartPayload_h

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,7 @@
using namespace render; using namespace render;
extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter);
extern void sortAndRenderZPassShapes(const ShapePlumberPointer& shapePlumber, const render::RenderContextPointer& renderContext, const render::ShapeBounds& inShapes, render::ItemBounds &itemBounds);
void RenderShadowTask::configure(const Config& configuration) { void RenderShadowTask::configure(const Config& configuration) {
//DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.isEnabled()); //DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.isEnabled());
@ -253,58 +254,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
batch.setProjectionTransform(projMat); batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat, false); batch.setViewTransform(viewMat, false);
const std::vector<ShapeKey::Builder> keys = { render::ItemBounds itemBounds;
ShapeKey::Builder(), ShapeKey::Builder().withFade(), sortAndRenderZPassShapes(_shapePlumber, renderContext, inShapes, itemBounds);
ShapeKey::Builder().withDeformed(), ShapeKey::Builder().withDeformed().withFade(),
ShapeKey::Builder().withDeformed().withDualQuatSkinned(), ShapeKey::Builder().withDeformed().withDualQuatSkinned().withFade(),
ShapeKey::Builder().withOwnPipeline(), ShapeKey::Builder().withOwnPipeline().withFade(),
ShapeKey::Builder().withDeformed().withOwnPipeline(), ShapeKey::Builder().withDeformed().withOwnPipeline().withFade(),
ShapeKey::Builder().withDeformed().withDualQuatSkinned().withOwnPipeline(), ShapeKey::Builder().withDeformed().withDualQuatSkinned().withOwnPipeline().withFade(),
};
std::vector<std::vector<ShapeKey>> sortedShapeKeys(keys.size());
const int OWN_PIPELINE_INDEX = 6;
for (const auto& items : inShapes) {
int index = items.first.hasOwnPipeline() ? OWN_PIPELINE_INDEX : 0;
if (items.first.isDeformed()) {
index += 2;
if (items.first.isDualQuatSkinned()) {
index += 2;
}
}
if (items.first.isFaded()) {
index += 1;
}
sortedShapeKeys[index].push_back(items.first);
}
// Render non-withOwnPipeline things
for (size_t i = 0; i < OWN_PIPELINE_INDEX; i++) {
auto& shapeKeys = sortedShapeKeys[i];
if (shapeKeys.size() > 0) {
const auto& shapePipeline = _shapePlumber->pickPipeline(args, keys[i]);
args->_shapePipeline = shapePipeline;
for (const auto& key : shapeKeys) {
renderShapes(renderContext, _shapePlumber, inShapes.at(key));
}
}
}
// Render withOwnPipeline things
for (size_t i = OWN_PIPELINE_INDEX; i < keys.size(); i++) {
auto& shapeKeys = sortedShapeKeys[i];
if (shapeKeys.size() > 0) {
args->_shapePipeline = nullptr;
for (const auto& key : shapeKeys) {
args->_itemShapeKey = key._flags.to_ulong();
renderShapes(renderContext, _shapePlumber, inShapes.at(key));
}
}
}
args->_shapePipeline = nullptr;
} }
args->_batch = nullptr; args->_batch = nullptr;

View file

@ -5,6 +5,7 @@
// //
// Created by Andrzej Kapolka on 5/6/14. // Created by Andrzej Kapolka on 5/6/14.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -15,8 +16,45 @@
<@include render-utils/ShaderConstants.h@> <@include render-utils/ShaderConstants.h@>
<@include CullFace.slh@> <@include CullFace.slh@>
<@if HIFI_USE_MTOON@>
<@if HIFI_USE_SHADOW@>
<$declareMToonMaterialTextures(ALBEDO)$>
<@else@>
<$declareMToonMaterialTextures(ALBEDO, HIFI_USE_NORMALMAP, SHADE, EMISSIVE, SHADING_SHIFT, MATCAP, RIM, UV_ANIMATION_MASK)$>
<@endif@>
<@else@>
<@if HIFI_USE_SHADOW or HIFI_USE_UNLIT@>
<$declareMaterialTextures(ALBEDO)$>
<@else@>
<@if not HIFI_USE_LIGHTMAP@>
<@if HIFI_USE_TRANSLUCENT@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, HIFI_USE_NORMALMAP, METALLIC, EMISSIVE, OCCLUSION)$>
<@else@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, HIFI_USE_NORMALMAP, METALLIC, EMISSIVE, OCCLUSION, SCATTERING)$>
<@endif@>
<@else@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, HIFI_USE_NORMALMAP, METALLIC)$>
<$declareMaterialLightmap()$>
<@endif@>
<@endif@>
<@endif@>
<@if not HIFI_USE_SHADOW@> <@if not HIFI_USE_SHADOW@>
<@if HIFI_USE_FORWARD or HIFI_USE_TRANSLUCENT@> <@if HIFI_USE_MTOON@>
<@include DefaultMaterials.slh@>
<@include GlobalLight.slh@>
<$declareEvalGlobalLightingAlphaBlendedMToon()$>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
<@if HIFI_USE_FORWARD or HIFI_USE_TRANSLUCENT@>
layout(location=0) out vec4 _fragColor0;
<@else@>
<@include DeferredBufferWrite.slh@>
<@endif@>
<@elif HIFI_USE_FORWARD or HIFI_USE_TRANSLUCENT@>
<@include DefaultMaterials.slh@> <@include DefaultMaterials.slh@>
<@include GlobalLight.slh@> <@include GlobalLight.slh@>
<@if HIFI_USE_LIGHTMAP@> <@if HIFI_USE_LIGHTMAP@>
@ -31,6 +69,7 @@
<@endif@> <@endif@>
<@include gpu/Transform.slh@> <@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$> <$declareStandardCameraTransform()$>
layout(location=0) out vec4 _fragColor0; layout(location=0) out vec4 _fragColor0;
<@else@> <@else@>
<@include DeferredBufferWrite.slh@> <@include DeferredBufferWrite.slh@>
@ -43,29 +82,6 @@
<@include LightingModel.slh@> <@include LightingModel.slh@>
<@endif@> <@endif@>
<@if HIFI_USE_SHADOW or HIFI_USE_UNLIT@>
<$declareMaterialTextures(ALBEDO)$>
<@else@>
<@if not HIFI_USE_LIGHTMAP@>
<@if HIFI_USE_NORMALMAP and HIFI_USE_TRANSLUCENT@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL , METALLIC, EMISSIVE, OCCLUSION)$>
<@elif HIFI_USE_NORMALMAP@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL , METALLIC, EMISSIVE, OCCLUSION, SCATTERING)$>
<@elif HIFI_USE_TRANSLUCENT@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL , METALLIC, EMISSIVE, OCCLUSION)$>
<@else@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL , METALLIC, EMISSIVE, OCCLUSION, SCATTERING)$>
<@endif@>
<@else@>
<@if HIFI_USE_NORMALMAP@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, NORMAL, METALLIC)$>
<@else@>
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, METALLIC)$>
<@endif@>
<$declareMaterialLightmap()$>
<@endif@>
<@endif@>
<@if HIFI_USE_FADE@> <@if HIFI_USE_FADE@>
<@include Fade.slh@> <@include Fade.slh@>
<$declareFadeFragment()$> <$declareFadeFragment()$>
@ -78,7 +94,9 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
<@if not HIFI_USE_SHADOW@> <@if not HIFI_USE_SHADOW@>
layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES;
layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS;
layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; <@if not HIFI_USE_MTOON@>
layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color;
<@endif@>
<@if HIFI_USE_NORMALMAP@> <@if HIFI_USE_NORMALMAP@>
layout(location=RENDER_UTILS_ATTR_TANGENT_WS) in vec3 _tangentWS; layout(location=RENDER_UTILS_ATTR_TANGENT_WS) in vec3 _tangentWS;
<@endif@> <@endif@>
@ -101,15 +119,21 @@ void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
BITFIELD matKey = getMaterialKey(mat); BITFIELD matKey = getMaterialKey(mat);
<@if HIFI_USE_SHADOW or HIFI_USE_UNLIT@> <@if HIFI_USE_SHADOW or HIFI_USE_UNLIT@>
<@if not HIFI_USE_MTOON@>
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$> <$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
<@else@>
<$fetchMToonMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
<@endif@>
<@if HIFI_USE_TRANSLUCENT@>
float cutoff = getMaterialOpacityCutoff(mat); float cutoff = getMaterialOpacityCutoff(mat);
float opacity = getMaterialOpacity(mat) * _color.a; <@if HIFI_USE_TRANSLUCENT@>
float opacity = getMaterialOpacity(mat);
<@if not HIFI_USE_MTOON@>
opacity *= _color.a;
<@endif@>
<$evalMaterialOpacity(albedoTex.a, cutoff, opacity, matKey, opacity)$>; <$evalMaterialOpacity(albedoTex.a, cutoff, opacity, matKey, opacity)$>;
<$discardInvisible(opacity)$>; <$discardInvisible(opacity)$>;
<@else@> <@else@>
float cutoff = getMaterialOpacityCutoff(mat);
float opacity = 1.0; float opacity = 1.0;
<$evalMaterialOpacityMask(albedoTex.a, cutoff, opacity, matKey, opacity)$>; <$evalMaterialOpacityMask(albedoTex.a, cutoff, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>; <$discardTransparent(opacity)$>;
@ -118,7 +142,9 @@ void main(void) {
<@if not HIFI_USE_SHADOW@> <@if not HIFI_USE_SHADOW@>
vec3 albedo = getMaterialAlbedo(mat); vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color.rgb; <@if not HIFI_USE_MTOON@>
albedo *= _color.rgb;
<@endif@>
<@if HIFI_USE_FADE@> <@if HIFI_USE_FADE@>
albedo += fadeEmissive; albedo += fadeEmissive;
<@endif@> <@endif@>
@ -134,6 +160,73 @@ void main(void) {
opacity, opacity,
albedo * isUnlitEnabled()); albedo * isUnlitEnabled());
<@endif@> <@endif@>
<@elif HIFI_USE_MTOON@>
vec3 uvScrollSpeed = getMaterialUVScrollSpeed(mat);
float time = getMaterialTime(mat);
<@if HIFI_USE_NORMALMAP@>
<$fetchMToonMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, normalTex, shadeTex, emissiveTex, shadingShiftTex, rimTex, uvScrollSpeed, time)$>
<@else@>
<$fetchMToonMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, _SCRIBE_NULL, shadeTex, emissiveTex, shadingShiftTex, rimTex, uvScrollSpeed, time)$>
<@endif@>
float cutoff = getMaterialOpacityCutoff(mat);
<@if HIFI_USE_TRANSLUCENT@>
float opacity = getMaterialOpacity(mat);
<$evalMaterialOpacity(albedoTex.a, cutoff, opacity, matKey, opacity)$>;
<$discardInvisible(opacity)$>;
<@else@>
float opacity = 1.0;
<$evalMaterialOpacityMask(albedoTex.a, cutoff, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
<@endif@>
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
<@if HIFI_USE_NORMALMAP@>
vec3 fragNormalWS;
<$evalMaterialNormalLOD(_positionES, normalTex, _normalWS, _tangentWS, fragNormalWS)$>
<@else@>
vec3 fragNormalWS = _normalWS;
<@endif@>
fragNormalWS = evalFrontOrBackFaceNormal(normalize(fragNormalWS));
vec3 shade = getMaterialShade(mat);
<$evalMaterialShade(shadeTex, shade, matKey, shade)$>;
float shadingShift = getMaterialShadingShift(mat);
<$evalMaterialShadingShift(shadingShiftTex, shadingShift, matKey, shadingShift)$>;
TransformCamera cam = getTransformCamera();
float metallic = DEFAULT_METALLIC;
vec3 fresnel = getFresnelF0(metallic, albedo);
vec4 color = vec4(evalGlobalLightingAlphaBlendedMToon(
cam._viewInverse, 1.0, _positionES.xyz, fragNormalWS,
albedo, fresnel, metallic, emissive, DEFAULT_ROUGHNESS, opacity,
shade, shadingShift, getMaterialShadingToony(mat), getMaterialMatcap(mat), getMaterialParametricRim(mat),
getMaterialParametricRimFresnelPower(mat), getMaterialParametricRimLift(mat), rimTex, getMaterialRimLightingMix(mat), matKey), opacity);
<@if HIFI_USE_FORWARD or HIFI_USE_TRANSLUCENT@>
_fragColor0 = isUnlitEnabled() * vec4(color.rgb
<@if HIFI_USE_FADE@>
+ fadeEmissive
<@endif@>
, color.a);
<@else@>
packDeferredFragmentUnlit(
fragNormalWS,
1.0,
color.rgb
<@if HIFI_USE_FADE@>
+ fadeEmissive
<@endif@>
);
<@endif@>
<@else@> <@else@>
<@if not HIFI_USE_LIGHTMAP@> <@if not HIFI_USE_LIGHTMAP@>
<@if HIFI_USE_NORMALMAP and HIFI_USE_TRANSLUCENT@> <@if HIFI_USE_NORMALMAP and HIFI_USE_TRANSLUCENT@>
@ -154,14 +247,13 @@ void main(void) {
<@endif@> <@endif@>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmap)$> <$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmap)$>
<@endif@> <@endif@>
<@if HIFI_USE_TRANSLUCENT@>
float cutoff = getMaterialOpacityCutoff(mat); float cutoff = getMaterialOpacityCutoff(mat);
<@if HIFI_USE_TRANSLUCENT@>
float opacity = getMaterialOpacity(mat) * _color.a; float opacity = getMaterialOpacity(mat) * _color.a;
<$evalMaterialOpacity(albedoTex.a, cutoff, opacity, matKey, opacity)$>; <$evalMaterialOpacity(albedoTex.a, cutoff, opacity, matKey, opacity)$>;
<$discardInvisible(opacity)$>; <$discardInvisible(opacity)$>;
<@else@> <@else@>
float cutoff = getMaterialOpacityCutoff(mat);
float opacity = 1.0; float opacity = 1.0;
<$evalMaterialOpacityMask(albedoTex.a, cutoff, opacity, matKey, opacity)$>; <$evalMaterialOpacityMask(albedoTex.a, cutoff, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>; <$discardTransparent(opacity)$>;

View file

@ -5,6 +5,7 @@
// //
// Created by Hifi Engine Team // Created by Hifi Engine Team
// Copyright 2019 High Fidelity, Inc. // Copyright 2019 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -47,7 +48,9 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01;
<@if not HIFI_USE_SHADOW@> <@if not HIFI_USE_SHADOW@>
layout(location=RENDER_UTILS_ATTR_POSITION_ES) out vec4 _positionES; layout(location=RENDER_UTILS_ATTR_POSITION_ES) out vec4 _positionES;
layout(location=RENDER_UTILS_ATTR_NORMAL_WS) out vec3 _normalWS; layout(location=RENDER_UTILS_ATTR_NORMAL_WS) out vec3 _normalWS;
layout(location=RENDER_UTILS_ATTR_COLOR) out vec4 _color; <@if not HIFI_USE_MTOON@>
layout(location=RENDER_UTILS_ATTR_COLOR) out vec4 _color;
<@endif@>
<@if HIFI_USE_NORMALMAP@> <@if HIFI_USE_NORMALMAP@>
layout(location=RENDER_UTILS_ATTR_TANGENT_WS) out vec3 _tangentWS; layout(location=RENDER_UTILS_ATTR_TANGENT_WS) out vec3 _tangentWS;
<@endif@> <@endif@>
@ -96,7 +99,9 @@ void main(void) {
_texCoord01 = vec4(0.0); _texCoord01 = vec4(0.0);
} }
<@else@> <@else@>
<@if not HIFI_USE_MTOON@>
_color = color_sRGBAToLinear(inColor); _color = color_sRGBAToLinear(inColor);
<@endif@>
TexMapArray texMapArray = getTexMapArray(); TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$> <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>

View file

@ -1 +1 @@
DEFINES (normalmap translucent:f unlit:f/lightmap:f)/shadow fade:f/forward:f deformed:v/deformeddq:v DEFINES (normalmap translucent:f unlit:f/lightmap:f)/shadow mtoon fade:f/forward:f deformed:v/deformeddq:v

View file

@ -3,6 +3,7 @@
// Created by Olivier Prat on 11/06/2017. // Created by Olivier Prat on 11/06/2017.
// Copyright 2017 High Fidelity, Inc. // Copyright 2017 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -12,6 +13,7 @@
#define hifi_render_utils_HighlightStyle_h #define hifi_render_utils_HighlightStyle_h
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
#include <glm/gtx/string_cast.hpp>
#include <string> #include <string>
@ -21,23 +23,59 @@ namespace render {
class HighlightStyle { class HighlightStyle {
public: public:
struct RGBA { struct RGBA {
glm::vec3 color{ 1.0f, 0.7f, 0.2f }; glm::vec3 color { 1.0f, 0.7f, 0.2f };
float alpha{ 0.9f }; float alpha { 0.9f };
RGBA(const glm::vec3& c, float a) : color(c), alpha(a) {} RGBA(const glm::vec3& c, float a) : color(c), alpha(a) {}
std::string toString() const { return glm::to_string(color) + " " + std::to_string(alpha); }
}; };
RGBA _outlineUnoccluded{ { 1.0f, 0.7f, 0.2f }, 0.9f }; RGBA _outlineUnoccluded { { 1.0f, 0.7f, 0.2f }, 0.9f };
RGBA _outlineOccluded{ { 1.0f, 0.7f, 0.2f }, 0.9f }; RGBA _outlineOccluded { { 1.0f, 0.7f, 0.2f }, 0.9f };
RGBA _fillUnoccluded{ { 0.2f, 0.7f, 1.0f }, 0.0f }; RGBA _fillUnoccluded { { 0.2f, 0.7f, 1.0f }, 0.0f };
RGBA _fillOccluded{ { 0.2f, 0.7f, 1.0f }, 0.0f }; RGBA _fillOccluded { { 0.2f, 0.7f, 1.0f }, 0.0f };
float _outlineWidth{ 2.0f }; float _outlineWidth { 2.0f };
bool _isOutlineSmooth{ false }; bool _isOutlineSmooth { false };
bool isFilled() const { bool isFilled() const {
return _fillUnoccluded.alpha > 5e-3f || _fillOccluded.alpha > 5e-3f; return _fillUnoccluded.alpha > 5e-3f || _fillOccluded.alpha > 5e-3f;
} }
std::string toString() const {
return _outlineUnoccluded.toString() + _outlineOccluded.toString() + _fillUnoccluded.toString() +
_fillOccluded.toString() + std::to_string(_outlineWidth) + std::to_string(_isOutlineSmooth);
}
static HighlightStyle calculateOutlineStyle(uint8_t mode, float outlineWidth, const glm::vec3& outline,
const glm::vec3& position, const ViewFrustum& viewFrustum, size_t screenHeight) {
HighlightStyle style;
style._outlineUnoccluded.color = outline;
style._outlineUnoccluded.alpha = 1.0f;
style._outlineOccluded.alpha = 0.0f;
style._fillUnoccluded.alpha = 0.0f;
style._fillOccluded.alpha = 0.0f;
style._isOutlineSmooth = false;
if (mode == 1) { // OUTLINE_WORLD
// FIXME: this is a hacky approximation, which gives us somewhat accurate widths with distance based falloff.
// Our outline implementation doesn't support the necessary vertex based extrusion to do real world based outlines.
glm::vec4 viewPos = glm::inverse(viewFrustum.getView()) * glm::vec4(position, 1.0f);
const glm::mat4& projection = viewFrustum.getProjection();
glm::vec4 p1 = projection * (viewPos + glm::vec4(0.0f, 0.5f * outlineWidth, 0.0f, 0.0f));
p1 /= p1.w;
glm::vec4 p2 = projection * (viewPos - glm::vec4(0.0f, 0.5f * outlineWidth, 0.0f, 0.0f));
p2 /= p2.w;
style._outlineWidth = floor(0.5f * (float)screenHeight * fabs(p1.y - p2.y));
} else { // OUTLINE_SCREEN
style._outlineWidth = floor(outlineWidth * (float)screenHeight);
}
return style;
}
}; };
} }

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 1/26/16. // Created by Sam Gateau on 1/26/16.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -160,4 +161,11 @@ namespace render {
} }
return payload->passesZoneOcclusionTest(containingZones); return payload->passesZoneOcclusionTest(containingZones);
} }
}
template <> HighlightStyle payloadGetOutlineStyle(const PayloadProxyInterface::Pointer& payload, const ViewFrustum& viewFrustum, const size_t height) {
if (!payload) {
return HighlightStyle();
}
return payload->getOutlineStyle(viewFrustum, height);
}
}

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 1/26/16. // Created by Sam Gateau on 1/26/16.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -29,6 +30,7 @@
#include "ShapePipeline.h" #include "ShapePipeline.h"
#include "BlendshapeConstants.h" #include "BlendshapeConstants.h"
#include "HighlightStyle.h"
namespace render { namespace render {
@ -104,15 +106,17 @@ public:
META_CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the view META_CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the view
SUB_META_CULLED, // As a sub item of a meta render item set as cull group, need to be set to my culling to the meta render it SUB_META_CULLED, // As a sub item of a meta render item set as cull group, need to be set to my culling to the meta render it
FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against
LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS, LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS,
FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer
LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS, LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS,
OUTLINE, // Item has an outline
__SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells)
NUM_FLAGS, // Not a valid flag NUM_FLAGS, // Not a valid flag
}; };
typedef std::bitset<NUM_FLAGS> Flags; typedef std::bitset<NUM_FLAGS> Flags;
@ -170,6 +174,9 @@ public:
Builder& withLayer(uint8_t layer) { _flags = evalLayerBitsWithKeyBits(layer, _flags.to_ulong()); return (*this); } Builder& withLayer(uint8_t layer) { _flags = evalLayerBitsWithKeyBits(layer, _flags.to_ulong()); return (*this); }
Builder& withoutLayer() { return withLayer(LAYER_DEFAULT); } Builder& withoutLayer() { return withLayer(LAYER_DEFAULT); }
Builder& withOutline() { _flags.set(OUTLINE); return (*this); }
Builder& withoutOutline() { _flags.reset(OUTLINE); return (*this); }
// Convenient standard keys that we will keep on using all over the place // Convenient standard keys that we will keep on using all over the place
static Builder opaqueShape() { return Builder().withTypeShape(); } static Builder opaqueShape() { return Builder().withTypeShape(); }
static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); }
@ -213,6 +220,8 @@ public:
bool isLayered() const { return getLayer() != LAYER_DEFAULT; } bool isLayered() const { return getLayer() != LAYER_DEFAULT; }
bool isSpatial() const { return !isLayered(); } bool isSpatial() const { return !isLayered(); }
bool isOutline() const { return _flags[OUTLINE]; }
// Probably not public, flags used by the scene // Probably not public, flags used by the scene
bool isSmall() const { return _flags[__SMALLER]; } bool isSmall() const { return _flags[__SMALLER]; }
void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); } void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); }
@ -284,6 +293,9 @@ public:
Builder& withoutLayered() { _value = ItemKey::evalLayerBitsWithKeyBits(ItemKey::LAYER_DEFAULT, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); } Builder& withoutLayered() { _value = ItemKey::evalLayerBitsWithKeyBits(ItemKey::LAYER_DEFAULT, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); }
Builder& withLayer(uint8_t layer) { _value = ItemKey::evalLayerBitsWithKeyBits(layer, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); } Builder& withLayer(uint8_t layer) { _value = ItemKey::evalLayerBitsWithKeyBits(layer, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); }
Builder& withoutOutline() { _value.reset(ItemKey::OUTLINE); _mask.set(ItemKey::OUTLINE); return (*this); }
Builder& withOutline() { _value.set(ItemKey::OUTLINE); _mask.set(ItemKey::OUTLINE); return (*this); }
Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); } Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); }
// Convenient standard keys that we will keep on using all over the place // Convenient standard keys that we will keep on using all over the place
@ -440,6 +452,8 @@ public:
virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0; virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0;
virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const = 0;
~PayloadInterface() {} ~PayloadInterface() {}
// Status interface is local to the base class // Status interface is local to the base class
@ -493,6 +507,8 @@ public:
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); } bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); }
HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const { return _payload->getOutlineStyle(viewFrustum, height); }
// Access the status // Access the status
const StatusPointer& getStatus() const { return _payload->getStatus(); } const StatusPointer& getStatus() const { return _payload->getStatus(); }
@ -547,6 +563,12 @@ template <class T> uint32_t metaFetchMetaSubItems(const std::shared_ptr<T>& payl
// Allows payloads to determine if they should render or not, based on the zones that contain the current camera // Allows payloads to determine if they should render or not, based on the zones that contain the current camera
template <class T> bool payloadPassesZoneOcclusionTest(const std::shared_ptr<T>& payloadData, const std::unordered_set<QUuid>& containingZones) { return true; } template <class T> bool payloadPassesZoneOcclusionTest(const std::shared_ptr<T>& payloadData, const std::unordered_set<QUuid>& containingZones) { return true; }
// Outline Interface
// Allows payloads to specify an outline style
template <class T> HighlightStyle payloadGetOutlineStyle(const std::shared_ptr<T>& payloadData, const ViewFrustum& viewFrustum, const size_t height) {
return HighlightStyle();
}
// THe Payload class is the real Payload to be used // THe Payload class is the real Payload to be used
// THis allow anything to be turned into a Payload as long as the required interface functions are available // THis allow anything to be turned into a Payload as long as the required interface functions are available
// When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff" // When creating a new kind of payload from a new "stuff" class then you need to create specialized version for "stuff"
@ -573,6 +595,8 @@ public:
virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override { return payloadPassesZoneOcclusionTest<T>(_data, containingZones); } virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const override { return payloadPassesZoneOcclusionTest<T>(_data, containingZones); }
virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const override { return payloadGetOutlineStyle<T>(_data, viewFrustum, height); }
protected: protected:
DataPointer _data; DataPointer _data;
@ -628,6 +652,7 @@ public:
virtual void render(RenderArgs* args) = 0; virtual void render(RenderArgs* args) = 0;
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0;
virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0; virtual bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& containingZones) const = 0;
virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const = 0;
// FIXME: this isn't the best place for this since it's only used for ModelEntities, but currently all Entities use PayloadProxyInterface // FIXME: this isn't the best place for this since it's only used for ModelEntities, but currently all Entities use PayloadProxyInterface
virtual void handleBlendedVertices(int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets, virtual void handleBlendedVertices(int blendshapeNumber, const QVector<BlendshapeOffset>& blendshapeOffsets,
@ -640,6 +665,7 @@ template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, Re
template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems); template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems);
template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload); template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload);
template <> bool payloadPassesZoneOcclusionTest(const PayloadProxyInterface::Pointer& payload, const std::unordered_set<QUuid>& containingZones); template <> bool payloadPassesZoneOcclusionTest(const PayloadProxyInterface::Pointer& payload, const std::unordered_set<QUuid>& containingZones);
template <> HighlightStyle payloadGetOutlineStyle(const PayloadProxyInterface::Pointer& payload, const ViewFrustum& viewFrustum, const size_t height);
typedef Item::PayloadPointer PayloadPointer; typedef Item::PayloadPointer PayloadPointer;
typedef std::vector<PayloadPointer> Payloads; typedef std::vector<PayloadPointer> Payloads;

View file

@ -4,6 +4,7 @@
// //
// Created by Zach Pomerantz on 12/22/2016. // Created by Zach Pomerantz on 12/22/2016.
// Copyright 2016 High Fidelity, Inc. // Copyright 2016 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -35,18 +36,20 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchLayeredSelection", nonspatialFilter); const auto nonspatialSelection = task.addJob<FetchNonspatialItems>("FetchLayeredSelection", nonspatialFilter);
// Multi filter visible items into different buckets // Multi filter visible items into different buckets
const int NUM_SPATIAL_FILTERS = 4; const int NUM_SPATIAL_FILTERS = 5;
const int NUM_NON_SPATIAL_FILTERS = 3; const int NUM_NON_SPATIAL_FILTERS = 3;
const int OPAQUE_SHAPE_BUCKET = 0; const int OPAQUE_SHAPE_BUCKET = 0;
const int TRANSPARENT_SHAPE_BUCKET = 1; const int TRANSPARENT_SHAPE_BUCKET = 1;
const int LIGHT_BUCKET = 2; const int LIGHT_BUCKET = 2;
const int META_BUCKET = 3; const int META_BUCKET = 3;
const int OUTLINE_BUCKET = 4;
const int BACKGROUND_BUCKET = 2; const int BACKGROUND_BUCKET = 2;
MultiFilterItems<NUM_SPATIAL_FILTERS>::ItemFilterArray spatialFilters = { { MultiFilterItems<NUM_SPATIAL_FILTERS>::ItemFilterArray spatialFilters = { {
ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::opaqueShape(),
ItemFilter::Builder::transparentShape(), ItemFilter::Builder::transparentShape(),
ItemFilter::Builder::light(), ItemFilter::Builder::light(),
ItemFilter::Builder::meta() ItemFilter::Builder::meta(),
ItemFilter::Builder().withVisible().withOutline()
} }; } };
MultiFilterItems<NUM_NON_SPATIAL_FILTERS>::ItemFilterArray nonspatialFilters = { { MultiFilterItems<NUM_NON_SPATIAL_FILTERS>::ItemFilterArray nonspatialFilters = { {
ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::opaqueShape(),
@ -76,7 +79,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
task.addJob<ClearContainingZones>("ClearContainingZones"); task.addJob<ClearContainingZones>("ClearContainingZones");
output = Output(BucketList{ opaques, transparents, lights, metas, output = Output(BucketList{ opaques, transparents, lights, metas, filteredSpatialBuckets[OUTLINE_BUCKET],
filteredLayeredOpaque.getN<FilterLayeredItems::Outputs>(0), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(0), filteredLayeredOpaque.getN<FilterLayeredItems::Outputs>(0), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(0),
filteredLayeredOpaque.getN<FilterLayeredItems::Outputs>(1), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(1), filteredLayeredOpaque.getN<FilterLayeredItems::Outputs>(1), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(1),
background }, spatialSelection); background }, spatialSelection);

View file

@ -4,6 +4,7 @@
// //
// Created by Zach Pomerantz on 12/22/2016. // Created by Zach Pomerantz on 12/22/2016.
// Copyright 2016 High Fidelity, Inc. // Copyright 2016 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -23,6 +24,7 @@ public:
TRANSPARENT_SHAPE, TRANSPARENT_SHAPE,
LIGHT, LIGHT,
META, META,
OUTLINE,
LAYER_FRONT_OPAQUE_SHAPE, LAYER_FRONT_OPAQUE_SHAPE,
LAYER_FRONT_TRANSPARENT_SHAPE, LAYER_FRONT_TRANSPARENT_SHAPE,
LAYER_HUD_OPAQUE_SHAPE, LAYER_HUD_OPAQUE_SHAPE,

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 1/11/15. // Created by Sam Gateau on 1/11/15.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -608,6 +609,22 @@ void Scene::resetSelections(const Transaction::SelectionResets& transactions) {
} }
} }
void Scene::addItemToSelection(const std::string& selectionName, ItemID itemID) {
std::unique_lock<std::mutex> lock(_selectionsMutex);
auto found = _selections.find(selectionName);
if (found == _selections.end()) {
Selection selection = Selection(selectionName, { itemID });
_selections[selectionName] = selection;
} else {
_selections[selectionName].add(itemID);
}
}
void Scene::removeSelection(const std::string& selectionName) {
std::unique_lock<std::mutex> lock(_selectionsMutex);
_selections.erase(selectionName);
}
// Access a particular Stage (empty if doesn't exist) // Access a particular Stage (empty if doesn't exist)
// Thread safe // Thread safe
StagePointer Scene::getStage(const Stage::Name& name) const { StagePointer Scene::getStage(const Stage::Name& name) const {

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 1/11/15. // Created by Sam Gateau on 1/11/15.
// Copyright 2014 High Fidelity, Inc. // Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -166,6 +167,14 @@ public:
// Thread safe // Thread safe
bool isSelectionEmpty(const Selection::Name& name) const; bool isSelectionEmpty(const Selection::Name& name) const;
// Add a single item to a selection by name
// Thread safe
void addItemToSelection(const std::string& selectionName, ItemID itemID);
// Remove a selection by name
// Thread safe
void removeSelection(const std::string& selectionName);
// This next call are NOT threadsafe, you have to call them from the correct thread to avoid any potential issues // This next call are NOT threadsafe, you have to call them from the correct thread to avoid any potential issues
// Access a particular item from its ID // Access a particular item from its ID
@ -194,6 +203,8 @@ public:
void setItemTransition(ItemID id, Index transitionId); void setItemTransition(ItemID id, Index transitionId);
void removeItemTransition(ItemID id); void removeItemTransition(ItemID id);
HighlightStyle getOutlineStyle(ItemID id, const ViewFrustum& viewFrustum, uint16_t height) { return _items[id].getOutlineStyle(viewFrustum, height); }
protected: protected:
// Thread safe elements that can be accessed from anywhere // Thread safe elements that can be accessed from anywhere

View file

@ -4,6 +4,7 @@
// //
// Created by Sam Gateau on 4/4/2017. // Created by Sam Gateau on 4/4/2017.
// Copyright 2017 High Fidelity, Inc. // Copyright 2017 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -37,7 +38,8 @@ namespace render {
// Test if the ID is in the selection, return the index or -1 if not present // Test if the ID is in the selection, return the index or -1 if not present
static const int NOT_FOUND{ -1 }; static const int NOT_FOUND{ -1 };
void add(ItemID id) { _items.push_back(id); }
int find(ItemID id) const; int find(ItemID id) const;
bool contains(ItemID id) const { return find(id) > NOT_FOUND; } bool contains(ItemID id) const { return find(id) > NOT_FOUND; }

View file

@ -4,6 +4,7 @@
// //
// Created by Zach Pomerantz on 12/31/15. // Created by Zach Pomerantz on 12/31/15.
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -38,6 +39,7 @@ public:
FADE, FADE,
CULL_FACE_NONE, // if neither of these are set, we're CULL_FACE_BACK CULL_FACE_NONE, // if neither of these are set, we're CULL_FACE_BACK
CULL_FACE_FRONT, CULL_FACE_FRONT,
MTOON,
OWN_PIPELINE, OWN_PIPELINE,
INVALID, INVALID,
@ -84,6 +86,7 @@ public:
Builder& withDepthBias() { _flags.set(DEPTH_BIAS); return (*this); } Builder& withDepthBias() { _flags.set(DEPTH_BIAS); return (*this); }
Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); }
Builder& withFade() { _flags.set(FADE); return (*this); } Builder& withFade() { _flags.set(FADE); return (*this); }
Builder& withMToon() { _flags.set(MTOON); return (*this); }
Builder& withoutCullFace() { return withCullFaceMode(graphics::MaterialKey::CullFaceMode::CULL_NONE); } Builder& withoutCullFace() { return withCullFaceMode(graphics::MaterialKey::CullFaceMode::CULL_NONE); }
Builder& withCullFaceMode(graphics::MaterialKey::CullFaceMode cullFaceMode) { Builder& withCullFaceMode(graphics::MaterialKey::CullFaceMode cullFaceMode) {
@ -184,6 +187,9 @@ public:
Builder& withFade() { _flags.set(FADE); _mask.set(FADE); return (*this); } Builder& withFade() { _flags.set(FADE); _mask.set(FADE); return (*this); }
Builder& withoutFade() { _flags.reset(FADE); _mask.set(FADE); return (*this); } Builder& withoutFade() { _flags.reset(FADE); _mask.set(FADE); return (*this); }
Builder& withMToon() { _flags.set(MTOON); _mask.set(MTOON); return (*this); }
Builder& withoutMToon() { _flags.reset(MTOON); _mask.set(MTOON); return (*this); }
Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); _mask |= (CUSTOM_MASK); return (*this); } Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); _mask |= (CUSTOM_MASK); return (*this); }
Builder& withoutCustom() { _flags &= (~CUSTOM_MASK); _mask |= (CUSTOM_MASK); return (*this); } Builder& withoutCustom() { _flags &= (~CUSTOM_MASK); _mask |= (CUSTOM_MASK); return (*this); }
@ -211,6 +217,7 @@ public:
bool isWireframe() const { return _flags[WIREFRAME]; } bool isWireframe() const { return _flags[WIREFRAME]; }
bool isCullFace() const { return !_flags[CULL_FACE_NONE] && !_flags[CULL_FACE_FRONT]; } bool isCullFace() const { return !_flags[CULL_FACE_NONE] && !_flags[CULL_FACE_FRONT]; }
bool isFaded() const { return _flags[FADE]; } bool isFaded() const { return _flags[FADE]; }
bool isMToon() const { return _flags[MTOON]; }
bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; } bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; }
bool isValid() const { return !_flags[INVALID]; } bool isValid() const { return !_flags[INVALID]; }
@ -250,6 +257,7 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& key) {
<< "isWireframe:" << key.isWireframe() << "isWireframe:" << key.isWireframe()
<< "isCullFace:" << key.isCullFace() << "isCullFace:" << key.isCullFace()
<< "isFaded:" << key.isFaded() << "isFaded:" << key.isFaded()
<< "isMToon:" << key.isMToon()
<< "]"; << "]";
} }
} else { } else {