From da254c2cccac0eda4792130f2675debb665cafe0 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 15 May 2019 22:47:46 -0700 Subject: [PATCH] =?UTF-8?q?(=C2=AC=E2=80=BF=C2=AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assignment-client/CMakeLists.txt | 1 + interface/src/Application.cpp | 13 +- libraries/avatars-renderer/CMakeLists.txt | 1 - .../src/avatars-renderer/Avatar.h | 4 +- libraries/avatars/CMakeLists.txt | 3 +- libraries/avatars/src/AvatarData.h | 4 - libraries/baking/CMakeLists.txt | 3 +- libraries/baking/src/MaterialBaker.h | 2 +- libraries/baking/src/TextureBaker.h | 2 +- libraries/display-plugins/CMakeLists.txt | 1 + .../src/RenderableMaterialEntityItem.cpp | 68 +++--- .../src/RenderableMaterialEntityItem.h | 2 +- .../src/RenderableShapeEntityItem.cpp | 185 ++++++++-------- .../src/RenderableShapeEntityItem.h | 8 +- libraries/entities/CMakeLists.txt | 1 + libraries/gpu/src/gpu/Shader.h | 3 - libraries/graphics/src/graphics/Material.h | 4 + libraries/model-baker/CMakeLists.txt | 3 +- .../model-baker/ParseMaterialMappingTask.h | 2 +- libraries/model-networking/CMakeLists.txt | 5 +- .../src/model-networking/ModelCache.h | 2 +- libraries/physics/CMakeLists.txt | 7 +- libraries/procedural/CMakeLists.txt | 2 +- .../procedural/src/procedural/Procedural.cpp | 110 ++++++---- .../procedural/src/procedural/Procedural.h | 76 +++++-- .../procedural/ProceduralMaterialCache.cpp} | 77 +++++-- .../src/procedural/ProceduralMaterialCache.h} | 2 +- .../src/procedural/ProceduralSkybox.cpp | 7 +- .../render-utils/src/MeshPartPayload.cpp | 120 +++++++---- .../render-utils/src/deformed_simple.slv | 47 +++++ .../render-utils/src/deformed_simple_dq.slv | 47 +++++ libraries/render-utils/src/forward_simple.slf | 108 ++++++++-- libraries/script-engine/CMakeLists.txt | 10 +- libraries/script-engine/src/Quat.cpp | 2 - .../src/SceneScriptingInterface.cpp | 129 +----------- .../src/SceneScriptingInterface.h | 197 +----------------- tests-manual/render-perf/src/main.cpp | 62 ------ tools/oven/CMakeLists.txt | 2 +- 38 files changed, 644 insertions(+), 678 deletions(-) rename libraries/{material-networking/src/material-networking/MaterialCache.cpp => procedural/src/procedural/ProceduralMaterialCache.cpp} (92%) rename libraries/{material-networking/src/material-networking/MaterialCache.h => procedural/src/procedural/ProceduralMaterialCache.h} (98%) create mode 100644 libraries/render-utils/src/deformed_simple.slv create mode 100644 libraries/render-utils/src/deformed_simple_dq.slv diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index b7afc3ed9e..b4042cf294 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -16,6 +16,7 @@ link_hifi_libraries( controllers physics plugins midi image material-networking model-networking ktx shaders ) +include_hifi_library_headers(procedural) add_dependencies(${TARGET_NAME} oven) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0e8c03e032..a94d8a13c9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -155,7 +155,8 @@ #include #include #include -#include +#include +#include #include "recording/ClipCache.h" #include "AudioClient.h" @@ -2014,7 +2015,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo EntityTreeRenderer::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { auto avatarManager = DependencyManager::get(); - auto avatar = avatarManager->getAvatarBySessionID(avatarID); + auto avatar = static_pointer_cast(avatarManager->getAvatarBySessionID(avatarID)); if (avatar) { avatar->addMaterial(material, parentMaterialName); return true; @@ -2023,13 +2024,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo }); EntityTreeRenderer::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { auto avatarManager = DependencyManager::get(); - auto avatar = avatarManager->getAvatarBySessionID(avatarID); + auto avatar = static_pointer_cast(avatarManager->getAvatarBySessionID(avatarID)); if (avatar) { avatar->removeMaterial(material, parentMaterialName); return true; } return false; }); + Procedural::opaqueStencil = [](gpu::StatePointer state) { PrepareStencil::testMaskDrawShape(*state); }; + Procedural::transparentStencil = [](gpu::StatePointer state) { PrepareStencil::testMask(*state); }; EntityTree::setGetEntityObjectOperator([this](const QUuid& id) -> QObject* { auto entities = getEntities(); @@ -7092,10 +7095,6 @@ void Application::clearDomainOctreeDetails(bool clearAll) { // reset the model renderer clearAll ? getEntities()->clear() : getEntities()->clearDomainAndNonOwnedEntities(); - auto skyStage = DependencyManager::get()->getSkyStage(); - - skyStage->setBackgroundMode(graphics::SunSkyStage::SKY_DEFAULT); - DependencyManager::get()->clearUnusedResources(); DependencyManager::get()->clearUnusedResources(); MaterialCache::instance().clearUnusedResources(); diff --git a/libraries/avatars-renderer/CMakeLists.txt b/libraries/avatars-renderer/CMakeLists.txt index de1ac1a7c2..a3cbe8cc36 100644 --- a/libraries/avatars-renderer/CMakeLists.txt +++ b/libraries/avatars-renderer/CMakeLists.txt @@ -9,7 +9,6 @@ include_hifi_library_headers(recording) include_hifi_library_headers(ktx) include_hifi_library_headers(procedural) include_hifi_library_headers(physics) -include_hifi_library_headers(entities-renderer) include_hifi_library_headers(audio) include_hifi_library_headers(entities) include_hifi_library_headers(octree) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 61901d662a..a4767e1f34 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -544,8 +544,8 @@ public: virtual void setEnableMeshVisible(bool isEnabled); virtual bool getEnableMeshVisible() const; - void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override; - void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override; + void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName); + void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName); virtual scriptable::ScriptableModelBase getScriptableModel() override; diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index 13fda28f40..fc6d15cced 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -1,4 +1,3 @@ set(TARGET_NAME avatars) setup_hifi_library(Network Script) -include_hifi_library_headers(gpu) -link_hifi_libraries(shared networking graphics) +link_hifi_libraries(shared networking) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 9219c2c03f..d29e05c7bc 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -55,8 +55,6 @@ #include "HeadData.h" #include "PathUtils.h" -#include - using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; using AvatarHash = QHash; @@ -1465,8 +1463,6 @@ public: bool getIsReplicated() const { return _isReplicated; } - virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {} - virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {} void setReplicaIndex(int replicaIndex) { _replicaIndex = replicaIndex; } int getReplicaIndex() { return _replicaIndex; } diff --git a/libraries/baking/CMakeLists.txt b/libraries/baking/CMakeLists.txt index 73618427f6..4350f386ab 100644 --- a/libraries/baking/CMakeLists.txt +++ b/libraries/baking/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME baking) setup_hifi_library(Concurrent) -link_hifi_libraries(shared shaders graphics networking material-networking graphics-scripting ktx image fbx model-baker task) +link_hifi_libraries(shared shaders graphics networking procedural graphics-scripting ktx image fbx model-baker task) include_hifi_library_headers(gpu) include_hifi_library_headers(hfm) +include_hifi_library_headers(material-networking) \ No newline at end of file diff --git a/libraries/baking/src/MaterialBaker.h b/libraries/baking/src/MaterialBaker.h index 04782443f0..33123cfc73 100644 --- a/libraries/baking/src/MaterialBaker.h +++ b/libraries/baking/src/MaterialBaker.h @@ -17,7 +17,7 @@ #include "TextureBaker.h" #include "baking/TextureFileNamer.h" -#include +#include static const QString BAKED_MATERIAL_EXTENSION = ".baked.json"; diff --git a/libraries/baking/src/TextureBaker.h b/libraries/baking/src/TextureBaker.h index 5fda05e9b4..5c6c85ea16 100644 --- a/libraries/baking/src/TextureBaker.h +++ b/libraries/baking/src/TextureBaker.h @@ -22,7 +22,7 @@ #include "Baker.h" -#include +#include extern const QString BAKED_TEXTURE_KTX_EXT; extern const QString BAKED_META_TEXTURE_SUFFIX; diff --git a/libraries/display-plugins/CMakeLists.txt b/libraries/display-plugins/CMakeLists.txt index ad6503b22d..bfe88f2eb8 100644 --- a/libraries/display-plugins/CMakeLists.txt +++ b/libraries/display-plugins/CMakeLists.txt @@ -11,6 +11,7 @@ include_hifi_library_headers(fbx) include_hifi_library_headers(image) include_hifi_library_headers(ktx) include_hifi_library_headers(render) +include_hifi_library_headers(procedural) target_opengl() diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 9a634a85ad..9eddf0831c 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -11,6 +11,8 @@ #include "RenderPipelines.h" #include "GeometryCache.h" +#include + using namespace render; using namespace render::entities; @@ -249,31 +251,31 @@ ItemKey MaterialEntityRenderer::getKey() { } ShapeKey MaterialEntityRenderer::getShapeKey() { + ShapeKey::Builder builder; graphics::MaterialKey drawMaterialKey; const auto drawMaterial = getMaterial(); if (drawMaterial) { drawMaterialKey = drawMaterial->getKey(); } - bool isTranslucent = drawMaterialKey.isTranslucent(); - bool hasTangents = drawMaterialKey.isNormalMap(); - bool hasLightmap = drawMaterialKey.isLightmapMap(); - bool isUnlit = drawMaterialKey.isUnlit(); - - ShapeKey::Builder builder; - builder.withMaterial(); - - if (isTranslucent) { + if (drawMaterialKey.isTranslucent()) { builder.withTranslucent(); } - if (hasTangents) { - builder.withTangents(); - } - if (hasLightmap) { - builder.withLightmap(); - } - if (isUnlit) { - builder.withUnlit(); + + if (drawMaterial && drawMaterial->isProcedural() && drawMaterial->isReady()) { + builder.withOwnPipeline(); + } else { + builder.withMaterial(); + + if (drawMaterialKey.isNormalMap()) { + builder.withTangents(); + } + if (drawMaterialKey.isLightmapMap()) { + builder.withLightmap(); + } + if (drawMaterialKey.isUnlit()) { + builder.withUnlit(); + } } if (_primitiveMode == PrimitiveMode::LINES) { @@ -299,6 +301,7 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { Transform renderTransform; graphics::MaterialPointer drawMaterial; + bool proceduralRender = false; Transform textureTransform; withReadLock([&] { renderTransform = _renderTransform; @@ -306,6 +309,10 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0)); textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot))); textureTransform.setScale(glm::vec3(_materialMappingScale, 1)); + + if (drawMaterial && drawMaterial->isProcedural() && drawMaterial->isReady()) { + proceduralRender = true; + } }); if (!drawMaterial) { return; @@ -313,14 +320,27 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { batch.setModelTransform(renderTransform); - drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true); - // bind the material - if (RenderPipelines::bindMaterial(drawMaterial, batch, args->_renderMode, args->_enableTexturing)) { - args->_details._materialSwitches++; - } + if (!proceduralRender) { + drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true); + // bind the material + if (RenderPipelines::bindMaterial(drawMaterial, batch, args->_renderMode, args->_enableTexturing)) { + args->_details._materialSwitches++; + } - // Draw! - DependencyManager::get()->renderSphere(batch); + // Draw! + DependencyManager::get()->renderSphere(batch); + } else { + auto proceduralDrawMaterial = std::static_pointer_cast(drawMaterial); + glm::vec4 outColor = glm::vec4(drawMaterial->getAlbedo(), drawMaterial->getOpacity()); + outColor = proceduralDrawMaterial->getColor(outColor); + proceduralDrawMaterial->prepare(batch, renderTransform.getTranslation(), renderTransform.getScale(), + renderTransform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f)); + if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) { + DependencyManager::get()->renderWireSphere(batch, outColor); + } else { + DependencyManager::get()->renderSphere(batch, outColor); + } + } args->_details._trianglesRendered += (int)DependencyManager::get()->getSphereTriangleCount(); } diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index d714727c7a..f9805ae229 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -13,7 +13,7 @@ #include -#include +#include class NetworkMaterial; diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 6a0d7b001c..ec05ba4319 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -12,10 +12,8 @@ #include #include -#include #include #include -#include #include "RenderPipelines.h" @@ -30,29 +28,21 @@ using namespace render::entities; // is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down. static const float SPHERE_ENTITY_SCALE = 0.5f; -static_assert(shader::render_utils::program::simple != 0, "Validate simple program exists"); -static_assert(shader::render_utils::program::simple_transparent != 0, "Validate simple transparent program exists"); - ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { - _procedural._vertexSource = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::simple); - // FIXME: Setup proper uniform slots and use correct pipelines for forward rendering - _procedural._opaqueFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple); - _procedural._transparentFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple_transparent); - - // TODO: move into Procedural.cpp - PrepareStencil::testMaskDrawShape(*_procedural._opaqueState); - PrepareStencil::testMask(*_procedural._transparentState); - addMaterial(graphics::MaterialLayer(_material, 0), "0"); } bool ShapeEntityRenderer::needsRenderUpdate() const { if (resultWithReadLock([&] { - if (_procedural.isEnabled() && _procedural.isFading()) { - return true; + auto mat = _materials.find("0"); + if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isProcedural() && + mat->second.top().material->isEnabled()) { + auto procedural = std::static_pointer_cast(mat->second.top().material); + if (procedural->isFading()) { + return true; + } } - auto mat = _materials.find("0"); if (mat != _materials.end() && mat->second.shouldUpdate()) { return true; } @@ -66,10 +56,6 @@ bool ShapeEntityRenderer::needsRenderUpdate() const { } bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { - if (_lastUserData != entity->getUserData()) { - return true; - } - if (_color != entity->getColor()) { return true; } @@ -89,17 +75,15 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin return true; } + if (_proceduralData != entity->getUserData()) { + return true; + } + return false; } void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { withWriteLock([&] { - auto userData = entity->getUserData(); - if (_lastUserData != userData) { - _lastUserData = userData; - _procedural.setProceduralData(ProceduralData::parse(_lastUserData)); - } - _shape = entity->getShape(); _pulseProperties = entity->getPulseProperties(); }); @@ -124,25 +108,45 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { withReadLock([&] { - if (_procedural.isEnabled() && _procedural.isFading()) { - float isFading = Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) < 1.0f; - _procedural.setIsFading(isFading); + auto mat = _materials.find("0"); + if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isEnabled()) { + auto procedural = std::static_pointer_cast(mat->second.top().material); + if (procedural->isFading()) { + procedural->setIsFading(Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) < 1.0f); + } } }); - glm::u8vec3 color = entity->getColor(); - float alpha = entity->getAlpha(); - if (_color != color || _alpha != alpha) { - _color = color; - _alpha = alpha; - _material->setAlbedo(toGlm(_color)); - _material->setOpacity(_alpha); - - auto materials = _materials.find("0"); - if (materials != _materials.end()) { - materials->second.setNeedsUpdate(true); + withWriteLock([&] { + bool materialChanged = false; + glm::u8vec3 color = entity->getColor(); + if (_color != color) { + _color = color; + _material->setAlbedo(toGlm(_color)); + materialChanged = true; } - } + + float alpha = entity->getAlpha(); + if (_alpha != alpha) { + _alpha = alpha; + _material->setOpacity(_alpha); + materialChanged = true; + } + + auto userData = entity->getUserData(); + if (_proceduralData != userData) { + _proceduralData = userData; + _material->setProceduralData(_proceduralData); + materialChanged = true; + } + + if (materialChanged) { + auto materials = _materials.find("0"); + if (materials != _materials.end()) { + materials->second.setNeedsUpdate(true); + } + } + }); } bool ShapeEntityRenderer::isTransparent() const { @@ -150,12 +154,15 @@ bool ShapeEntityRenderer::isTransparent() const { return true; } - if (_procedural.isEnabled() && _procedural.isFading()) { - return Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) < 1.0f; - } - auto mat = _materials.find("0"); - if (mat != _materials.end()) { + if (mat != _materials.end() && mat->second.top().material) { + if (mat->second.top().material->isProcedural() && mat->second.top().material->isEnabled()) { + auto procedural = std::static_pointer_cast(mat->second.top().material); + if (procedural->isFading()) { + return true; + } + } + if (mat->second.getMaterialKey().isTranslucent()) { return true; } @@ -164,80 +171,59 @@ bool ShapeEntityRenderer::isTransparent() const { return Parent::isTransparent(); } -bool ShapeEntityRenderer::useMaterialPipeline(const graphics::MultiMaterial& materials) const { - bool proceduralReady = resultWithReadLock([&] { - return _procedural.isReady(); - }); - if (proceduralReady) { - return false; +ShapeEntityRenderer::Pipeline ShapeEntityRenderer::getPipelineType(const graphics::MultiMaterial& materials) const { + if (materials.top().material && materials.top().material->isProcedural() && materials.top().material->isReady()) { + return Pipeline::PROCEDURAL; } graphics::MaterialKey drawMaterialKey = materials.getMaterialKey(); if (drawMaterialKey.isEmissive() || drawMaterialKey.isUnlit() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) { - return true; + return Pipeline::MATERIAL; } // If the material is using any map, we need to use a material ShapeKey for (int i = 0; i < graphics::Material::MapChannel::NUM_MAP_CHANNELS; i++) { if (drawMaterialKey.isMapChannel(graphics::Material::MapChannel(i))) { - return true; + return Pipeline::MATERIAL; } } - return false; + return Pipeline::SIMPLE; } ShapeKey ShapeEntityRenderer::getShapeKey() { + ShapeKey::Builder builder; auto mat = _materials.find("0"); if (mat != _materials.end() && mat->second.shouldUpdate()) { RenderPipelines::updateMultiMaterial(mat->second); } - if (mat != _materials.end() && useMaterialPipeline(mat->second)) { - graphics::MaterialKey drawMaterialKey = mat->second.getMaterialKey(); + if (isTransparent()) { + builder.withTranslucent(); + } - bool isTranslucent = drawMaterialKey.isTranslucent(); - bool hasTangents = drawMaterialKey.isNormalMap(); - bool hasLightmap = drawMaterialKey.isLightmapMap(); - bool isUnlit = drawMaterialKey.isUnlit(); + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } - ShapeKey::Builder builder; + auto pipelineType = getPipelineType(mat->second); + if (pipelineType == Pipeline::MATERIAL) { builder.withMaterial(); - if (isTranslucent) { - builder.withTranslucent(); - } - if (hasTangents) { + graphics::MaterialKey drawMaterialKey = mat->second.getMaterialKey(); + if (drawMaterialKey.isNormalMap()) { builder.withTangents(); } - if (hasLightmap) { + if (drawMaterialKey.isLightmapMap()) { builder.withLightmap(); } - if (isUnlit) { + if (drawMaterialKey.isUnlit()) { builder.withUnlit(); } - - if (_primitiveMode == PrimitiveMode::LINES) { - builder.withWireframe(); - } - - return builder.build(); - } else { - ShapeKey::Builder builder; - bool proceduralReady = resultWithReadLock([&] { - return _procedural.isReady(); - }); - if (proceduralReady) { - builder.withOwnPipeline(); - } - if (isTransparent()) { - builder.withTranslucent(); - } - - if (_primitiveMode == PrimitiveMode::LINES) { - builder.withWireframe(); - } - return builder.build(); + } else if (pipelineType == Pipeline::PROCEDURAL) { + builder.withOwnPipeline(); } + + return builder.build(); } void ShapeEntityRenderer::doRender(RenderArgs* args) { @@ -251,32 +237,31 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { GeometryCache::Shape geometryShape; PrimitiveMode primitiveMode; RenderLayer renderLayer; - bool proceduralRender = false; glm::vec4 outColor; + Pipeline pipelineType; withReadLock([&] { geometryShape = geometryCache->getShapeForEntityShape(_shape); primitiveMode = _primitiveMode; renderLayer = _renderLayer; batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation materials = _materials["0"]; + pipelineType = getPipelineType(materials); auto& schema = materials.getSchemaBuffer().get(); outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity); outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created); - if (_procedural.isReady()) { - outColor = _procedural.getColor(outColor); - outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; - _procedural.prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f)); - proceduralRender = true; - } }); - if (proceduralRender) { + if (pipelineType == Pipeline::PROCEDURAL) { + auto procedural = std::static_pointer_cast(materials.top().material); + outColor = procedural->getColor(outColor); + outColor.a *= procedural->isFading() ? Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) : 1.0f; + procedural->prepare(batch, _position, _dimensions, _orientation, _created, ProceduralProgramKey(outColor.a < 1.0f)); if (render::ShapeKey(args->_globalShapeKey).isWireframe() || primitiveMode == PrimitiveMode::LINES) { geometryCache->renderWireShape(batch, geometryShape, outColor); } else { geometryCache->renderShape(batch, geometryShape, outColor); } - } else if (!useMaterialPipeline(materials)) { + } else if (pipelineType == Pipeline::SIMPLE) { // FIXME, support instanced multi-shape rendering using multidraw indirect outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; render::ShapePipelinePointer pipeline; diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index c9fd4801d5..d1c875012e 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -35,14 +35,14 @@ private: virtual void doRender(RenderArgs* args) override; virtual bool isTransparent() const override; - bool useMaterialPipeline(const graphics::MultiMaterial& materials) const; + enum Pipeline { SIMPLE, MATERIAL, PROCEDURAL }; + Pipeline getPipelineType(const graphics::MultiMaterial& materials) const; - Procedural _procedural; - QString _lastUserData; + QString _proceduralData; entity::Shape _shape { entity::Sphere }; PulsePropertyGroup _pulseProperties; - std::shared_ptr _material { std::make_shared() }; + std::shared_ptr _material { std::make_shared() }; glm::u8vec3 _color; float _alpha; diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index 56adb59914..819365265f 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -6,4 +6,5 @@ include_hifi_library_headers(fbx) include_hifi_library_headers(gpu) include_hifi_library_headers(image) include_hifi_library_headers(ktx) +include_hifi_library_headers(procedural) link_hifi_libraries(shared shaders networking octree avatars graphics material-networking model-networking) diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 987e632025..61e9ce6024 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -118,9 +118,6 @@ protected: Shader(Type type, const Source& source, bool dynamic); Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel); - Shader(const Shader& shader); // deep copy of the sysmem shader - Shader& operator=(const Shader& shader); // deep copy of the sysmem texture - // Source contains the actual source code or nothing if the shader is a program const Source _source; diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 330feaa61c..6bf72d9f24 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -343,6 +343,10 @@ public: bool getPropertyFallthrough(uint property) { return _propertyFallthroughs[property]; } void setPropertyDoesFallthrough(uint property) { _propertyFallthroughs[property] = true; } + virtual bool isProcedural() const { return false; } + virtual bool isEnabled() const { return true; } + virtual bool isReady() const { return true; } + protected: std::string _name { "" }; diff --git a/libraries/model-baker/CMakeLists.txt b/libraries/model-baker/CMakeLists.txt index 6c0f220340..bf75db4750 100644 --- a/libraries/model-baker/CMakeLists.txt +++ b/libraries/model-baker/CMakeLists.txt @@ -1,7 +1,8 @@ set(TARGET_NAME model-baker) setup_hifi_library() -link_hifi_libraries(shared shaders task gpu graphics hfm material-networking) +link_hifi_libraries(shared shaders task gpu graphics hfm procedural) +include_hifi_library_headers(material-networking) include_hifi_library_headers(networking) include_hifi_library_headers(image) include_hifi_library_headers(ktx) diff --git a/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h index 7c94661b28..3e967a7d3f 100644 --- a/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h +++ b/libraries/model-baker/src/model-baker/ParseMaterialMappingTask.h @@ -18,7 +18,7 @@ #include "Engine.h" #include "BakerTypes.h" -#include +#include class ParseMaterialMappingTask { public: diff --git a/libraries/model-networking/CMakeLists.txt b/libraries/model-networking/CMakeLists.txt index e79d18f779..b71d125586 100644 --- a/libraries/model-networking/CMakeLists.txt +++ b/libraries/model-networking/CMakeLists.txt @@ -1,8 +1,9 @@ set(TARGET_NAME model-networking) setup_hifi_library() -link_hifi_libraries(shared shaders networking graphics fbx material-networking model-baker) +link_hifi_libraries(shared shaders networking graphics fbx procedural model-baker) include_hifi_library_headers(hfm) include_hifi_library_headers(task) include_hifi_library_headers(gpu) include_hifi_library_headers(image) -include_hifi_library_headers(ktx) \ No newline at end of file +include_hifi_library_headers(ktx) +include_hifi_library_headers(material-networking) \ No newline at end of file diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index f9ae2dccd6..a8e373dc6e 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -18,7 +18,7 @@ #include #include "FBXSerializer.h" -#include +#include #include #include "ModelLoader.h" diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index d7ce40641d..c1410a6bfc 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -1,17 +1,18 @@ set(TARGET_NAME physics) setup_hifi_library() -link_hifi_libraries(shared task workload fbx entities graphics shaders) +link_hifi_libraries(shared workload entities shaders) include_hifi_library_headers(networking) include_hifi_library_headers(gpu) include_hifi_library_headers(avatars) -include_hifi_library_headers(audio) include_hifi_library_headers(octree) -include_hifi_library_headers(animation) include_hifi_library_headers(material-networking) include_hifi_library_headers(model-networking) +include_hifi_library_headers(procedural) include_hifi_library_headers(image) include_hifi_library_headers(ktx) include_hifi_library_headers(gpu) include_hifi_library_headers(hfm) +include_hifi_library_headers(fbx) +include_hifi_library_headers(graphics) target_bullet() diff --git a/libraries/procedural/CMakeLists.txt b/libraries/procedural/CMakeLists.txt index d08a7aef02..d737d34e95 100644 --- a/libraries/procedural/CMakeLists.txt +++ b/libraries/procedural/CMakeLists.txt @@ -1,4 +1,4 @@ set(TARGET_NAME procedural) setup_hifi_library() -link_hifi_libraries(shared gpu shaders networking graphics material-networking ktx image) +link_hifi_libraries(shared gpu shaders networking graphics material-networking ktx image hfm) diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index dbdf9cc7d1..cd872a84fc 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -29,6 +29,7 @@ Q_LOGGING_CATEGORY(proceduralLog, "hifi.gpu.procedural") // User-data parsing constants static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity"; +static const QString FRAGMENT_URL_KEY = "fragmentShaderURL"; static const QString URL_KEY = "shaderUrl"; static const QString VERSION_KEY = "version"; static const QString UNIFORMS_KEY = "uniforms"; @@ -40,7 +41,7 @@ static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION"; bool operator==(const ProceduralData& a, const ProceduralData& b) { return ((a.version == b.version) && - (a.shaderUrl == b.shaderUrl) && + (a.fragmentShaderUrl == b.fragmentShaderUrl) && (a.uniforms == b.uniforms) && (a.channels == b.channels)); } @@ -56,7 +57,13 @@ QJsonValue ProceduralData::getProceduralData(const QString& proceduralJson) { return QJsonValue(); } - return doc.object()[PROCEDURAL_USER_DATA_KEY]; + auto object = doc.object(); + auto userDataIt = object.find(PROCEDURAL_USER_DATA_KEY); + if (userDataIt != object.end()) { + return userDataIt.value(); + } + + return object; } ProceduralData ProceduralData::parse(const QString& proceduralData) { @@ -84,11 +91,18 @@ void ProceduralData::parse(const QJsonObject& proceduralData) { } } - auto rawShaderUrl = proceduralData[URL_KEY].toString(); - shaderUrl = DependencyManager::get()->normalizeURL(rawShaderUrl); + { // Fragment shader URL (either fragmentShaderUrl or shaderUrl) + auto rawShaderUrl = proceduralData[FRAGMENT_URL_KEY].toString(); + fragmentShaderUrl = DependencyManager::get()->normalizeURL(rawShaderUrl); + + if (fragmentShaderUrl.isEmpty()) { + rawShaderUrl = proceduralData[URL_KEY].toString(); + fragmentShaderUrl = DependencyManager::get()->normalizeURL(rawShaderUrl); + } + } // Empty shader URL isn't valid - if (shaderUrl.isEmpty()) { + if (fragmentShaderUrl.isEmpty()) { return; } @@ -96,12 +110,8 @@ void ProceduralData::parse(const QJsonObject& proceduralData) { channels = proceduralData[CHANNELS_KEY].toArray(); } -// Example -//{ -// "ProceduralEntity": { -// "shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/test.fs", -// } -//} +std::function Procedural::opaqueStencil = [](gpu::StatePointer state) {}; +std::function Procedural::transparentStencil = [](gpu::StatePointer state) {}; Procedural::Procedural() { _opaqueState->setCullMode(gpu::State::CULL_NONE); @@ -109,12 +119,14 @@ Procedural::Procedural() { _opaqueState->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + opaqueStencil(_opaqueState); _transparentState->setCullMode(gpu::State::CULL_NONE); _transparentState->setDepthTest(true, true, gpu::LESS_EQUAL); _transparentState->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + transparentStencil(_transparentState); _standardInputsBuffer = std::make_shared(sizeof(StandardInputs), nullptr); } @@ -158,14 +170,14 @@ void Procedural::setProceduralData(const ProceduralData& proceduralData) { } } - if (proceduralData.shaderUrl != _data.shaderUrl) { - _data.shaderUrl = proceduralData.shaderUrl; - const auto& shaderUrl = _data.shaderUrl; + if (proceduralData.fragmentShaderUrl != _data.fragmentShaderUrl) { + _data.fragmentShaderUrl = proceduralData.fragmentShaderUrl; + const auto& shaderUrl = _data.fragmentShaderUrl; _shaderDirty = true; - _networkShader.reset(); - _shaderPath.clear(); - _shaderSource.clear(); + _networkFragmentShader.reset(); + _fragmentShaderPath.clear(); + _fragmentShaderSource.clear(); if (shaderUrl.isEmpty() || !shaderUrl.isValid()) { return; @@ -175,11 +187,11 @@ void Procedural::setProceduralData(const ProceduralData& proceduralData) { if (!QFileInfo(shaderUrl.toLocalFile()).exists()) { return; } - _shaderPath = shaderUrl.toLocalFile(); + _fragmentShaderPath = shaderUrl.toLocalFile(); } else if (shaderUrl.scheme() == URL_SCHEME_QRC) { - _shaderPath = ":" + shaderUrl.path(); + _fragmentShaderPath = ":" + shaderUrl.path(); } else { - _networkShader = ShaderCache::instance().getShader(shaderUrl); + _networkFragmentShader = ShaderCache::instance().getShader(shaderUrl); } } @@ -202,7 +214,7 @@ bool Procedural::isReady() const { } // Do we have a network or local shader, and if so, is it loaded? - if (_shaderPath.isEmpty() && (!_networkShader || !_networkShader->isLoaded())) { + if (_fragmentShaderPath.isEmpty() && (!_networkFragmentShader || !_networkFragmentShader->isLoaded())) { return false; } @@ -232,17 +244,17 @@ void Procedural::prepare(gpu::Batch& batch, _entityPosition = position; _entityOrientation = glm::mat3_cast(orientation); _entityCreated = created; - if (!_shaderPath.isEmpty()) { - auto lastModified = (uint64_t)QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch(); - if (lastModified > _shaderModified) { - QFile file(_shaderPath); + if (!_fragmentShaderPath.isEmpty()) { + auto lastModified = (uint64_t)QFileInfo(_fragmentShaderPath).lastModified().toMSecsSinceEpoch(); + if (lastModified > _fragmentShaderModified) { + QFile file(_fragmentShaderPath); file.open(QIODevice::ReadOnly); - _shaderSource = QTextStream(&file).readAll(); + _fragmentShaderSource = QTextStream(&file).readAll(); _shaderDirty = true; - _shaderModified = lastModified; + _fragmentShaderModified = lastModified; } - } else if (_shaderSource.isEmpty() && _networkShader && _networkShader->isLoaded()) { - _shaderSource = _networkShader->_source; + } else if (_fragmentShaderSource.isEmpty() && _networkFragmentShader && _networkFragmentShader->isLoaded()) { + _fragmentShaderSource = _networkFragmentShader->_source; _shaderDirty = true; } @@ -253,8 +265,13 @@ void Procedural::prepare(gpu::Batch& batch, auto pipeline = _proceduralPipelines.find(key); bool recompiledShader = false; if (pipeline == _proceduralPipelines.end()) { - if (!_vertexShader) { - _vertexShader = gpu::Shader::createVertex(_vertexSource); + gpu::Shader::Source vertexSource; + if (key.isSkinnedDQ()) { + vertexSource = _vertexSourceSkinnedDQ; + } else if (key.isSkinned()) { + vertexSource = _vertexSourceSkinned; + } else { + vertexSource = _vertexSource; } gpu::Shader::Source& fragmentSource = (key.isTransparent() && _transparentFragmentSource.valid()) ? _transparentFragmentSource : _opaqueFragmentSource; @@ -262,7 +279,7 @@ void Procedural::prepare(gpu::Batch& batch, // Build the fragment shader fragmentSource.replacements.clear(); fragmentSource.replacements[PROCEDURAL_VERSION] = "#define PROCEDURAL_V" + std::to_string(_data.version); - fragmentSource.replacements[PROCEDURAL_BLOCK] = _shaderSource.toStdString(); + fragmentSource.replacements[PROCEDURAL_BLOCK] = _fragmentShaderSource.toStdString(); // Set any userdata specified uniforms int customSlot = procedural::slot::uniform::Custom; @@ -275,8 +292,9 @@ void Procedural::prepare(gpu::Batch& batch, // Leave this here for debugging //qCDebug(proceduralLog) << "FragmentShader:\n" << fragmentSource.getSource(shader::Dialect::glsl450, shader::Variant::Mono).c_str(); + gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(vertexSource); gpu::ShaderPointer fragmentShader = gpu::Shader::createPixel(fragmentSource); - gpu::ShaderPointer program = gpu::Shader::createProgram(_vertexShader, fragmentShader); + gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, fragmentShader); _proceduralPipelines[key] = gpu::Pipeline::create(program, key.isTransparent() ? _transparentState : _opaqueState); @@ -291,10 +309,12 @@ void Procedural::prepare(gpu::Batch& batch, // FIXME: need to handle forward rendering batch.setPipeline(recompiledShader ? _proceduralPipelines[key] : pipeline->second); - if (_shaderDirty || _uniformsDirty) { + bool recreateUniforms = _shaderDirty || _uniformsDirty || recompiledShader || _prevKey != key; + if (recreateUniforms) { setupUniforms(); } + _prevKey = key; _shaderDirty = _uniformsDirty = false; for (auto lambda : _uniforms) { @@ -329,7 +349,7 @@ void Procedural::setupUniforms() { QJsonValue value = _data.uniforms[key]; if (value.isDouble()) { float v = value.toDouble(); - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); + _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); } else if (value.isArray()) { auto valueArray = value.toArray(); switch (valueArray.size()) { @@ -338,13 +358,13 @@ void Procedural::setupUniforms() { case 1: { float v = valueArray[0].toDouble(); - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); + _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); break; } case 2: { glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); }); + _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); }); break; } @@ -354,7 +374,7 @@ void Procedural::setupUniforms() { valueArray[1].toDouble(), valueArray[2].toDouble(), }; - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); }); + _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); }); break; } @@ -366,7 +386,7 @@ void Procedural::setupUniforms() { valueArray[2].toDouble(), valueArray[3].toDouble(), }; - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); }); + _uniforms.push_back([slot, v](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); }); break; } } @@ -374,7 +394,7 @@ void Procedural::setupUniforms() { slot++; } - _uniforms.push_back([=](gpu::Batch& batch) { + _uniforms.push_back([this](gpu::Batch& batch) { _standardInputs.position = vec4(_entityPosition, 1.0f); // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds auto now = usecTimestampNow(); @@ -420,3 +440,13 @@ glm::vec4 Procedural::getColor(const glm::vec4& entityColor) const { } return entityColor; } + +void graphics::ProceduralMaterial::initializeProcedural() { + _procedural._vertexSource = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::simple); + _procedural._vertexSourceSkinned = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::deformed_simple); + _procedural._vertexSourceSkinnedDQ = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::deformed_simple_dq); + + // FIXME: Setup proper uniform slots and use correct pipelines for forward rendering + _procedural._opaqueFragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple); + _procedural._transparentFragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_transparent); +} \ No newline at end of file diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 956cef368f..2ae50e0ffe 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -21,11 +21,26 @@ #include #include #include +#include "ProceduralMaterialCache.h" using UniformLambdas = std::list>; const size_t MAX_PROCEDURAL_TEXTURE_CHANNELS{ 4 }; +/**jsdoc + * An object containing user-defined uniforms for communicating data to shaders. + * @typedef {object} ProceduralUniforms + */ + +/**jsdoc + * The data used to define a Procedural shader material. + * @typedef {object} ProceduralData + * @property {number} version=1 - The version of the procedural shader. + * @property {string} fragmentShaderURL - A link to a fragment shader. Currently, only GLSL shaders are supported. The shader must implement a different method depending on the version. + * shaderUrl is an alias. + * @property {string[]} channels=[] - An array of input texture URLs. Currently, up to 4 are supported. + * @property {ProceduralUniforms} uniforms={} - A {@link ProceduralUniforms} object containing all the custom uniforms to be passed to the shader. + */ struct ProceduralData { static QJsonValue getProceduralData(const QString& proceduralJson); @@ -34,7 +49,7 @@ struct ProceduralData { // Rendering object descriptions, from userData uint8_t version { 0 }; - QUrl shaderUrl; + QUrl fragmentShaderUrl; QJsonObject uniforms; QJsonArray channels; }; @@ -43,19 +58,23 @@ class ProceduralProgramKey { public: enum FlagBit { IS_TRANSPARENT = 0, + IS_SKINNED, + IS_SKINNED_DQ, + NUM_FLAGS }; - typedef std::bitset Flags; Flags _flags; bool isTransparent() const { return _flags[IS_TRANSPARENT]; } + bool isSkinned() const { return _flags[IS_SKINNED]; } + bool isSkinnedDQ() const { return _flags[IS_SKINNED_DQ]; } - ProceduralProgramKey(bool transparent = false) { - if (transparent) { - _flags.set(IS_TRANSPARENT); - } + ProceduralProgramKey(bool transparent = false, bool isSkinned = false, bool isSkinnedDQ = false) { + _flags.set(IS_TRANSPARENT, transparent); + _flags.set(IS_SKINNED, isSkinned); + _flags.set(IS_SKINNED_DQ, isSkinnedDQ); } }; namespace std { @@ -92,12 +111,16 @@ public: void setDoesFade(bool doesFade) { _doesFade = doesFade; } gpu::Shader::Source _vertexSource; + gpu::Shader::Source _vertexSourceSkinned; + gpu::Shader::Source _vertexSourceSkinnedDQ; gpu::Shader::Source _opaqueFragmentSource; gpu::Shader::Source _transparentFragmentSource; gpu::StatePointer _opaqueState { std::make_shared() }; gpu::StatePointer _transparentState { std::make_shared() }; + static std::function opaqueStencil; + static std::function transparentStencil; protected: // DO NOT TOUCH @@ -134,10 +157,10 @@ protected: int32_t _frameCount { 0 }; // Rendering object descriptions, from userData - QString _shaderSource; - QString _shaderPath; - uint64_t _shaderModified { 0 }; - NetworkShaderPointer _networkShader; + QString _fragmentShaderSource; + QString _fragmentShaderPath; + uint64_t _fragmentShaderModified { 0 }; + NetworkShaderPointer _networkFragmentShader; bool _shaderDirty { true }; bool _uniformsDirty { true }; @@ -147,8 +170,6 @@ protected: std::unordered_map _proceduralPipelines; - gpu::ShaderPointer _vertexShader; - StandardInputs _standardInputs; gpu::BufferPointer _standardInputsBuffer; @@ -165,5 +186,36 @@ private: mutable bool _hasStartedFade { false }; mutable bool _isFading { false }; bool _doesFade { true }; + ProceduralProgramKey _prevKey; mutable std::mutex _mutex; }; + +namespace graphics { + +class ProceduralMaterial : public NetworkMaterial { +public: + ProceduralMaterial() : NetworkMaterial() { initializeProcedural(); } + ProceduralMaterial(const NetworkMaterial& material) : NetworkMaterial(material) { initializeProcedural(); } + //ProceduralMaterial(const ProceduralMaterial& material) : NetworkMaterial(material), _procedural(material._procedural) {} + + bool isProcedural() const override { return true; } + bool isEnabled() const override { return _procedural.isEnabled(); } + bool isReady() const override { return _procedural.isReady(); } + void setProceduralData(const QString& data) { _procedural.setProceduralData(ProceduralData::parse(data)); } + glm::vec4 getColor(const glm::vec4& color) const { return _procedural.getColor(color); } + bool isFading() const { return _procedural.isFading(); } + void setIsFading(bool isFading) { _procedural.setIsFading(isFading); } + uint64_t getFadeStartTime() const { return _procedural.getFadeStartTime(); } + void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, + const uint64_t& created, const ProceduralProgramKey key = ProceduralProgramKey()) { + _procedural.prepare(batch, position, size, orientation, created, key); + } + + void initializeProcedural(); + +private: + Procedural _procedural; +}; +typedef std::shared_ptr ProceduralMaterialPointer; + +} \ No newline at end of file diff --git a/libraries/material-networking/src/material-networking/MaterialCache.cpp b/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp similarity index 92% rename from libraries/material-networking/src/material-networking/MaterialCache.cpp rename to libraries/procedural/src/procedural/ProceduralMaterialCache.cpp index 745504fb3d..78cb6c7daa 100644 --- a/libraries/material-networking/src/material-networking/MaterialCache.cpp +++ b/libraries/procedural/src/procedural/ProceduralMaterialCache.cpp @@ -5,7 +5,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "MaterialCache.h" +#include "ProceduralMaterialCache.h" #include "QJsonObject" #include "QJsonDocument" @@ -13,6 +13,8 @@ #include "RegisteredMetaTypes.h" +#include "Procedural.h" + NetworkMaterialResource::NetworkMaterialResource(const QUrl& url) : Resource(url) {} @@ -112,18 +114,18 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater * A material such as may be used by a {@link Entities.EntityType|Material} entity. * @typedef {object} Material * @property {string} model="hifi_pbr" - Different material models support different properties and rendering modes. - * Supported models are: "hifi_pbr" + * Supported models are: "hifi_pbr", "hifi_shader_simple" * @property {string} name="" - A name for the material. Supported by all material models. * @property {Color|RGBS|string} emissive - The emissive color, i.e., the color that the material emits. A {@link Color} value * is treated as sRGB. A {@link RGBS} value can be either RGB or sRGB. Set to "fallthrough" to fallthrough to * the material below. "hifi_pbr" model only. * @property {number|string} opacity=1.0 - The opacity, 0.01.0. Set to "fallthrough" to fallthrough to - * the material below. "hifi_pbr" model only. + * the material below. Supported by all material models. * @property {boolean|string} unlit=false - If true, the material is not lit. Set to "fallthrough" to fallthrough to * the material below. "hifi_pbr" model only. * @property {Color|RGBS|string} albedo - The albedo color. A {@link Color} value is treated as sRGB. A {@link RGBS} value can * be either RGB or sRGB. Set to "fallthrough" to fallthrough to the material below. Set to "fallthrough" to fallthrough to - * the material below. "hifi_pbr" model only. + * the material below. Supported by all material models. * @property {number|string} roughness - The roughness, 0.01.0. Set to "fallthrough" to fallthrough to * the material below. "hifi_pbr" model only. * @property {number|string} metallic - The metallicness, 0.01.0. Set to "fallthrough" to fallthrough to @@ -163,23 +165,25 @@ NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMater * to fallthrough to the material below. "hifi_pbr" model only. * @property {bool} defaultFallthrough=false - If true, all properties will fallthrough to the material below unless they are set. If * false, they will respect the individual properties' fallthrough state. "hifi_pbr" model only. + * @property {ProceduralData} procedural - The definition of a procedural shader material. "hifi_shader_simple" model only. */ // Note: See MaterialEntityItem.h for default values used in practice. std::pair> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON, const QUrl& baseUrl) { std::string name = ""; - std::shared_ptr material = std::make_shared(); + std::shared_ptr networkMaterial; - const std::string HIFI_PBR = "hifi_pbr"; + static const std::string HIFI_PBR = "hifi_pbr"; + static const std::string HIFI_SHADER_SIMPLE = "hifi_shader_simple"; std::string modelString = HIFI_PBR; auto modelJSONIter = materialJSON.find("model"); if (modelJSONIter != materialJSON.end() && modelJSONIter.value().isString()) { modelString = modelJSONIter.value().toString().toStdString(); - material->setModel(modelString); } std::array texcoordTransforms; if (modelString == HIFI_PBR) { + auto material = std::make_shared(); const QString FALLTHROUGH("fallthrough"); for (auto& key : materialJSON.keys()) { if (key == "name") { @@ -188,11 +192,6 @@ std::pair> NetworkMaterialResource name = nameJSON.toString().toStdString(); material->setName(name); } - } else if (key == "model") { - auto modelJSON = materialJSON.value(key); - if (modelJSON.isString()) { - material->setModel(modelJSON.toString().toStdString()); - } } else if (key == "emissive") { auto value = materialJSON.value(key); if (value.isString() && value.toString() == FALLTHROUGH) { @@ -416,17 +415,57 @@ std::pair> NetworkMaterialResource } } } - } - // Do this after the texture maps are defined, so it overrides the default transforms - for (int i = 0; i < graphics::Material::NUM_TEXCOORD_TRANSFORMS; i++) { - mat4 newTransform = texcoordTransforms[i]; - if (newTransform != mat4() || newTransform != material->getTexCoordTransform(i)) { - material->setTexCoordTransform(i, newTransform); + // Do this after the texture maps are defined, so it overrides the default transforms + for (int i = 0; i < graphics::Material::NUM_TEXCOORD_TRANSFORMS; i++) { + mat4 newTransform = texcoordTransforms[i]; + if (newTransform != mat4() || newTransform != material->getTexCoordTransform(i)) { + material->setTexCoordTransform(i, newTransform); + } } + networkMaterial = material; + } else if (modelString == HIFI_SHADER_SIMPLE) { + auto material = std::make_shared(); + const QString FALLTHROUGH("fallthrough"); + for (auto& key : materialJSON.keys()) { + if (key == "name") { + auto nameJSON = materialJSON.value(key); + if (nameJSON.isString()) { + name = nameJSON.toString().toStdString(); + material->setName(name); + } + } else if (key == "opacity") { + auto value = materialJSON.value(key); + if (value.isString() && value.toString() == FALLTHROUGH) { + material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::OPACITY_VAL_BIT); + } else if (value.isDouble()) { + material->setOpacity(value.toDouble()); + } + } else if (key == "albedo") { + auto value = materialJSON.value(key); + if (value.isString() && value.toString() == FALLTHROUGH) { + material->setPropertyDoesFallthrough(graphics::MaterialKey::FlagBit::ALBEDO_VAL_BIT); + } else { + glm::vec3 color; + bool isSRGB; + bool valid = parseJSONColor(value, color, isSRGB); + if (valid) { + material->setAlbedo(color, isSRGB); + } + } + } else if (key == "procedural") { + auto value = materialJSON.value(key); + material->setProceduralData(QJsonDocument::fromVariant(value.toVariant()).toJson()); + } + } + networkMaterial = material; } - return std::pair>(name, material); + if (networkMaterial) { + networkMaterial->setModel(modelString); + } + + return std::pair>(name, networkMaterial); } MaterialCache& MaterialCache::instance() { diff --git a/libraries/material-networking/src/material-networking/MaterialCache.h b/libraries/procedural/src/procedural/ProceduralMaterialCache.h similarity index 98% rename from libraries/material-networking/src/material-networking/MaterialCache.h rename to libraries/procedural/src/procedural/ProceduralMaterialCache.h index 7ed0453187..3bbaa7b2c0 100644 --- a/libraries/material-networking/src/material-networking/MaterialCache.h +++ b/libraries/procedural/src/procedural/ProceduralMaterialCache.h @@ -14,7 +14,7 @@ #include #include -#include "TextureCache.h" +#include class NetworkMaterial : public graphics::Material { public: diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 53df1532dc..d852d9242c 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -18,10 +18,11 @@ #include ProceduralSkybox::ProceduralSkybox(uint64_t created) : graphics::Skybox(), _created(created) { - _procedural._vertexSource = gpu::Shader::createVertex(shader::graphics::vertex::skybox)->getSource(); - _procedural._opaqueFragmentSource = shader::Source::get(shader::procedural::fragment::proceduralSkybox); - // Adjust the pipeline state for background using the stencil test + _procedural._vertexSource = gpu::Shader::Source::get(shader::graphics::vertex::skybox); + _procedural._opaqueFragmentSource = gpu::Shader::Source::get(shader::procedural::fragment::proceduralSkybox); _procedural.setDoesFade(false); + + // Adjust the pipeline state for background using the stencil test // Must match PrepareStencil::STENCIL_BACKGROUND const int8_t STENCIL_BACKGROUND = 0; _procedural._opaqueState->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_BACKGROUND, 0xFF, gpu::EQUAL, diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index cb3aa76468..5b59a56759 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -16,6 +16,7 @@ #include #include "render-utils/ShaderConstants.h" +#include #include "DeferredLightingEffect.h" #include "RenderPipelines.h" @@ -104,20 +105,30 @@ Item::Bound MeshPartPayload::getBound() const { } ShapeKey MeshPartPayload::getShapeKey() const { - graphics::MaterialKey drawMaterialKey = _drawMaterials.getMaterialKey(); - ShapeKey::Builder builder; - builder.withMaterial(); + graphics::MaterialPointer material = _drawMaterials.empty() ? nullptr : _drawMaterials.top().material; + graphics::MaterialKey drawMaterialKey = _drawMaterials.getMaterialKey(); if (drawMaterialKey.isTranslucent()) { builder.withTranslucent(); } - if (drawMaterialKey.isNormalMap()) { - builder.withTangents(); - } - if (drawMaterialKey.isLightmapMap()) { - builder.withLightmap(); + + if (material && material->isProcedural() && material->isReady()) { + builder.withOwnPipeline(); + } else { + builder.withMaterial(); + + if (drawMaterialKey.isNormalMap()) { + builder.withTangents(); + } + if (drawMaterialKey.isLightmapMap()) { + builder.withLightmap(); + } + if (drawMaterialKey.isUnlit()) { + builder.withUnlit(); + } } + return builder.build(); } @@ -153,9 +164,19 @@ void MeshPartPayload::render(RenderArgs* args) { //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); - // apply material properties - if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) { - args->_details._materialSwitches++; + if (!_drawMaterials.empty() && _drawMaterials.top().material && _drawMaterials.top().material->isProcedural() && + _drawMaterials.top().material->isReady()) { + auto procedural = std::static_pointer_cast(_drawMaterials.top().material); + auto& schema = _drawMaterials.getSchemaBuffer().get(); + glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity); + outColor = procedural->getColor(outColor); + procedural->prepare(batch, _drawTransform.getTranslation(), _drawTransform.getScale(), _drawTransform.getRotation(), 0, // FIXME: pass in _created + ProceduralProgramKey(outColor.a < 1.0f)); + } else { + // apply material properties + if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) { + args->_details._materialSwitches++; + } } // Draw! @@ -350,43 +371,46 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode pr RenderPipelines::updateMultiMaterial(_drawMaterials); } + ShapeKey::Builder builder; + graphics::MaterialPointer material = _drawMaterials.empty() ? nullptr : _drawMaterials.top().material; graphics::MaterialKey drawMaterialKey = _drawMaterials.getMaterialKey(); - - bool isTranslucent = drawMaterialKey.isTranslucent(); - bool hasTangents = drawMaterialKey.isNormalMap() && _hasTangents; - bool hasLightmap = drawMaterialKey.isLightmapMap(); - bool isUnlit = drawMaterialKey.isUnlit(); - - bool isDeformed = _isBlendShaped || _isSkinned; bool isWireframe = primitiveMode == PrimitiveMode::LINES; if (isWireframe) { - isTranslucent = hasTangents = hasLightmap = false; - } - - ShapeKey::Builder builder; - builder.withMaterial(); - - if (isTranslucent) { + builder.withWireframe(); + } else if (drawMaterialKey.isTranslucent()) { builder.withTranslucent(); } - if (hasTangents) { - builder.withTangents(); - } - if (hasLightmap) { - builder.withLightmap(); - } - if (isUnlit) { - builder.withUnlit(); - } - if (isDeformed) { + + if (_isSkinned || (_isBlendShaped && _meshBlendshapeBuffer)) { builder.withDeformed(); + if (useDualQuaternionSkinning) { + builder.withDualQuatSkinned(); + } } - if (isWireframe) { - builder.withWireframe(); - } - if (isDeformed && useDualQuaternionSkinning) { - builder.withDualQuatSkinned(); + + if (material && material->isProcedural() && material->isReady()) { + builder.withOwnPipeline(); + } else { + bool hasTangents = drawMaterialKey.isNormalMap() && _hasTangents; + bool hasLightmap = drawMaterialKey.isLightmapMap(); + bool isUnlit = drawMaterialKey.isUnlit(); + + if (isWireframe) { + hasTangents = hasLightmap = false; + } + + builder.withMaterial(); + + if (hasTangents) { + builder.withTangents(); + } + if (hasLightmap) { + builder.withLightmap(); + } + if (isUnlit) { + builder.withUnlit(); + } } _shapeKey = builder.build(); @@ -432,9 +456,19 @@ void ModelMeshPartPayload::render(RenderArgs* args) { batch.setDrawcallUniform(drawcallInfo); } - // apply material properties - if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) { - args->_details._materialSwitches++; + if (!_drawMaterials.empty() && _drawMaterials.top().material && _drawMaterials.top().material->isProcedural() && + _drawMaterials.top().material->isReady()) { + auto procedural = std::static_pointer_cast(_drawMaterials.top().material); + auto& schema = _drawMaterials.getSchemaBuffer().get(); + glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity); + outColor = procedural->getColor(outColor); + procedural->prepare(batch, _drawTransform.getTranslation(), _drawTransform.getScale(), _drawTransform.getRotation(), 0,// FIXME: pass in _created + ProceduralProgramKey(outColor.a < 1.0f, _shapeKey.isDeformed(), _shapeKey.isDualQuatSkinned())); + } else { + // apply material properties + if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) { + args->_details._materialSwitches++; + } } // Draw! diff --git a/libraries/render-utils/src/deformed_simple.slv b/libraries/render-utils/src/deformed_simple.slv new file mode 100644 index 0000000000..ca587b79ef --- /dev/null +++ b/libraries/render-utils/src/deformed_simple.slv @@ -0,0 +1,47 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gondelman on 5/15/19 +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Inputs.slh@> +<@include gpu/Color.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include MeshDeformer.slh@> +<$declareMeshDeformer(1, _SCRIBE_NULL, 1, _SCRIBE_NULL, 1)$> +<$declareMeshDeformerActivation(1, 1)$> + +<@include render-utils/ShaderConstants.h@> + +layout(location=RENDER_UTILS_ATTR_NORMAL_WS) out vec3 _normalWS; +layout(location=RENDER_UTILS_ATTR_NORMAL_MS) out vec3 _normalMS; +layout(location=RENDER_UTILS_ATTR_COLOR) out vec4 _color; +layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01; +layout(location=RENDER_UTILS_ATTR_POSITION_MS) out vec4 _positionMS; +layout(location=RENDER_UTILS_ATTR_POSITION_ES) out vec4 _positionES; + +void main(void) { + vec4 deformedPosition = vec4(0.0, 0.0, 0.0, 0.0); + vec3 deformedNormal = vec3(0.0, 0.0, 0.0); + evalMeshDeformer(inPosition, deformedPosition, inNormal.xyz, deformedNormal, + meshDeformer_doSkinning(_drawCallInfo.y), inSkinClusterIndex, inSkinClusterWeight, + meshDeformer_doBlendshape(_drawCallInfo.y), gl_VertexID); + + _color = color_sRGBAToLinear(inColor); + _texCoord01.xy = inTexCoord0.st; + _positionMS = inPosition; + _normalMS = inNormal.xyz; + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, deformedPosition, _positionES, gl_Position)$> + <$transformModelToWorldDir(cam, obj, deformedNormal, _normalWS)$> +} \ No newline at end of file diff --git a/libraries/render-utils/src/deformed_simple_dq.slv b/libraries/render-utils/src/deformed_simple_dq.slv new file mode 100644 index 0000000000..825fc9a9f3 --- /dev/null +++ b/libraries/render-utils/src/deformed_simple_dq.slv @@ -0,0 +1,47 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by Sam Gondelman on 5/15/19 +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Inputs.slh@> +<@include gpu/Color.slh@> +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include MeshDeformer.slh@> +<$declareMeshDeformer(1, _SCRIBE_NULL, 1, 1, 1)$> +<$declareMeshDeformerActivation(1, 1)$> + +<@include render-utils/ShaderConstants.h@> + +layout(location=RENDER_UTILS_ATTR_NORMAL_WS) out vec3 _normalWS; +layout(location=RENDER_UTILS_ATTR_NORMAL_MS) out vec3 _normalMS; +layout(location=RENDER_UTILS_ATTR_COLOR) out vec4 _color; +layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01; +layout(location=RENDER_UTILS_ATTR_POSITION_MS) out vec4 _positionMS; +layout(location=RENDER_UTILS_ATTR_POSITION_ES) out vec4 _positionES; + +void main(void) { + vec4 deformedPosition = vec4(0.0, 0.0, 0.0, 0.0); + vec3 deformedNormal = vec3(0.0, 0.0, 0.0); + evalMeshDeformer(inPosition, deformedPosition, inNormal.xyz, deformedNormal, + meshDeformer_doSkinning(_drawCallInfo.y), inSkinClusterIndex, inSkinClusterWeight, + meshDeformer_doBlendshape(_drawCallInfo.y), gl_VertexID); + + _color = color_sRGBAToLinear(inColor); + _texCoord01.xy = inTexCoord0.st; + _positionMS = inPosition; + _normalMS = inNormal.xyz; + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToEyeAndClipPos(cam, obj, deformedPosition, _positionES, gl_Position)$> + <$transformModelToWorldDir(cam, obj, deformedNormal, _normalWS)$> +} \ No newline at end of file diff --git a/libraries/render-utils/src/forward_simple.slf b/libraries/render-utils/src/forward_simple.slf index 677c369033..7fa2b044d8 100644 --- a/libraries/render-utils/src/forward_simple.slf +++ b/libraries/render-utils/src/forward_simple.slf @@ -35,27 +35,111 @@ layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; #define _position _positionMS #define _eyePosition _positionES +<@include procedural/ProceduralCommon.slh@> + +#line 1001 +//PROCEDURAL_BLOCK_BEGIN + +vec3 getProceduralColor() { + return _color.rgb; +} + +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + return 1.0; +} + +float getProceduralFragment(inout ProceduralFragment proceduralData) { + return 1.0; +} + +float getProceduralFragmentWithPosition(inout ProceduralFragmentWithPosition proceduralData) { + return 1.0; +} + +//PROCEDURAL_BLOCK_END + layout(location=0) out vec4 _fragColor0; +#line 2030 void main(void) { vec3 normal = normalize(_normalWS.xyz); vec3 diffuse = _color.rgb; - vec3 specular = DEFAULT_SPECULAR; - float shininess = DEFAULT_SHININESS; + float roughness = DEFAULT_ROUGHNESS; + float metallic = DEFAULT_METALLIC; + vec3 emissive = DEFAULT_EMISSIVE; + float occlusion = DEFAULT_OCCLUSION; + float scattering = DEFAULT_SCATTERING; + float emissiveAmount = 0.0; TransformCamera cam = getTransformCamera(); - vec3 fragPosition = _positionES.xyz; - _fragColor0 = vec4(evalSkyboxGlobalColor( - cam._viewInverse, - 1.0, - DEFAULT_OCCLUSION, - fragPosition, +#if defined(PROCEDURAL_V1) + diffuse = getProceduralColor().rgb; + emissiveAmount = 1.0; + emissive = vec3(1.0); +#elif defined(PROCEDURAL_V2) + vec3 specular = DEFAULT_SPECULAR; + float shininess = DEFAULT_SHININESS; + emissiveAmount = getProceduralColors(diffuse, specular, shininess); + roughness = max(0.0, 1.0 - shininess / 128.0); + metallic = length(specular); + emissive = vec3(clamp(emissiveAmount, 0.0, 1.0)); +#elif defined(PROCEDURAL_V3) || defined(PROCEDURAL_V4) +#if defined(PROCEDURAL_V3) + ProceduralFragment proceduralData = ProceduralFragment( +#else + vec4 position = cam._viewInverse * _positionES; + ProceduralFragmentWithPosition proceduralData = ProceduralFragmentWithPosition( + position.xyz, +#endif normal, diffuse, - DEFAULT_FRESNEL, - length(specular), - max(0.0, 1.0 - shininess / 128.0)), - 1.0); + DEFAULT_SPECULAR, + emissive, + 1.0, + roughness, + metallic, + occlusion, + scattering + ); + +#if defined(PROCEDURAL_V3) + emissiveAmount = getProceduralFragment(proceduralData); +#else + emissiveAmount = getProceduralFragmentWithPosition(proceduralData); +#endif + normal = proceduralData.normal; + diffuse = proceduralData.diffuse; + roughness = proceduralData.roughness; + metallic = proceduralData.metallic; + emissive = proceduralData.emissive; + occlusion = proceduralData.occlusion; + scattering = proceduralData.scattering; + +#if defined(PROCEDURAL_V4) + position = vec4(proceduralData.position, 1.0); + vec4 posClip = cam._projection * (cam._view * position); + gl_FragDepth = 0.5 * (posClip.z / posClip.w + 1.0); +#endif + +#endif + + if (emissiveAmount > 0.0) { + _fragColor0 = vec4(diffuse, 1.0); + } else { + vec3 fragPosition = _positionES.xyz; + vec3 fresnel = getFresnelF0(metallic, diffuse); + _fragColor0 = vec4(evalSkyboxGlobalColor( + cam._viewInverse, + 1.0, + occlusion, + fragPosition, + normal, + diffuse, + fresnel, + metallic, + roughness), + 1.0); + } } diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 82c408f386..0fefff1c4c 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -17,6 +17,12 @@ if (NOT ANDROID) endif () -link_hifi_libraries(shared networking octree shaders gpu procedural graphics material-networking model-networking ktx recording avatars fbx hfm entities controllers animation audio physics image midi) -# ui includes gl, but link_hifi_libraries does not use transitive includes, so gl must be explicit +link_hifi_libraries(shared networking shaders material-networking model-networking recording avatars fbx entities controllers animation audio midi) include_hifi_library_headers(gl) +include_hifi_library_headers(hfm) +include_hifi_library_headers(gpu) +include_hifi_library_headers(ktx) +include_hifi_library_headers(image) +include_hifi_library_headers(graphics) +include_hifi_library_headers(octree) +include_hifi_library_headers(procedural) \ No newline at end of file diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index afff0a6b03..8335cb9adf 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -16,8 +16,6 @@ #include -#include - #include "ScriptEngineLogging.h" #include "ScriptEngine.h" diff --git a/libraries/script-engine/src/SceneScriptingInterface.cpp b/libraries/script-engine/src/SceneScriptingInterface.cpp index 7b36b815fb..90159f8ee6 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.cpp +++ b/libraries/script-engine/src/SceneScriptingInterface.cpp @@ -11,129 +11,6 @@ #include "SceneScriptingInterface.h" -#include - -float SceneScripting::Location::getLongitude() const { - return _skyStage->getOriginLongitude(); -} - -float SceneScripting::Location::getLatitude() const { - return _skyStage->getOriginLatitude(); -} - -float SceneScripting::Location::getAltitude() const { - return _skyStage->getOriginSurfaceAltitude(); -} - -void SceneScripting::Location::setLongitude(float longitude) { - _skyStage->setOriginLongitude(longitude); -} - -void SceneScripting::Location::setLatitude(float latitude) { - _skyStage->setOriginLatitude(latitude); -} - -void SceneScripting::Location::setAltitude(float altitude) { - _skyStage->setOriginSurfaceAltitude(altitude); -} - -void SceneScripting::Time::setHour(float hour) { - _skyStage->setDayTime(hour); -} - -float SceneScripting::Time::getHour() const { - return _skyStage->getDayTime(); -} - -void SceneScripting::Time::setDay(int day) { - _skyStage->setYearTime(day); -} - -int SceneScripting::Time::getDay() const { - return _skyStage->getYearTime(); -} - -glm::vec3 SceneScripting::KeyLight::getColor() const { - return _skyStage->getSunColor(); -} - -void SceneScripting::KeyLight::setColor(const glm::vec3& color) { - _skyStage->setSunColor(color); -} - -float SceneScripting::KeyLight::getIntensity() const { - return _skyStage->getSunIntensity(); -} - -void SceneScripting::KeyLight::setIntensity(float intensity) { - _skyStage->setSunIntensity(intensity); -} - -float SceneScripting::KeyLight::getAmbientIntensity() const { - return _skyStage->getSunAmbientIntensity(); -} - -void SceneScripting::KeyLight::setAmbientIntensity(float intensity) { - _skyStage->setSunAmbientIntensity(intensity); -} - -void SceneScripting::KeyLight::setAmbientSphere(const gpu::SHPointer& sphere) { - _skyStage->setSunAmbientSphere(sphere); -} - -void SceneScripting::KeyLight::setAmbientMap(const gpu::TexturePointer& map) { - _skyStage->setSunAmbientMap(map); -} - - -glm::vec3 SceneScripting::KeyLight::getDirection() const { - return _skyStage->getSunDirection(); -} - -void SceneScripting::KeyLight::setDirection(const glm::vec3& direction) { - _skyStage->setSunDirection(direction); -} - -void SceneScripting::Stage::setOrientation(const glm::quat& orientation) const { - _skyStage->setOriginOrientation(orientation); -} - -void SceneScripting::Stage::setLocation(float longitude, float latitude, float altitude) { - _skyStage->setOriginLocation(longitude, latitude, altitude); -} - -void SceneScripting::Stage::setSunModelEnable(bool isEnabled) { - _skyStage->setSunModelEnable(isEnabled); -} - -bool SceneScripting::Stage::isSunModelEnabled() const { - return _skyStage->isSunModelEnabled(); -} - -void SceneScripting::Stage::setBackgroundMode(const QString& mode) { - if (mode == QString("inherit")) { - _skyStage->setBackgroundMode(graphics::SunSkyStage::NO_BACKGROUND); - } else if (mode == QString("skybox")) { - _skyStage->setBackgroundMode(graphics::SunSkyStage::SKY_BOX); - } -} - -QString SceneScripting::Stage::getBackgroundMode() const { - switch (_skyStage->getBackgroundMode()) { - case graphics::SunSkyStage::NO_BACKGROUND: - return QString("inherit"); - case graphics::SunSkyStage::SKY_BOX: - return QString("skybox"); - default: - return QString("inherit"); - }; -} - -SceneScriptingInterface::SceneScriptingInterface() : _stage{ new SceneScripting::Stage{ _skyStage } } { - // Let's make sure the sunSkyStage is using a proceduralSkybox - _skyStage->setSkybox(graphics::SkyboxPointer(new ProceduralSkybox())); -} - void SceneScriptingInterface::setShouldRenderAvatars(bool shouldRenderAvatars) { if (shouldRenderAvatars != _shouldRenderAvatars) { _shouldRenderAvatars = shouldRenderAvatars; @@ -146,8 +23,4 @@ void SceneScriptingInterface::setShouldRenderEntities(bool shouldRenderEntities) _shouldRenderEntities = shouldRenderEntities; emit shouldRenderEntitiesChanged(_shouldRenderEntities); } -} - -graphics::SunSkyStagePointer SceneScriptingInterface::getSkyStage() const { - return _skyStage; -} +} \ No newline at end of file diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index fa67666676..ce205bdf3c 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -12,183 +12,8 @@ #ifndef hifi_SceneScriptingInterface_h #define hifi_SceneScriptingInterface_h -#include // QObject -#include // Dependency - -#include "graphics/Stage.h" - -// TODO: if QT moc ever supports nested classes, subclass these to the interface instead of namespacing -namespace SceneScripting { - - /**jsdoc - * Stage location. - * @typedef {object} Stage.Location - * @property {number} longitude - Longitude. - * @property {number} latitude - Latitude. - * @property {number} altitude - Altitude. - */ - class Location : public QObject { - Q_OBJECT - - public: - Location(graphics::SunSkyStagePointer skyStage) : _skyStage{ skyStage } {} - - Q_PROPERTY(float longitude READ getLongitude WRITE setLongitude) - Q_PROPERTY(float latitude READ getLatitude WRITE setLatitude) - Q_PROPERTY(float altitude READ getAltitude WRITE setAltitude) - - float getLongitude() const; - float getLatitude() const; - float getAltitude() const; - void setLongitude(float longitude); - void setLatitude(float latitude); - void setAltitude(float altitude); - - protected: - graphics::SunSkyStagePointer _skyStage; - }; - using LocationPointer = std::unique_ptr; - - /**jsdoc - * Stage time. - * @typedef {object} Stage.Time - * @property {number} hour - Hour. - * @property {number} day - Day. - */ - class Time : public QObject { - Q_OBJECT - - public: - Time(graphics::SunSkyStagePointer skyStage) : _skyStage{ skyStage } {} - - Q_PROPERTY(float hour READ getHour WRITE setHour) - Q_PROPERTY(int day READ getDay WRITE setDay) - - float getHour() const; - void setHour(float hour); - int getDay() const; - void setDay(int day); - - protected: - graphics::SunSkyStagePointer _skyStage; - }; - using TimePointer = std::unique_ptr