diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 022c0262e0..627c42ffa8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -313,7 +313,6 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptrremoveFromScene(scene, pendingChanges); } - } void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) { diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 49a8012cd9..f16173b79e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -55,7 +55,7 @@ AvatarManager::AvatarManager(QObject* parent) : _avatarFades() { // register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar qRegisterMetaType >("NodeWeakPointer"); - _myAvatar = std::shared_ptr(new MyAvatar()); + _myAvatar = std::make_shared(); } void AvatarManager::init() { @@ -97,9 +97,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { // simulate avatars AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { - Avatar* avatar = reinterpret_cast(avatarIterator.value().get()); + auto avatar = std::dynamic_pointer_cast(avatarIterator.value()); - if (avatar == _myAvatar.get() || !avatar->isInitialized()) { + if (avatar == _myAvatar || !avatar->isInitialized()) { // DO NOT update _myAvatar! Its update has already been done earlier in the main loop. // DO NOT update or fade out uninitialized Avatars ++avatarIterator; @@ -121,26 +121,30 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { const float SHRINK_RATE = 0.9f; const float MIN_FADE_SCALE = 0.001f; - + + render::ScenePointer scene = Application::getInstance()->getMain3DScene(); + render::PendingChanges pendingChanges; while (fadingIterator != _avatarFades.end()) { - Avatar* avatar = static_cast(fadingIterator->get()); + auto avatar = std::static_pointer_cast(*fadingIterator); avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true); if (avatar->getTargetScale() < MIN_FADE_SCALE) { + avatar->removeFromScene(*fadingIterator, scene, pendingChanges); fadingIterator = _avatarFades.erase(fadingIterator); } else { avatar->simulate(deltaTime); ++fadingIterator; } } + scene->enqueuePendingChanges(pendingChanges); } AvatarSharedPointer AvatarManager::newSharedAvatar() { - return AvatarSharedPointer(new Avatar()); + return AvatarSharedPointer(std::make_shared()); } // virtual AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { - std::shared_ptr avatar = std::dynamic_pointer_cast(AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer)); + auto avatar = std::dynamic_pointer_cast(AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer)); render::ScenePointer scene = Application::getInstance()->getMain3DScene(); render::PendingChanges pendingChanges; avatar->addToScene(avatar, scene, pendingChanges); @@ -171,10 +175,6 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { _avatarFades.push_back(avatarIterator.value()); _avatarHash.erase(avatarIterator); } - render::ScenePointer scene = Application::getInstance()->getMain3DScene(); - render::PendingChanges pendingChanges; - avatar->removeFromScene(avatar, scene, pendingChanges); - scene->enqueuePendingChanges(pendingChanges); } } @@ -182,12 +182,12 @@ void AvatarManager::clearOtherAvatars() { // clear any avatars that came from an avatar-mixer AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { - Avatar* avatar = reinterpret_cast(avatarIterator.value().get()); - if (avatar == _myAvatar.get() || !avatar->isInitialized()) { + auto avatar = std::static_pointer_cast(avatarIterator.value()); + if (avatar == _myAvatar || !avatar->isInitialized()) { // don't remove myAvatar or uninitialized avatars from the list ++avatarIterator; } else { - removeAvatarMotionState(avatar); + removeAvatarMotionState(avatar.get()); _avatarFades.push_back(avatarIterator.value()); avatarIterator = _avatarHash.erase(avatarIterator); } @@ -250,7 +250,7 @@ void AvatarManager::handleCollisionEvents(CollisionEvents& collisionEvents) { void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) { AvatarHash::iterator avatarItr = _avatarHash.find(id); if (avatarItr != _avatarHash.end()) { - Avatar* avatar = static_cast(avatarItr.value().get()); + auto avatar = std::static_pointer_cast(avatarItr.value()); AvatarMotionState* motionState = avatar->_motionState; if (motionState) { motionState->addDirtyFlags(EntityItem::DIRTY_SHAPE); @@ -259,7 +259,7 @@ void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) { avatar->computeShapeInfo(shapeInfo); btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); if (shape) { - AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); + AvatarMotionState* motionState = new AvatarMotionState(avatar.get(), shape); avatar->_motionState = motionState; _motionStatesToAdd.insert(motionState); _avatarMotionStates.insert(motionState); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 76108730e8..de8f53c503 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1902,8 +1902,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, } else { material._material->setDiffuse(material.diffuse); } - material._material->setSpecular(material.specular); - material._material->setShininess(material.shininess); + material._material->setMetallic(glm::length(material.specular)); + material._material->setGloss(material.shininess); if (material.opacity <= 0.0f) { material._material->setOpacity(1.0f); diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index f0d3ecf517..b7fea218d8 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -134,8 +134,8 @@ void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID) { meshPart._material = model::MaterialPointer(new model::Material()); meshPart._material->setDiffuse(glm::vec3(1.0, 1.0, 1.0)); meshPart._material->setOpacity(1.0); - meshPart._material->setSpecular(glm::vec3(1.0, 1.0, 1.0)); - meshPart._material->setShininess(96.0); + meshPart._material->setMetallic(0.0); + meshPart._material->setGloss(96.0); meshPart._material->setEmissive(glm::vec3(0.0, 0.0, 0.0)); } @@ -481,8 +481,8 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q meshPart.specularTexture.filename = material->specularTextureFilename; // ... and some things are set in the underlying material. meshPart._material->setDiffuse(material->diffuseColor); - meshPart._material->setSpecular(material->specularColor); - meshPart._material->setShininess(material->shininess); + meshPart._material->setMetallic(glm::length(material->specularColor)); + meshPart._material->setGloss(material->shininess); meshPart._material->setOpacity(material->opacity); } // qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count(); @@ -566,10 +566,10 @@ void fbxDebugDump(const FBXGeometry& fbxgeo) { qCDebug(modelformat) << " quadIndices.count() =" << meshPart.quadIndices.count(); qCDebug(modelformat) << " triangleIndices.count() =" << meshPart.triangleIndices.count(); qCDebug(modelformat) << " diffuseColor =" << meshPart.diffuseColor << "mat =" << meshPart._material->getDiffuse(); - qCDebug(modelformat) << " specularColor =" << meshPart.specularColor << "mat =" << meshPart._material->getSpecular(); + qCDebug(modelformat) << " specularColor =" << meshPart.specularColor << "mat =" << meshPart._material->getMetallic(); qCDebug(modelformat) << " emissiveColor =" << meshPart.emissiveColor << "mat =" << meshPart._material->getEmissive(); qCDebug(modelformat) << " emissiveParams =" << meshPart.emissiveParams; - qCDebug(modelformat) << " shininess =" << meshPart.shininess << "mat =" << meshPart._material->getShininess(); + qCDebug(modelformat) << " gloss =" << meshPart.shininess << "mat =" << meshPart._material->getGloss(); qCDebug(modelformat) << " opacity =" << meshPart.opacity << "mat =" << meshPart._material->getOpacity(); qCDebug(modelformat) << " materialID =" << meshPart.materialID; qCDebug(modelformat) << " diffuse texture =" << meshPart.diffuseTexture.filename; diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 9036f0f6db..d5c3635816 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -437,6 +437,8 @@ public: explicit operator bool() const { return bool(_texture); } bool operator !() const { return (!_texture); } + + bool isValid() const { return bool(_texture); } }; typedef std::vector TextureViews; diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 55572a5122..a3448889b0 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -14,7 +14,7 @@ using namespace model; using namespace gpu; Material::Material() : - _flags(0), + _key(0), _schemaBuffer(), _textureMap() { @@ -26,13 +26,13 @@ Material::Material() : } Material::Material(const Material& material) : - _flags(material._flags), + _key(material._key), _schemaBuffer(material._schemaBuffer), _textureMap(material._textureMap) { } Material& Material::operator= (const Material& material) { - _flags = (material._flags); + _key = (material._key); _schemaBuffer = (material._schemaBuffer); _textureMap = (material._textureMap); @@ -43,52 +43,32 @@ Material::~Material() { } void Material::setDiffuse(const Color& diffuse) { - if (glm::any(glm::greaterThan(diffuse, Color(0.0f)))) { - _flags.set(DIFFUSE_BIT); - } else { - _flags.reset(DIFFUSE_BIT); - } + _key.setDiffuse(glm::any(glm::greaterThan(diffuse, Color(0.0f)))); _schemaBuffer.edit()._diffuse = diffuse; } -void Material::setSpecular(const Color& specular) { - if (glm::any(glm::greaterThan(specular, Color(0.0f)))) { - _flags.set(SPECULAR_BIT); - } else { - _flags.reset(SPECULAR_BIT); - } - _schemaBuffer.edit()._specular = specular; +void Material::setMetallic(float metallic) { + _key.setMetallic(metallic > 0.0f); + _schemaBuffer.edit()._metallic = glm::vec3(metallic); } void Material::setEmissive(const Color& emissive) { - if (glm::any(glm::greaterThan(emissive, Color(0.0f)))) { - _flags.set(EMISSIVE_BIT); - } else { - _flags.reset(EMISSIVE_BIT); - } + _key.setEmissive(glm::any(glm::greaterThan(emissive, Color(0.0f)))); _schemaBuffer.edit()._emissive = emissive; } -void Material::setShininess(float shininess) { - if (shininess > 0.0f) { - _flags.set(SHININESS_BIT); - } else { - _flags.reset(SHININESS_BIT); - } - _schemaBuffer.edit()._shininess = shininess; +void Material::setGloss(float gloss) { + _key.setGloss((gloss > 0.0f)); + _schemaBuffer.edit()._gloss = gloss; } void Material::setOpacity(float opacity) { - if (opacity >= 1.0f) { - _flags.reset(TRANSPARENT_BIT); - } else { - _flags.set(TRANSPARENT_BIT); - } + _key.setTransparent((opacity < 1.0f)); _schemaBuffer.edit()._opacity = opacity; } void Material::setTextureView(MapChannel channel, const gpu::TextureView& view) { - _flags.set(DIFFUSE_MAP_BIT + channel); + _key.setMapChannel(channel, (view.isValid())); _textureMap[channel] = view; } diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index ea0ab808e9..392fd918a1 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -23,6 +23,177 @@ namespace model { +// Material Key is a coarse trait description of a material used to classify the materials +class MaterialKey { +public: + enum FlagBit { + EMISSIVE_VAL_BIT = 0, + DIFFUSE_VAL_BIT, + METALLIC_VAL_BIT, + GLOSS_VAL_BIT, + TRANSPARENT_VAL_BIT, + + EMISSIVE_MAP_BIT, + DIFFUSE_MAP_BIT, + METALLIC_MAP_BIT, + GLOSS_MAP_BIT, + TRANSPARENT_MAP_BIT, + NORMAL_MAP_BIT, + + NUM_FLAGS, + }; + typedef std::bitset Flags; + + enum MapChannel { + EMISSIVE_MAP = 0, + DIFFUSE_MAP, + METALLIC_MAP, + GLOSS_MAP, + TRANSPARENT_MAP, + NORMAL_MAP, + + NUM_MAP_CHANNELS, + }; + + // The signature is the Flags + Flags _flags; + + MaterialKey() : _flags(0) {} + MaterialKey(const Flags& flags) : _flags(flags) {} + + class Builder { + Flags _flags{ 0 }; + public: + Builder() {} + + MaterialKey build() const { return MaterialKey(_flags); } + + Builder& withEmissive() { _flags.set(EMISSIVE_VAL_BIT); return (*this); } + Builder& withDiffuse() { _flags.set(DIFFUSE_VAL_BIT); return (*this); } + Builder& withMetallic() { _flags.set(METALLIC_VAL_BIT); return (*this); } + Builder& withGloss() { _flags.set(GLOSS_VAL_BIT); return (*this); } + Builder& withTransparent() { _flags.set(TRANSPARENT_VAL_BIT); return (*this); } + + Builder& withEmissiveMap() { _flags.set(EMISSIVE_MAP_BIT); return (*this); } + Builder& withDiffuseMap() { _flags.set(DIFFUSE_MAP_BIT); return (*this); } + Builder& withMetallicMap() { _flags.set(METALLIC_MAP_BIT); return (*this); } + Builder& withGlossMap() { _flags.set(GLOSS_MAP_BIT); return (*this); } + Builder& withTransparentMap() { _flags.set(TRANSPARENT_MAP_BIT); return (*this); } + + Builder& withNormalMap() { _flags.set(NORMAL_MAP_BIT); return (*this); } + + // Convenient standard keys that we will keep on using all over the place + static MaterialKey opaqueDiffuse() { return Builder().withDiffuse().build(); } + }; + + void setEmissive(bool value) { _flags.set(EMISSIVE_VAL_BIT, value); } + bool isEmissive() const { return _flags[EMISSIVE_VAL_BIT]; } + + void setEmissiveMap(bool value) { _flags.set(EMISSIVE_MAP_BIT, value); } + bool isEmissiveMap() const { return _flags[EMISSIVE_MAP_BIT]; } + + void setDiffuse(bool value) { _flags.set(DIFFUSE_VAL_BIT, value); } + bool isDiffuse() const { return _flags[DIFFUSE_VAL_BIT]; } + + void setDiffuseMap(bool value) { _flags.set(DIFFUSE_MAP_BIT, value); } + bool isDiffuseMap() const { return _flags[DIFFUSE_MAP_BIT]; } + + void setMetallic(bool value) { _flags.set(METALLIC_VAL_BIT, value); } + bool isMetallic() const { return _flags[METALLIC_VAL_BIT]; } + + void setMetallicMap(bool value) { _flags.set(METALLIC_MAP_BIT, value); } + bool isMetallicMap() const { return _flags[METALLIC_MAP_BIT]; } + + void setGloss(bool value) { _flags.set(GLOSS_VAL_BIT, value); } + bool isGloss() const { return _flags[GLOSS_VAL_BIT]; } + + void setGlossMap(bool value) { _flags.set(GLOSS_MAP_BIT, value); } + bool isGlossMap() const { return _flags[GLOSS_MAP_BIT]; } + + void setTransparent(bool value) { _flags.set(TRANSPARENT_VAL_BIT, value); } + bool isTransparent() const { return _flags[TRANSPARENT_VAL_BIT]; } + bool isOpaque() const { return !_flags[TRANSPARENT_VAL_BIT]; } + + void setTransparentMap(bool value) { _flags.set(TRANSPARENT_MAP_BIT, value); } + bool isTransparentMap() const { return _flags[TRANSPARENT_MAP_BIT]; } + + void setNormalMap(bool value) { _flags.set(NORMAL_MAP_BIT, value); } + bool isNormalMap() const { return _flags[NORMAL_MAP_BIT]; } + + void setMapChannel(MapChannel channel, bool value) { _flags.set(EMISSIVE_MAP_BIT + channel, value); } + bool isMapChannel(MapChannel channel) const { return _flags[EMISSIVE_MAP_BIT + channel]; } + +}; + + +class MaterialFilter { +public: + MaterialKey::Flags _value{ 0 }; + MaterialKey::Flags _mask{ 0 }; + + + MaterialFilter(const MaterialKey::Flags& value = MaterialKey::Flags(0), const MaterialKey::Flags& mask = MaterialKey::Flags(0)) : _value(value), _mask(mask) {} + + class Builder { + MaterialKey::Flags _value{ 0 }; + MaterialKey::Flags _mask{ 0 }; + public: + Builder() {} + + MaterialFilter build() const { return MaterialFilter(_value, _mask); } + + Builder& withoutEmissive() { _value.reset(MaterialKey::EMISSIVE_VAL_BIT); _mask.set(MaterialKey::EMISSIVE_VAL_BIT); return (*this); } + Builder& withEmissive() { _value.set(MaterialKey::EMISSIVE_VAL_BIT); _mask.set(MaterialKey::EMISSIVE_VAL_BIT); return (*this); } + + Builder& withoutEmissiveMap() { _value.reset(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT); return (*this); } + Builder& withEmissiveMap() { _value.set(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT); return (*this); } + + Builder& withoutDiffuse() { _value.reset(MaterialKey::DIFFUSE_VAL_BIT); _mask.set(MaterialKey::DIFFUSE_VAL_BIT); return (*this); } + Builder& withDiffuse() { _value.set(MaterialKey::DIFFUSE_VAL_BIT); _mask.set(MaterialKey::DIFFUSE_VAL_BIT); return (*this); } + + Builder& withoutDiffuseMap() { _value.reset(MaterialKey::DIFFUSE_MAP_BIT); _mask.set(MaterialKey::DIFFUSE_MAP_BIT); return (*this); } + Builder& withDiffuseMap() { _value.set(MaterialKey::DIFFUSE_MAP_BIT); _mask.set(MaterialKey::DIFFUSE_MAP_BIT); return (*this); } + + Builder& withoutMetallic() { _value.reset(MaterialKey::METALLIC_VAL_BIT); _mask.set(MaterialKey::METALLIC_VAL_BIT); return (*this); } + Builder& withMetallic() { _value.set(MaterialKey::METALLIC_VAL_BIT); _mask.set(MaterialKey::METALLIC_VAL_BIT); return (*this); } + + Builder& withoutMetallicMap() { _value.reset(MaterialKey::METALLIC_MAP_BIT); _mask.set(MaterialKey::METALLIC_MAP_BIT); return (*this); } + Builder& withMetallicMap() { _value.set(MaterialKey::METALLIC_MAP_BIT); _mask.set(MaterialKey::METALLIC_MAP_BIT); return (*this); } + + Builder& withoutGloss() { _value.reset(MaterialKey::GLOSS_VAL_BIT); _mask.set(MaterialKey::GLOSS_VAL_BIT); return (*this); } + Builder& withGloss() { _value.set(MaterialKey::GLOSS_VAL_BIT); _mask.set(MaterialKey::GLOSS_VAL_BIT); return (*this); } + + Builder& withoutGlossMap() { _value.reset(MaterialKey::GLOSS_MAP_BIT); _mask.set(MaterialKey::GLOSS_MAP_BIT); return (*this); } + Builder& withGlossMap() { _value.set(MaterialKey::GLOSS_MAP_BIT); _mask.set(MaterialKey::GLOSS_MAP_BIT); return (*this); } + + Builder& withoutTransparent() { _value.reset(MaterialKey::TRANSPARENT_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_VAL_BIT); return (*this); } + Builder& withTransparent() { _value.set(MaterialKey::TRANSPARENT_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_VAL_BIT); return (*this); } + + Builder& withoutTransparentMap() { _value.reset(MaterialKey::TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::TRANSPARENT_MAP_BIT); return (*this); } + Builder& withTransparentMap() { _value.set(MaterialKey::TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::TRANSPARENT_MAP_BIT); return (*this); } + + Builder& withoutNormalMap() { _value.reset(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT); return (*this); } + Builder& withNormalMap() { _value.set(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT); return (*this); } + + // Convenient standard keys that we will keep on using all over the place + static MaterialFilter opaqueDiffuse() { return Builder().withDiffuse().withoutTransparent().build(); } + }; + + // Item Filter operator testing if a key pass the filter + bool test(const MaterialKey& key) const { return (key._flags & _mask) == (_value & _mask); } + + class Less { + public: + bool operator() (const MaterialFilter& left, const MaterialFilter& right) const { + if (left._value.to_ulong() == right._value.to_ulong()) { + return left._mask.to_ulong() < right._mask.to_ulong(); + } else { + return left._value.to_ulong() < right._value.to_ulong(); + } + } + }; +}; + class Material { public: typedef gpu::BufferView UniformBufferView; @@ -30,52 +201,27 @@ public: typedef glm::vec3 Color; - enum MapChannel { - DIFFUSE_MAP = 0, - SPECULAR_MAP, - SHININESS_MAP, - EMISSIVE_MAP, - OPACITY_MAP, - NORMAL_MAP, - - NUM_MAPS, - }; + typedef MaterialKey::MapChannel MapChannel; typedef std::map TextureMap; - typedef std::bitset MapFlags; - - enum FlagBit { - DIFFUSE_BIT = 0, - SPECULAR_BIT, - SHININESS_BIT, - EMISSIVE_BIT, - TRANSPARENT_BIT, - - DIFFUSE_MAP_BIT, - SPECULAR_MAP_BIT, - SHININESS_MAP_BIT, - EMISSIVE_MAP_BIT, - OPACITY_MAP_BIT, - NORMAL_MAP_BIT, - - NUM_FLAGS, - }; - typedef std::bitset Flags; + typedef std::bitset MapFlags; Material(); Material(const Material& material); Material& operator= (const Material& material); virtual ~Material(); + const MaterialKey& getKey() const { return _key; } + const Color& getEmissive() const { return _schemaBuffer.get()._emissive; } const Color& getDiffuse() const { return _schemaBuffer.get()._diffuse; } - const Color& getSpecular() const { return _schemaBuffer.get()._specular; } - float getShininess() const { return _schemaBuffer.get()._shininess; } + float getMetallic() const { return _schemaBuffer.get()._metallic.x; } + float getGloss() const { return _schemaBuffer.get()._gloss; } float getOpacity() const { return _schemaBuffer.get()._opacity; } - void setDiffuse(const Color& diffuse); - void setSpecular(const Color& specular); void setEmissive(const Color& emissive); - void setShininess(float shininess); + void setDiffuse(const Color& diffuse); + void setMetallic(float metallic); + void setGloss(float gloss); void setOpacity(float opacity); // Schema to access the attribute values of the material @@ -84,8 +230,8 @@ public: Color _diffuse{0.5f}; float _opacity{1.f}; - Color _specular{0.03f}; - float _shininess{0.1f}; + Color _metallic{0.03f}; + float _gloss{0.1f}; Color _emissive{0.0f}; float _spare0{0.0f}; glm::vec4 _spareVec4{0.0f}; // for alignment beauty, Material size == Mat4x4 @@ -100,7 +246,7 @@ public: protected: - Flags _flags; + MaterialKey _key; UniformBufferView _schemaBuffer; TextureMap _textureMap; diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index a34a3be3fd..933c737b83 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -44,70 +44,73 @@ void Skybox::setCubemap(const gpu::TexturePointer& cubemap) { void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) { - if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) { + if (skybox.getCubemap()) { + if (skybox.getCubemap()->isDefined()) { - static gpu::PipelinePointer thePipeline; - static gpu::BufferPointer theBuffer; - static gpu::Stream::FormatPointer theFormat; - static gpu::BufferPointer theConstants; - int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader - if (!thePipeline) { - auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert))); - auto skyFS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(Skybox_frag))); - auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyVS, skyFS)); + static gpu::PipelinePointer thePipeline; + static gpu::BufferPointer theBuffer; + static gpu::Stream::FormatPointer theFormat; + static gpu::BufferPointer theConstants; + int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader + if (!thePipeline) { + auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert))); + auto skyFS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(Skybox_frag))); + auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyVS, skyFS)); - gpu::Shader::BindingSet bindings; - bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), 0)); - if (!gpu::Shader::makeProgram(*skyShader, bindings)) { + gpu::Shader::BindingSet bindings; + bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), 0)); + if (!gpu::Shader::makeProgram(*skyShader, bindings)) { - } + } - SKYBOX_CONSTANTS_SLOT = skyShader->getBuffers().findLocation("skyboxBuffer"); - if (SKYBOX_CONSTANTS_SLOT == gpu::Shader::INVALID_LOCATION) { - SKYBOX_CONSTANTS_SLOT = skyShader->getUniforms().findLocation("skyboxBuffer"); - } + SKYBOX_CONSTANTS_SLOT = skyShader->getBuffers().findLocation("skyboxBuffer"); + if (SKYBOX_CONSTANTS_SLOT == gpu::Shader::INVALID_LOCATION) { + SKYBOX_CONSTANTS_SLOT = skyShader->getUniforms().findLocation("skyboxBuffer"); + } - auto skyState = gpu::StatePointer(new gpu::State()); + auto skyState = gpu::StatePointer(new gpu::State()); - thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); + thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); - const float CLIP = 1.0; - const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}}; - theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices)); + const float CLIP = 1.0; + const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}}; + theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices)); - theFormat.reset(new gpu::Stream::Format()); - theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ)); + theFormat.reset(new gpu::Stream::Format()); + theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ)); - auto color = glm::vec4(1.0f); - theConstants.reset(new gpu::Buffer(sizeof(color), (const gpu::Byte*) &color)); + auto color = glm::vec4(1.0f); + theConstants.reset(new gpu::Buffer(sizeof(color), (const gpu::Byte*) &color)); + } + + glm::mat4 projMat; + viewFrustum.evalProjectionMatrix(projMat); + + Transform viewTransform; + viewFrustum.evalViewTransform(viewTransform); + + if (glm::all(glm::equal(skybox.getColor(), glm::vec3(0.0f)))) { + auto color = glm::vec4(1.0f); + theConstants->setSubData(0, sizeof(color), (const gpu::Byte*) &color); + } else { + theConstants->setSubData(0, sizeof(Color), (const gpu::Byte*) &skybox.getColor()); + } + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewTransform); + batch.setModelTransform(Transform()); // only for Mac + batch.setPipeline(thePipeline); + batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8); + batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize()); + batch.setInputFormat(theFormat); + batch.setUniformTexture(0, skybox.getCubemap()); + batch.draw(gpu::TRIANGLE_STRIP, 4); } - glm::mat4 projMat; - viewFrustum.evalProjectionMatrix(projMat); - - Transform viewTransform; - viewFrustum.evalViewTransform(viewTransform); - - if (glm::all(glm::equal(skybox.getColor(), glm::vec3(0.0f)))) { - auto color = glm::vec4(1.0f); - theConstants->setSubData(0, sizeof(color), (const gpu::Byte*) &color); - } else { - theConstants->setSubData(0, sizeof(Color), (const gpu::Byte*) &skybox.getColor()); - } - - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewTransform); - batch.setModelTransform(Transform()); // only for Mac - batch.setPipeline(thePipeline); - batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8); - batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize()); - batch.setInputFormat(theFormat); - batch.setUniformTexture(0, skybox.getCubemap()); - batch.draw(gpu::TRIANGLE_STRIP, 4); } else { // skybox has no cubemap, just clear the color buffer auto color = skybox.getColor(); - batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 1.0f), 0.f, 0); + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.f, 0); } } diff --git a/libraries/model/src/model/TextureStorage.h b/libraries/model/src/model/TextureStorage.h index ebc027298b..a6752d21b2 100755 --- a/libraries/model/src/model/TextureStorage.h +++ b/libraries/model/src/model/TextureStorage.h @@ -24,7 +24,7 @@ typedef glm::vec3 Color; class TextureUsage { public: gpu::Texture::Type _type{ gpu::Texture::TEX_2D }; - Material::MapFlags _materialUsage{ Material::DIFFUSE_MAP }; + Material::MapFlags _materialUsage{ MaterialKey::DIFFUSE_MAP }; int _environmentUsage = 0; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3026efceb2..3cea5c9777 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -875,6 +875,9 @@ namespace render { return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, false); } } + /* template <> const model::MaterialKey& shapeGetMaterialKey(const OpaqueMeshPart::Pointer& payload) { + return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex); + }*/ } void Model::setVisibleInScene(bool newValue, std::shared_ptr scene) { diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index f9e78c69bb..777d9466a5 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -44,7 +44,7 @@ template <> void render::jobRun(const ResolveDeferred& job, const SceneContextPo RenderDeferredTask::RenderDeferredTask() : Task() { _jobs.push_back(Job(PrepareDeferred())); _jobs.push_back(Job(DrawBackground())); - _jobs.push_back(Job(DrawOpaque())); + _jobs.push_back(Job(DrawOpaqueDeferred())); _jobs.push_back(Job(DrawLight())); _jobs.push_back(Job(ResetGLState())); _jobs.push_back(Job(RenderDeferred())); @@ -78,6 +78,84 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend +template <> void render::jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { + PerformanceTimer perfTimer("DrawOpaqueDeferred"); + assert(renderContext->args); + assert(renderContext->args->_viewFrustum); + + // render opaques + auto& scene = sceneContext->_scene; + auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape()); + auto& renderDetails = renderContext->args->_details; + + ItemIDsBounds inItems; + inItems.reserve(items.size()); + for (auto id : items) { + inItems.emplace_back(ItemIDAndBounds(id)); + } + ItemIDsBounds& renderedItems = inItems; + + renderContext->_numFeedOpaqueItems = renderedItems.size(); + + ItemIDsBounds culledItems; + culledItems.reserve(inItems.size()); + if (renderContext->_cullOpaque) { + renderDetails.pointTo(RenderDetails::OPAQUE_ITEM); + cullItems(sceneContext, renderContext, renderedItems, culledItems); + renderDetails.pointTo(RenderDetails::OTHER_ITEM); + renderedItems = culledItems; + } + + renderContext->_numDrawnOpaqueItems = renderedItems.size(); + + + ItemIDsBounds sortedItems; + sortedItems.reserve(culledItems.size()); + if (renderContext->_sortOpaque) { + depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items! + renderedItems = sortedItems; + } + + // ItemIDsBounds sortedItems; + /* ItemMaterialBucketMap stateSortedItems; + stateSortedItems.allocateStandardMaterialBuckets(); + if (true) { + for (auto& itemIDAndBound : renderedItems) { + stateSortedItems.insert(itemIDAndBound.id, scene->getItem(itemIDAndBound.id).getMaterialKey()); + } + } +*/ + + if (renderContext->_renderOpaque) { + RenderArgs* args = renderContext->args; + gpu::Batch batch; + args->_batch = &batch; + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + + renderContext->args->_renderMode = RenderArgs::NORMAL_RENDER_MODE; + { + GLenum buffers[3]; + int bufferCount = 0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT0; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT1; + buffers[bufferCount++] = GL_COLOR_ATTACHMENT2; + batch._glDrawBuffers(bufferCount, buffers); + } + + renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems); + + args->_context->render((*args->_batch)); + args->_batch = nullptr; + } +} + + template <> void render::jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { PerformanceTimer perfTimer("DrawTransparentDeferred"); assert(renderContext->args); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 17971dbfac..e2cac53c0d 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -35,6 +35,14 @@ namespace render { template <> void jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); } + +class DrawOpaqueDeferred { +public: +}; +namespace render { +template <> void jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext); +} + class DrawTransparentDeferred { public: }; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 41e36de37b..bfc888ea8a 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -445,3 +445,18 @@ template <> void render::jobRun(const DrawBackground& job, const SceneContextPoi // Force the context sync args->_context->syncCache(); } + + + +void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) { + // Insert the itemID in every bucket where it filters true + for (auto& bucket : (*this)) { + if (bucket.first.test(key)) { + bucket.second.push_back(id); + } + } +} + +void ItemMaterialBucketMap::allocateStandardMaterialBuckets() { + (*this)[model::MaterialFilter::Builder::opaqueDiffuse()]; +} diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 687287cd56..1f260583f2 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -62,6 +62,10 @@ void depthSortItems(const SceneContextPointer& sceneContext, const RenderContext void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1); + +void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems); + + class DrawOpaque { public: }; @@ -101,6 +105,20 @@ public: }; + +// A map of ItemIDs allowing to create bucket lists of SHAPE type items which are filtered by their +// Material +class ItemMaterialBucketMap : public std::map { +public: + + ItemMaterialBucketMap() {} + + void insert(const ItemID& id, const model::MaterialKey& key); + + // standard builders allocating the main buckets + void allocateStandardMaterialBuckets(); +}; + } #endif // hifi_render_Task_h diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 054fbeb602..8cb29609ba 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -24,6 +24,8 @@ #include #include +#include "model/Material.h" + namespace render { class Context; @@ -216,6 +218,8 @@ public: virtual void update(const UpdateFunctorPointer& functor) = 0; + virtual const model::MaterialKey getMaterialKey() const = 0; + ~PayloadInterface() {} protected: }; @@ -240,6 +244,9 @@ public: void render(RenderArgs* args) { _payload->render(args); } void update(const UpdateFunctorPointer& updateFunctor) { _payload->update(updateFunctor); } + // Shape Type Interface + const model::MaterialKey& getMaterialKey() const { return _payload->getMaterialKey(); } + protected: PayloadPointer _payload; ItemKey _key; @@ -275,16 +282,23 @@ template const ItemKey payloadGetKey(const std::shared_ptr& payload template const Item::Bound payloadGetBound(const std::shared_ptr& payloadData) { return Item::Bound(); } template void payloadRender(const std::shared_ptr& payloadData, RenderArgs* args) { } +// Shape type interface +template const model::MaterialKey shapeGetMaterialKey(const std::shared_ptr& payloadData) { return model::MaterialKey(); } + template class Payload : public Item::PayloadInterface { public: typedef std::shared_ptr DataPointer; typedef UpdateFunctor Updater; + virtual void update(const UpdateFunctorPointer& functor) { static_cast(functor.get())->_func((*_data)); } + + // Payload general interface virtual const ItemKey getKey() const { return payloadGetKey(_data); } virtual const Item::Bound getBound() const { return payloadGetBound(_data); } - virtual void render(RenderArgs* args) { payloadRender(_data, args); } - - virtual void update(const UpdateFunctorPointer& functor) { static_cast(functor.get())->_func((*_data)); } + virtual void render(RenderArgs* args) { payloadRender(_data, args); } + + // Shape Type interface + virtual const model::MaterialKey getMaterialKey() const { return shapeGetMaterialKey(_data); } Payload(const DataPointer& data) : _data(data) {} protected: