native MToon materials

This commit is contained in:
HifiExperiments 2024-02-02 17:59:32 -08:00
parent ce11eb3920
commit c04c037588
38 changed files with 2992 additions and 990 deletions

View file

@ -4,6 +4,7 @@
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -196,6 +197,8 @@ ItemKey EntityRenderer::getKey() {
builder.withInvisible();
}
updateItemKeyBuilderFromMaterials(builder);
return builder;
}
@ -221,6 +224,20 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set<QUuid>& co
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) {
if (!isValidRenderItem()) {
return;
@ -510,7 +527,7 @@ EntityRenderer::Pipeline EntityRenderer::getPipelineType(const graphics::MultiMa
}
graphics::MaterialKey drawMaterialKey = materials.getMaterialKey();
if (drawMaterialKey.isEmissive() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
if (materials.isMToon() || drawMaterialKey.isEmissive() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
return Pipeline::MATERIAL;
}
@ -630,6 +647,26 @@ Item::Bound EntityRenderer::getMaterialBound(RenderArgs* 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) {
MaterialMap::iterator materials;
{
@ -656,7 +693,7 @@ void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& build
builder.withCullFaceMode(materials->second.getCullFaceMode());
graphics::MaterialKey drawMaterialKey = materials->second.getMaterialKey();
if (drawMaterialKey.isUnlit()) {
if (!materials->second.isMToon() && drawMaterialKey.isUnlit()) {
builder.withUnlit();
}
@ -666,8 +703,12 @@ void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& build
if (drawMaterialKey.isNormalMap()) {
builder.withTangents();
}
if (drawMaterialKey.isLightMap()) {
builder.withLightMap();
if (!materials->second.isMToon()) {
if (drawMaterialKey.isLightMap()) {
builder.withLightMap();
}
} else {
builder.withMToon();
}
} else if (pipelineType == Pipeline::PROCEDURAL) {
builder.withOwnPipeline();

View file

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

View file

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

View file

@ -1,6 +1,7 @@
//
// Created by Sam Gondelman on 1/18/2018
// Copyright 2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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() {
auto builder = ItemKey::Builder().withTypeShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
if (!_visible) {
if (!_visible || !_parentID.isNull()) {
builder.withInvisible();
}
@ -229,6 +230,10 @@ ItemKey MaterialEntityRenderer::getKey() {
if (matKey.isTranslucent()) {
builder.withTransparent();
}
if (drawMaterial->getOutlineWidthMode() != NetworkMToonMaterial::OutlineWidthMode::OUTLINE_NONE && drawMaterial->getOutlineWidth() > 0.0f) {
builder.withOutline();
}
}
return builder.build();
@ -258,11 +263,16 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
if (drawMaterialKey.isNormalMap()) {
builder.withTangents();
}
if (drawMaterialKey.isLightMap()) {
builder.withLightMap();
}
if (drawMaterialKey.isUnlit()) {
builder.withUnlit();
if (drawMaterial && drawMaterial->isMToon()) {
builder.withMToon();
} else {
if (drawMaterialKey.isLightMap()) {
builder.withLightMap();
}
if (drawMaterialKey.isUnlit()) {
builder.withUnlit();
}
}
}
@ -273,6 +283,18 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
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) {
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
Q_ASSERT(args->_batch);

View file

@ -1,6 +1,7 @@
//
// Created by Sam Gondelman on 1/18/2018
// Copyright 2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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 doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const override;
ItemKey getKey() override;
ShapeKey getShapeKey() override;

View file

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

View file

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

View file

@ -82,13 +82,33 @@ namespace scriptable {
QString procedural;
glm::vec3 shade;
QString shadeMap;
float shadingShift;
QString shadingShiftMap;
float shadingToony;
glm::vec3 matcap;
QString matcapMap;
glm::vec3 parametricRim;
float parametricRimFresnelPower;
float parametricRimLift;
QString rimMap;
float rimLightingMix;
QString outlineWidthMode;
float outlineWidth;
glm::vec3 outline;
QString uvAnimationMaskMap;
float uvAnimationScrollXSpeed;
float uvAnimationScrollYSpeed;
float uvAnimationRotationSpeed;
graphics::MaterialKey key { 0 };
};
/*@jsdoc
* A material layer.
* @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
* 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;
}
/*@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 obj = engine->newObject();
obj.setProperty("name", material.name);
@ -503,7 +389,7 @@ namespace scriptable {
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)) {
obj.setProperty("opacityCutoff", FALLTHROUGH);
} else if (material.key.isOpacityCutoff()) {
@ -516,30 +402,6 @@ namespace scriptable {
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)) {
obj.setProperty("emissive", FALLTHROUGH);
} else if (material.key.isEmissive()) {
@ -562,41 +424,6 @@ namespace scriptable {
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)) {
obj.setProperty("normalMap", FALLTHROUGH);
} else if (!material.normalMap.isEmpty()) {
@ -616,10 +443,7 @@ namespace scriptable {
obj.setProperty("texCoordTransform1", mat4toScriptValue(engine, material.texCoordTransforms[1]));
}
// These need to be implemented, but set the fallthrough for now
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::LIGHTMAP_PARAMS)) {
obj.setProperty("lightmapParams", FALLTHROUGH);
}
// This needs to be implemented, but set the fallthrough for now
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::MATERIAL_PARAMS)) {
obj.setProperty("materialParams", FALLTHROUGH);
}
@ -629,6 +453,179 @@ namespace scriptable {
} else if (!material.cullFaceMode.isEmpty()) {
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
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));
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::ROUGHNESS_MAP_BIT)) {
obj.setProperty("shadeMap", FALLTHROUGH);
} else if (!material.shadeMap.isEmpty()) {
obj.setProperty("shadeMap", material.shadeMap);
}
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);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::METALLIC_MAP_BIT)) {
obj.setProperty("shadingShiftMap", FALLTHROUGH);
} else if (!material.shadingShiftMap.isEmpty()) {
obj.setProperty("shadingShiftMap", material.shadingShiftMap);
}
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);
}
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));
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::OCCLUSION_MAP_BIT)) {
obj.setProperty("matcapMap", FALLTHROUGH);
} else if (!material.matcapMap.isEmpty()) {
obj.setProperty("matcapMap", material.matcapMap);
}
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));
}
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);
}
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);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::SCATTERING_MAP_BIT)) {
obj.setProperty("rimMap", FALLTHROUGH);
} else if (!material.rimMap.isEmpty()) {
obj.setProperty("rimMap", material.rimMap);
}
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);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::MaterialKey::LIGHT_MAP_BIT)) {
obj.setProperty("uvAnimationMaskMap", FALLTHROUGH);
} else if (!material.uvAnimationMaskMap.isEmpty()) {
obj.setProperty("uvAnimationMaskMap", material.uvAnimationMaskMap);
}
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);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::EXTRA_1_BIT)) {
obj.setProperty("outlineWidthMode", FALLTHROUGH);
} else {
obj.setProperty("outlineWidthMode", material.outlineWidthMode);
}
if (hasPropertyFallthroughs && material.propertyFallthroughs.at(graphics::Material::EXTRA_2_BIT)) {
obj.setProperty("outlineWidth", FALLTHROUGH);
} else {
obj.setProperty("outlineWidth", material.outlineWidth);
}
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) {
obj.setProperty("procedural", material.procedural);
}

View file

@ -27,27 +27,50 @@ scriptable::ScriptableMaterial& scriptable::ScriptableMaterial::operator=(const
opacity = material.opacity;
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;
opacityMapMode = material.opacityMapMode;
roughness = material.roughness;
metallic = material.metallic;
scattering = material.scattering;
unlit = material.unlit;
emissive = material.emissive;
emissiveMap = material.emissiveMap;
albedoMap = material.albedoMap;
opacityMap = material.opacityMap;
metallicMap = material.metallicMap;
specularMap = material.specularMap;
roughnessMap = material.roughnessMap;
glossMap = material.glossMap;
normalMap = material.normalMap;
bumpMap = material.bumpMap;
occlusionMap = material.occlusionMap;
lightMap = material.lightMap;
scatteringMap = material.scatteringMap;
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) {
procedural = material.procedural;
}
@ -67,13 +90,9 @@ scriptable::ScriptableMaterial::ScriptableMaterial(const graphics::MaterialPoint
opacity = material->getOpacity();
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();
opacityMapMode = QString(graphics::MaterialKey::getOpacityMapModeName(material->getOpacityMapMode()).c_str());
roughness = material->getRoughness();
metallic = material->getMetallic();
scattering = material->getScattering();
unlit = material->isUnlit();
emissive = material->getEmissive();
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);
if (map && map->getTextureSource()) {
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++) {
texCoordTransforms[i] = material->getTexCoordTransform(i);
}
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) {
procedural = material->getProceduralString();
}

View file

@ -4,6 +4,7 @@
//
// Created by Sam Gateau on 12/10/2014.
// Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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_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() {
for (int i = 0; i < NUM_TOTAL_FLAGS; i++) {
@ -258,6 +260,17 @@ void Material::setTextureTransforms(const Transform& transform, MaterialMappingM
_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() {
Schema 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;
}
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.
// Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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
class MaterialKey {
public:
// Be careful changing these, they need to match up with the bits in graphics/Material.slh
enum FlagBit {
EMISSIVE_VAL_BIT = 0,
UNLIT_VAL_BIT,
@ -57,6 +59,12 @@ public:
LIGHT_MAP_BIT,
SCATTERING_MAP_BIT,
EXTRA_1_BIT,
EXTRA_2_BIT,
EXTRA_3_BIT,
EXTRA_4_BIT,
EXTRA_5_BIT,
NUM_FLAGS,
};
typedef std::bitset<NUM_FLAGS> Flags;
@ -419,6 +427,10 @@ public:
MATERIAL_PARAMS,
CULL_FACE_MODE,
EXTRA_1_BIT,
EXTRA_2_BIT,
EXTRA_3_BIT,
NUM_TOTAL_FLAGS
};
std::unordered_map<uint, bool> getPropertyFallthroughs() { return _propertyFallthroughs; }
@ -432,15 +444,43 @@ public:
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_SHADER_SIMPLE;
static const std::string VRM_MTOON;
protected:
std::string _name { "" };
mutable MaterialKey _key { 0 };
private:
std::string _model { HIFI_PBR };
mutable MaterialKey _key { 0 };
// Material properties
glm::vec3 _emissive { DEFAULT_EMISSIVE };
@ -525,12 +565,12 @@ public:
// Texture Coord Transform Array
glm::mat4 _texcoordTransforms[Material::NUM_TEXCOORD_TRANSFORMS];
glm::vec2 _lightmapParams { 0.0, 1.0 };
// x: material mode (0 for UV, 1 for PROJECTED)
// y: 1 for texture repeat, 0 for discard outside of 0 - 1
glm::vec2 _materialParams { 0.0, 1.0 };
glm::vec2 _lightmapParams { 0.0, 1.0 };
Schema() {
for (auto& transform : _texcoordTransforms) {
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; }
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; }
void setCullFaceMode(graphics::MaterialKey::CullFaceMode cullFaceMode) { _cullFaceMode = cullFaceMode; }
@ -559,6 +659,18 @@ public:
void addReferenceTexture(const std::function<gpu::TexturePointer()>& textureOperator);
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:
gpu::BufferView _schemaBuffer;
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<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.
// Copyright 2013 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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 {
mat4 _texcoordTransforms0;
mat4 _texcoordTransforms1;
vec2 _lightmapParams;
vec2 _materialParams;
<@if not HIFI_USE_MTOON@>
vec2 _lightmapParams;
<@endif@>
};
<@func declareMaterialTexMapArrayBuffer()@>
@ -45,11 +48,24 @@ struct TexMapArray {
// 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
<@if not HIFI_USE_MTOON@>
struct Material {
vec4 _emissiveOpacity;
vec4 _albedoRoughness;
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 {
Material _mat;
@ -63,39 +79,91 @@ TexMapArray getTexMapArray() {
return _texMapArray;
}
vec3 getMaterialEmissive(Material m) { return m._emissiveOpacity.rgb; }
float getMaterialOpacity(Material m) { return m._emissiveOpacity.a; }
<@if not HIFI_USE_MTOON@>
vec3 getMaterialEmissive(Material m) { return m._emissiveOpacity.rgb; }
float getMaterialOpacity(Material m) { return m._emissiveOpacity.a; }
vec3 getMaterialAlbedo(Material m) { return m._albedoRoughness.rgb; }
float getMaterialRoughness(Material m) { return m._albedoRoughness.a; }
float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); }
vec3 getMaterialAlbedo(Material m) { return m._albedoRoughness.rgb; }
float getMaterialRoughness(Material m) { return m._albedoRoughness.a; }
float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); }
float getMaterialMetallic(Material m) { return m._metallicScatteringOpacityCutoffKey.x; }
float getMaterialScattering(Material m) { return m._metallicScatteringOpacityCutoffKey.y; }
float getMaterialOpacityCutoff(Material m) { return m._metallicScatteringOpacityCutoffKey.z; }
float getMaterialMetallic(Material m) { return m._metallicScatteringOpacityCutoffKey.x; }
float getMaterialScattering(Material m) { return m._metallicScatteringOpacityCutoffKey.y; }
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 UNLIT_VAL_BIT = 0x00000002;
const BITFIELD ALBEDO_VAL_BIT = 0x00000004;
const BITFIELD METALLIC_VAL_BIT = 0x00000008;
const BITFIELD GLOSSY_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 SCATTERING_VAL_BIT = 0x00000400;
const BITFIELD EMISSIVE_VAL_BIT = 0x00000001;
const BITFIELD UNLIT_VAL_BIT = 0x00000002;
const BITFIELD ALBEDO_VAL_BIT = 0x00000004;
const BITFIELD METALLIC_VAL_BIT = 0x00000008;
const BITFIELD GLOSSY_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 SCATTERING_VAL_BIT = 0x00000400;
const BITFIELD EMISSIVE_MAP_BIT = 0x00000800;
const BITFIELD ALBEDO_MAP_BIT = 0x00001000;
const BITFIELD METALLIC_MAP_BIT = 0x00002000;
const BITFIELD ROUGHNESS_MAP_BIT = 0x00004000;
const BITFIELD NORMAL_MAP_BIT = 0x00008000;
const BITFIELD OCCLUSION_MAP_BIT = 0x00010000;
const BITFIELD LIGHTMAP_MAP_BIT = 0x00020000;
const BITFIELD SCATTERING_MAP_BIT = 0x00040000;
const BITFIELD EMISSIVE_MAP_BIT = 0x00000800;
const BITFIELD ALBEDO_MAP_BIT = 0x00001000;
const BITFIELD METALLIC_MAP_BIT = 0x00002000;
const BITFIELD ROUGHNESS_MAP_BIT = 0x00004000;
const BITFIELD NORMAL_MAP_BIT = 0x00008000;
const BITFIELD OCCLUSION_MAP_BIT = 0x00010000;
const BITFIELD LIGHTMAP_MAP_BIT = 0x00020000;
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@>

View file

@ -4,6 +4,7 @@
//
// Created by Sam Gateau on 2/22/16
// Copyright 2016 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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/Material.slh@>
<@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@>
#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@>
#ifdef GPU_TEXTURE_TABLE_BINDLESS
@ -41,14 +102,6 @@ vec4 fetchAlbedoMap(vec2 uv) {
}
<@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@>
#define normalMap 1
vec3 fetchNormalMap(vec2 uv) {
@ -73,6 +126,14 @@ vec3 fetchEmissiveMap(vec2 uv) {
}
<@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@>
#define occlusionMap 5
float fetchOcclusionMap(vec2 uv) {
@ -98,13 +159,6 @@ vec4 fetchAlbedoMap(vec2 uv) {
}
<@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@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap;
vec3 fetchNormalMap(vec2 uv) {
@ -129,6 +183,13 @@ vec3 fetchEmissiveMap(vec2 uv) {
}
<@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@>
LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_OCCLUSION) uniform sampler2D occlusionMap;
float fetchOcclusionMap(vec2 uv) {
@ -183,7 +244,6 @@ float fetchScatteringMap(vec2 uv) {
<@endfunc@>
<@func declareMaterialLightmap()@>
<$declareMaterialTexMapArrayBuffer()$>
@ -195,59 +255,6 @@ vec3 fetchLightMap(vec2 uv) {
}
<@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)@>
{
<$roughness$> = mix(<$materialRoughness$>, <$fetchedRoughness$>, float((<$matKey$> & ROUGHNESS_MAP_BIT) != 0));
@ -260,12 +267,6 @@ vec3 fetchLightMap(vec2 uv) {
}
<@endfunc@>
<@func evalMaterialEmissive(fetchedEmissive, materialEmissive, matKey, emissive)@>
{
<$emissive$> = mix(<$materialEmissive$>, <$fetchedEmissive$>, float((<$matKey$> & EMISSIVE_MAP_BIT) != 0));
}
<@endfunc@>
<@func evalMaterialOcclusion(fetchedOcclusion, matKey, occlusion)@>
{
<$occlusion$> = <$fetchedOcclusion$>;
@ -277,5 +278,214 @@ vec3 fetchLightMap(vec2 uv) {
<$scattering$> = mix(<$materialScattering$>, <$fetchedScattering$>, float((<$matKey$> & SCATTERING_MAP_BIT) != 0));
}
<@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
// Copyright 2013-2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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_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
#define GRAPHICS_TEXTURE_SKYBOX 11
#define GRAPHICS_BUFFER_SKYBOX_PARAMS 5
@ -59,7 +67,13 @@ enum Texture {
MaterialRoughness = GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS,
MaterialOcclusion = GRAPHICS_TEXTURE_MATERIAL_OCCLUSION,
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

View file

@ -1,6 +1,7 @@
//
// Created by Sam Gondelman on 2/9/2018
// Copyright 2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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
* @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.
* 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
* {@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. <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>.
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> and
* <code>"hifi_shader_simple"</code> models only.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: all.
* @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.
* 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
* 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
* <code>"hifi_shader_simple"</code> models only.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: all.
* @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>.
* 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>.
* 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
* Image or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below.
* <code>"hifi_pbr"</code> model only.
* Image or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>,
* <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
* or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code>
* model only.
* or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>,
* <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
* or Web entity. Set the value the same as the <code>albedoMap</code> value for transparency.
* <code>"hifi_pbr"</code> model only.
* or Web entity. Set the value the same as the <code>albedoMap</code> value for transparency. Supported models: <code>"hifi_pbr"</code>,
* <code>"vrm_mtoon"</code>.
* @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>
@ -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
* with the background.</li>
* </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
* <code>opacityMap</code> when <code>opacityMapMode</code> is <code>"OPACITY_MAP_MASK"</code>. 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: all.
* @property {string} cullFaceMode="CULL_BACK" - The mode defining which side of the geometry should be rendered. 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>
* Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code> model only.
* @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.
* Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: all.
* @property {string} roughnessMap - The URL of the roughness texture image. You can use this or <code>glossMap</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} glossMap - The URL of the gloss texture image. You can use this or <code>roughnessMap</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} 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.
* 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
* 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
* 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
* 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
* 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
* 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
* or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. <code>"hifi_pbr"</code>
* model only.
* or Web entity. Set to <code>"fallthrough"</code> to fall through to the material below. Supported models: <code>"hifi_pbr"</code>.
* @property {Mat4|string} texCoordTransform0 - The transform to use for all of the maps apart from <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 {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.
* 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>
* @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>
* @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.
* <code>"hifi_pbr"</code> and <code>"hifi_shader_simple"</code> models only.
* @property {ProceduralData} procedural - The definition of a procedural shader material. <code>"hifi_shader_simple"</code> model only.
* Supported models: all.
* @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.
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;
const QString FALLTHROUGH("fallthrough");
if (modelString == graphics::Material::HIFI_PBR) {
auto material = std::make_shared<NetworkMaterial>();
if (modelString == graphics::Material::HIFI_PBR || modelString == graphics::Material::VRM_MTOON) {
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()) {
if (key == "name") {
auto nameJSON = materialJSON.value(key);
@ -282,13 +333,6 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
} else if (value.isDouble()) {
material->setOpacity(value.toDouble());
}
} else if (key == "unlit") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::UNLIT_VAL_BIT);
} else if (value.isBool()) {
material->setUnlit(value.toBool());
}
} else if (key == "albedo") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
@ -301,21 +345,7 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
material->setAlbedo(color, isSRGB);
}
}
} else if (key == "roughness") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::GLOSSY_VAL_BIT);
} else if (value.isDouble()) {
material->setRoughness(value.toDouble());
}
} else if (key == "metallic") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::METALLIC_VAL_BIT);
} else if (value.isDouble()) {
material->setMetallic(value.toDouble());
}
} else if (key == "opacityMapMode") {
} else if (key == "opacityMapMode") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
@ -348,14 +378,7 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
}
}
}
} else if (key == "scattering") {
auto value = materialJSON.value(key);
if (value.isString() && value.toString() == FALLTHROUGH) {
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::SCATTERING_VAL_BIT);
} else if (value.isDouble()) {
material->setScattering(value.toDouble());
}
} else if (key == "emissiveMap") {
} else if (key == "emissiveMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
@ -380,46 +403,6 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
material->setAlbedoMap(baseUrl.resolved(valueString), useAlphaChannel);
}
}
} else if (key == "roughnessMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::ROUGHNESS_MAP_BIT);
} else {
material->setRoughnessMap(baseUrl.resolved(valueString), false);
}
}
} else if (key == "glossMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::ROUGHNESS_MAP_BIT);
} else {
material->setRoughnessMap(baseUrl.resolved(valueString), true);
}
}
} else if (key == "metallicMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::METALLIC_MAP_BIT);
} else {
material->setMetallicMap(baseUrl.resolved(valueString), false);
}
}
} else if (key == "specularMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
auto valueString = value.toString();
if (valueString == FALLTHROUGH) {
material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::METALLIC_MAP_BIT);
} else {
material->setMetallicMap(baseUrl.resolved(valueString), true);
}
}
} else if (key == "normalMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
@ -440,36 +423,6 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
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") {
auto value = materialJSON.value(key);
if (value.isString()) {
@ -494,15 +447,6 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
glm::mat4 transform = mat4FromVariant(valueVariant);
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") {
auto value = materialJSON.value(key);
if (value.isString()) {
@ -518,6 +462,295 @@ std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource
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)) {
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
@ -893,3 +1126,138 @@ bool NetworkMaterial::checkResetOpacityMap() {
}
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
// Copyright 2018 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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; }
private:
// Helpers for the ctors
QUrl getTextureUrl(const QUrl& baseUrl, const HFMTexture& hfmTexture);
graphics::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const HFMTexture& hfmTexture,
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 _lightmapTransform;
vec2 _lightmapParams;
@ -77,6 +79,119 @@ private:
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 {
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 {
public:
NetworkMaterialResource() : Resource() {}

View file

@ -1,6 +1,7 @@
//
// Created by HifiExperiments on 3/14/2021
// Copyright 2021 Vircadia contributors.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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 {
return resultWithLock<QString>([&] {
auto material = getMaterial();
auto material = getProceduralMaterial();
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) {
_unboundMaterialForUUIDOperator = materialForUUIDOperator;
}
@ -244,6 +351,16 @@ graphics::ProceduralMaterialPointer ReferenceMaterial::getProceduralMaterial() c
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>
inline T ReferenceMaterial::resultWithLock(F&& f) const {
if (_locked) {

View file

@ -1,6 +1,7 @@
//
// Created by HifiExperiments on 3/14/2021
// Copyright 2021 Vircadia contributors.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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;
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; }
std::function<graphics::MaterialPointer()> getReferenceOperator() const { return _materialForUUIDOperator; }
@ -65,6 +83,7 @@ private:
graphics::MaterialPointer getMaterial() const;
std::shared_ptr<NetworkMaterial> getNetworkMaterial() const;
graphics::ProceduralMaterialPointer getProceduralMaterial() const;
std::shared_ptr<NetworkMToonMaterial> getMToonMaterial() const;
template <typename T, typename F>
T resultWithLock(F&& f) const;

View file

@ -4,6 +4,7 @@
//
// Created by Sam Gateau on 2/5/15.
// Copyright 2013 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -286,5 +287,78 @@ vec3 evalGlobalLightingAlphaBlended(
}
<@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@>

View file

@ -4,6 +4,7 @@
//
// Created by Olivier Prat on 08/08/17.
// Copyright 2017 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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
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() {
}
@ -108,10 +110,14 @@ PrepareDrawHighlight::PrepareDrawHighlight() {
}
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);
outputs = _resources;
outputs.edit0() = _resources;
outputs.edit1() = args->_renderMode;
args->_renderMode = RenderArgs::SHADOW_RENDER_MODE;
}
gpu::PipelinePointer DrawHighlightMask::_stencilMaskPipeline;
@ -188,61 +194,7 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c
batch.setProjectionJitter(jitter.x, jitter.y);
batch.setViewTransform(viewMat);
const std::vector<ShapeKey::Builder> keys = {
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;
sortAndRenderZPassShapes(_shapePlumber, renderContext, inShapes, itemBounds);
});
_boundsBuffer->setData(itemBounds.size() * sizeof(render::ItemBound), (const gpu::Byte*) itemBounds.data());
@ -452,13 +404,28 @@ const gpu::PipelinePointer& DebugHighlight::getDepthPipeline() {
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 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);
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;
auto highlightList = highlightStage->getActiveHighlightIds();
@ -467,8 +434,8 @@ void SelectionToHighlight::run(const render::RenderContextPointer& renderContext
if (!scene->isSelectionEmpty(highlight._selectionName)) {
auto highlightId = highlightStage->getHighlightIdBySelection(highlight._selectionName);
_sharedParameters->_highlightIds[outputs.size()] = highlightId;
outputs.emplace_back(highlight._selectionName);
_sharedParameters->_highlightIds[outputs.edit0().size()] = highlightId;
outputs.edit0().emplace_back(highlight._selectionName);
numLayers++;
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) {
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 primaryFramebuffer = inputs.getN<Inputs>(2);
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>();
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.
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;
const auto extractSelectionNameInput = Varying(highlightSelectionOutputs.getN<SelectionToHighlight::Outputs>(0));
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 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);
// Sort
@ -557,6 +530,10 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren
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
const auto debugInputs = DebugHighlight::Inputs(highlightResources, const_cast<const render::Varying&>(highlight0Rect), jitter, primaryFramebuffer).asVarying();
task.addJob<DebugHighlight>("HighlightDebug", debugInputs);
@ -576,3 +553,31 @@ const render::Varying DrawHighlightTask::addSelectItemJobs(JobModel& task, const
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.
// Copyright 2017 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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 {
public:
using Inputs = gpu::FramebufferPointer;
using Outputs = HighlightResourcesPointer;
using Outputs = render::VaryingSet2<HighlightResourcesPointer, render::Args::RenderMode>;
using JobModel = render::Job::ModelIO<PrepareDrawHighlight, Inputs, Outputs>;
PrepareDrawHighlight();
@ -81,12 +82,13 @@ private:
class SelectionToHighlight {
public:
using Outputs = std::vector<std::string>;
using JobModel = render::Job::ModelO<SelectionToHighlight, Outputs>;
using Inputs = render::VaryingSet2<render::ItemBounds, gpu::FramebufferPointer>;
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 } {}
void run(const render::RenderContextPointer& renderContext, Outputs& outputs);
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
private:
@ -96,7 +98,7 @@ private:
class ExtractSelectionName {
public:
using Inputs = SelectionToHighlight::Outputs;
using Inputs = std::vector<std::string>;
using Outputs = std::string;
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

View file

@ -4,6 +4,7 @@
//
// Created by Sam Gateau on 10/3/15.
// Copyright 2015 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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();
}
if (_drawMaterials.hasOutline()) {
builder.withOutline();
}
_itemKey = builder.build();
}
@ -268,11 +273,15 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode pr
if (hasTangents) {
builder.withTangents();
}
if (hasLightmap) {
builder.withLightMap();
}
if (isUnlit) {
builder.withUnlit();
if (!_drawMaterials.isMToon()) {
if (hasLightmap) {
builder.withLightMap();
}
if (isUnlit) {
builder.withUnlit();
}
} else {
builder.withMToon();
}
if (material) {
builder.withCullFaceMode(material->getCullFaceMode());
@ -377,6 +386,11 @@ bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set<QUui
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) {
if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) {
auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex);
@ -426,4 +440,11 @@ template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Poin
}
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.
// Copyright 2015 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -17,6 +18,7 @@
#include <gpu/Batch.h>
#include <render/Scene.h>
#include <graphics/Geometry.h>
#include <render/HighlightStyle.h>
class ModelMeshPartPayload {
public:
@ -59,6 +61,7 @@ public:
void setRenderWithZones(const QVector<QUuid>& renderWithZones) { _renderWithZones = renderWithZones; }
void setBillboardMode(BillboardMode billboardMode) { _billboardMode = billboardMode; }
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 removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); }
@ -107,6 +110,7 @@ namespace render {
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload);
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
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

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,7 @@
using namespace render;
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) {
//DependencyManager::get<DeferredLightingEffect>()->setShadowMapEnabled(configuration.isEnabled());
@ -253,58 +254,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat, false);
const std::vector<ShapeKey::Builder> keys = {
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) {
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;
render::ItemBounds itemBounds;
sortAndRenderZPassShapes(_shapePlumber, renderContext, inShapes, itemBounds);
}
args->_batch = nullptr;

View file

@ -5,6 +5,7 @@
//
// Created by Andrzej Kapolka on 5/6/14.
// Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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 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 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 GlobalLight.slh@>
<@if HIFI_USE_LIGHTMAP@>
@ -31,6 +69,7 @@
<@endif@>
<@include gpu/Transform.slh@>
<$declareStandardCameraTransform()$>
layout(location=0) out vec4 _fragColor0;
<@else@>
<@include DeferredBufferWrite.slh@>
@ -43,29 +82,6 @@
<@include LightingModel.slh@>
<@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@>
<@include Fade.slh@>
<$declareFadeFragment()$>
@ -78,7 +94,9 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
<@if not HIFI_USE_SHADOW@>
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_COLOR) in vec4 _color;
<@if not HIFI_USE_MTOON@>
layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color;
<@endif@>
<@if HIFI_USE_NORMALMAP@>
layout(location=RENDER_UTILS_ATTR_TANGENT_WS) in vec3 _tangentWS;
<@endif@>
@ -101,15 +119,21 @@ void main(void) {
Material mat = getMaterial();
BITFIELD matKey = getMaterialKey(mat);
<@if HIFI_USE_SHADOW or HIFI_USE_UNLIT@>
<@if not HIFI_USE_MTOON@>
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
<@else@>
<$fetchMToonMaterialTexturesCoord0(matKey, _texCoord0, albedoTex)$>
<@endif@>
<@if HIFI_USE_TRANSLUCENT@>
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)$>;
<$discardInvisible(opacity)$>;
<@else@>
float cutoff = getMaterialOpacityCutoff(mat);
float opacity = 1.0;
<$evalMaterialOpacityMask(albedoTex.a, cutoff, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
@ -118,7 +142,9 @@ void main(void) {
<@if not HIFI_USE_SHADOW@>
vec3 albedo = getMaterialAlbedo(mat);
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
albedo *= _color.rgb;
<@if not HIFI_USE_MTOON@>
albedo *= _color.rgb;
<@endif@>
<@if HIFI_USE_FADE@>
albedo += fadeEmissive;
<@endif@>
@ -134,6 +160,73 @@ void main(void) {
opacity,
albedo * isUnlitEnabled());
<@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@>
<@if not HIFI_USE_LIGHTMAP@>
<@if HIFI_USE_NORMALMAP and HIFI_USE_TRANSLUCENT@>
@ -154,14 +247,13 @@ void main(void) {
<@endif@>
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, _SCRIBE_NULL, lightmap)$>
<@endif@>
<@if HIFI_USE_TRANSLUCENT@>
float cutoff = getMaterialOpacityCutoff(mat);
<@if HIFI_USE_TRANSLUCENT@>
float opacity = getMaterialOpacity(mat) * _color.a;
<$evalMaterialOpacity(albedoTex.a, cutoff, opacity, matKey, opacity)$>;
<$discardInvisible(opacity)$>;
<@else@>
float cutoff = getMaterialOpacityCutoff(mat);
float opacity = 1.0;
<$evalMaterialOpacityMask(albedoTex.a, cutoff, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;

View file

@ -5,6 +5,7 @@
//
// Created by Hifi Engine Team
// Copyright 2019 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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@>
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_COLOR) out vec4 _color;
<@if not HIFI_USE_MTOON@>
layout(location=RENDER_UTILS_ATTR_COLOR) out vec4 _color;
<@endif@>
<@if HIFI_USE_NORMALMAP@>
layout(location=RENDER_UTILS_ATTR_TANGENT_WS) out vec3 _tangentWS;
<@endif@>
@ -96,7 +99,9 @@ void main(void) {
_texCoord01 = vec4(0.0);
}
<@else@>
<@if not HIFI_USE_MTOON@>
_color = color_sRGBAToLinear(inColor);
<@endif@>
TexMapArray texMapArray = getTexMapArray();
<$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.
// Copyright 2017 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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
#include <glm/vec3.hpp>
#include <glm/gtx/string_cast.hpp>
#include <string>
@ -21,23 +23,59 @@ namespace render {
class HighlightStyle {
public:
struct RGBA {
glm::vec3 color{ 1.0f, 0.7f, 0.2f };
float alpha{ 0.9f };
glm::vec3 color { 1.0f, 0.7f, 0.2f };
float alpha { 0.9f };
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 _outlineOccluded{ { 1.0f, 0.7f, 0.2f }, 0.9f };
RGBA _fillUnoccluded{ { 0.2f, 0.7f, 1.0f }, 0.0f };
RGBA _fillOccluded{ { 0.2f, 0.7f, 1.0f }, 0.0f };
RGBA _outlineUnoccluded { { 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 _fillOccluded { { 0.2f, 0.7f, 1.0f }, 0.0f };
float _outlineWidth{ 2.0f };
bool _isOutlineSmooth{ false };
float _outlineWidth { 2.0f };
bool _isOutlineSmooth { false };
bool isFilled() const {
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 = 0.5 * screenHeight * fabs(p1.y - p2.y);
} else { // OUTLINE_SCREEN
style._outlineWidth = outlineWidth * screenHeight;
}
return style;
}
};
}

View file

@ -4,6 +4,7 @@
//
// Created by Sam Gateau on 1/26/16.
// Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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);
}
}
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.
// Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -29,6 +30,7 @@
#include "ShapePipeline.h"
#include "BlendshapeConstants.h"
#include "HighlightStyle.h"
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
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,
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,
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)
NUM_FLAGS, // Not a valid flag
NUM_FLAGS, // Not a valid flag
};
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& 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
static Builder opaqueShape() { return Builder().withTypeShape(); }
static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); }
@ -213,6 +220,8 @@ public:
bool isLayered() const { return getLayer() != LAYER_DEFAULT; }
bool isSpatial() const { return !isLayered(); }
bool isOutline() const { return _flags[OUTLINE]; }
// Probably not public, flags used by the scene
bool isSmall() const { return _flags[__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& 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); }
// 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 HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const = 0;
~PayloadInterface() {}
// 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); }
HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const { return _payload->getOutlineStyle(viewFrustum, height); }
// Access the status
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
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
// 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"
@ -573,6 +595,8 @@ public:
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:
DataPointer _data;
@ -628,6 +652,7 @@ public:
virtual void render(RenderArgs* args) = 0;
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) 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
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 <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload);
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 std::vector<PayloadPointer> Payloads;

View file

@ -4,6 +4,7 @@
//
// Created by Zach Pomerantz on 12/22/2016.
// Copyright 2016 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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);
// 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 OPAQUE_SHAPE_BUCKET = 0;
const int TRANSPARENT_SHAPE_BUCKET = 1;
const int LIGHT_BUCKET = 2;
const int META_BUCKET = 3;
const int OUTLINE_BUCKET = 4;
const int BACKGROUND_BUCKET = 2;
MultiFilterItems<NUM_SPATIAL_FILTERS>::ItemFilterArray spatialFilters = { {
ItemFilter::Builder::opaqueShape(),
ItemFilter::Builder::transparentShape(),
ItemFilter::Builder::light(),
ItemFilter::Builder::meta()
ItemFilter::Builder::meta(),
ItemFilter::Builder().withVisible().withOutline()
} };
MultiFilterItems<NUM_NON_SPATIAL_FILTERS>::ItemFilterArray nonspatialFilters = { {
ItemFilter::Builder::opaqueShape(),
@ -76,7 +79,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
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>(1), filteredLayeredTransparent.getN<FilterLayeredItems::Outputs>(1),
background }, spatialSelection);

View file

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

View file

@ -4,6 +4,7 @@
//
// Created by Sam Gateau on 1/11/15.
// Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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)
// Thread safe
StagePointer Scene::getStage(const Stage::Name& name) const {

View file

@ -4,6 +4,7 @@
//
// Created by Sam Gateau on 1/11/15.
// Copyright 2014 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -166,6 +167,14 @@ public:
// Thread safe
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
// Access a particular item from its ID
@ -194,6 +203,8 @@ public:
void setItemTransition(ItemID id, Index transitionId);
void removeItemTransition(ItemID id);
HighlightStyle getOutlineStyle(ItemID id, const ViewFrustum& viewFrustum, uint16_t height) { return _items[id].getOutlineStyle(viewFrustum, height); }
protected:
// Thread safe elements that can be accessed from anywhere

View file

@ -4,6 +4,7 @@
//
// Created by Sam Gateau on 4/4/2017.
// Copyright 2017 High Fidelity, Inc.
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// 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
static const int NOT_FOUND{ -1 };
void add(ItemID id) { _items.push_back(id); }
int find(ItemID id) const;
bool contains(ItemID id) const { return find(id) > NOT_FOUND; }

View file

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