mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 08:21:24 +02:00
Merge pull request #1076 from HifiExperiments/materials
Material improvements
This commit is contained in:
commit
f062d64223
17 changed files with 524 additions and 321 deletions
|
@ -29,6 +29,8 @@
|
||||||
#include "RenderableZoneEntityItem.h"
|
#include "RenderableZoneEntityItem.h"
|
||||||
#include "RenderableMaterialEntityItem.h"
|
#include "RenderableMaterialEntityItem.h"
|
||||||
|
|
||||||
|
#include "RenderPipelines.h"
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
|
||||||
|
@ -149,10 +151,11 @@ Item::Bound EntityRenderer::getBound(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeKey EntityRenderer::getShapeKey() {
|
ShapeKey EntityRenderer::getShapeKey() {
|
||||||
|
ShapeKey::Builder builder = ShapeKey::Builder().withOwnPipeline();
|
||||||
if (_primitiveMode == PrimitiveMode::LINES) {
|
if (_primitiveMode == PrimitiveMode::LINES) {
|
||||||
return ShapeKey::Builder().withOwnPipeline().withWireframe();
|
builder.withWireframe();
|
||||||
}
|
}
|
||||||
return ShapeKey::Builder().withOwnPipeline();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
render::hifi::Tag EntityRenderer::getTagMask() const {
|
render::hifi::Tag EntityRenderer::getTagMask() const {
|
||||||
|
@ -365,6 +368,7 @@ bool EntityRenderer::needsRenderUpdate() const {
|
||||||
if (_prevIsTransparent != isTransparent()) {
|
if (_prevIsTransparent != isTransparent()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return needsRenderUpdateFromEntity(_entity);
|
return needsRenderUpdateFromEntity(_entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,6 +495,176 @@ void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const st
|
||||||
emit requestRenderUpdate();
|
emit requestRenderUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EntityRenderer::Pipeline EntityRenderer::getPipelineType(const graphics::MultiMaterial& materials) {
|
||||||
|
if (materials.top().material && materials.top().material->isProcedural() && materials.top().material->isReady()) {
|
||||||
|
return Pipeline::PROCEDURAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
graphics::MaterialKey drawMaterialKey = materials.getMaterialKey();
|
||||||
|
if (drawMaterialKey.isEmissive() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
|
||||||
|
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 Pipeline::MATERIAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Pipeline::SIMPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityRenderer::needsRenderUpdateFromMaterials() const {
|
||||||
|
MaterialMap::const_iterator materials;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
materials = _materials.find("0");
|
||||||
|
|
||||||
|
if (materials == _materials.cend()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (materials->second.shouldUpdate()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (materials->second.top().material && materials->second.top().material->isProcedural() && materials->second.top().material->isReady()) {
|
||||||
|
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials->second.top().material);
|
||||||
|
if (procedural->isFading()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityRenderer::updateMaterials(bool baseMaterialChanged) {
|
||||||
|
MaterialMap::iterator materials;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
materials = _materials.find("0");
|
||||||
|
|
||||||
|
if (materials == _materials.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseMaterialChanged) {
|
||||||
|
materials->second.setNeedsUpdate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool requestUpdate = false;
|
||||||
|
if (materials->second.top().material && materials->second.top().material->isProcedural() && materials->second.top().material->isReady()) {
|
||||||
|
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials->second.top().material);
|
||||||
|
if (procedural->isFading()) {
|
||||||
|
procedural->setIsFading(Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) < 1.0f);
|
||||||
|
requestUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (materials->second.shouldUpdate()) {
|
||||||
|
RenderPipelines::updateMultiMaterial(materials->second);
|
||||||
|
requestUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestUpdate) {
|
||||||
|
emit requestRenderUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityRenderer::materialsTransparent() const {
|
||||||
|
MaterialMap::const_iterator materials;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
materials = _materials.find("0");
|
||||||
|
|
||||||
|
if (materials == _materials.cend()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (materials->second.top().material) {
|
||||||
|
if (materials->second.top().material->isProcedural() && materials->second.top().material->isReady()) {
|
||||||
|
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials->second.top().material);
|
||||||
|
if (procedural->isFading()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (materials->second.getMaterialKey().isTranslucent()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item::Bound EntityRenderer::getMaterialBound(RenderArgs* args) {
|
||||||
|
MaterialMap::iterator materials;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
materials = _materials.find("0");
|
||||||
|
|
||||||
|
if (materials == _materials.end()) {
|
||||||
|
return EntityRenderer::getBound(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (materials->second.top().material && materials->second.top().material->isProcedural() && materials->second.top().material->isReady()) {
|
||||||
|
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials->second.top().material);
|
||||||
|
if (procedural->hasVertexShader() && procedural->hasBoundOperator()) {
|
||||||
|
return procedural->getBound(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EntityRenderer::getBound(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& builder) {
|
||||||
|
MaterialMap::iterator materials;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
materials = _materials.find("0");
|
||||||
|
if (materials != _materials.end()) {
|
||||||
|
if (materials->second.shouldUpdate()) {
|
||||||
|
RenderPipelines::updateMultiMaterial(materials->second);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTransparent()) {
|
||||||
|
builder.withTranslucent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_primitiveMode == PrimitiveMode::LINES) {
|
||||||
|
builder.withWireframe();
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.withCullFaceMode(materials->second.getCullFaceMode());
|
||||||
|
|
||||||
|
graphics::MaterialKey drawMaterialKey = materials->second.getMaterialKey();
|
||||||
|
if (drawMaterialKey.isUnlit()) {
|
||||||
|
builder.withUnlit();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pipelineType = getPipelineType(materials->second);
|
||||||
|
if (pipelineType == Pipeline::MATERIAL) {
|
||||||
|
builder.withMaterial();
|
||||||
|
|
||||||
|
if (drawMaterialKey.isNormalMap()) {
|
||||||
|
builder.withTangents();
|
||||||
|
}
|
||||||
|
if (drawMaterialKey.isLightMap()) {
|
||||||
|
builder.withLightMap();
|
||||||
|
}
|
||||||
|
} else if (pipelineType == Pipeline::PROCEDURAL) {
|
||||||
|
builder.withOwnPipeline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec4 EntityRenderer::calculatePulseColor(const glm::vec4& color, const PulsePropertyGroup& pulseProperties, quint64 start) {
|
glm::vec4 EntityRenderer::calculatePulseColor(const glm::vec4& color, const PulsePropertyGroup& pulseProperties, quint64 start) {
|
||||||
if (pulseProperties.getPeriod() == 0.0f || (pulseProperties.getColorMode() == PulseMode::NONE && pulseProperties.getAlphaMode() == PulseMode::NONE)) {
|
if (pulseProperties.getPeriod() == 0.0f || (pulseProperties.getColorMode() == PulseMode::NONE && pulseProperties.getAlphaMode() == PulseMode::NONE)) {
|
||||||
return color;
|
return color;
|
||||||
|
|
|
@ -55,8 +55,14 @@ public:
|
||||||
|
|
||||||
const uint64_t& getUpdateTime() const { return _updateTime; }
|
const uint64_t& getUpdateTime() const { return _updateTime; }
|
||||||
|
|
||||||
|
enum class Pipeline {
|
||||||
|
SIMPLE,
|
||||||
|
MATERIAL,
|
||||||
|
PROCEDURAL
|
||||||
|
};
|
||||||
virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||||
virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||||
|
static Pipeline getPipelineType(const graphics::MultiMaterial& materials);
|
||||||
|
|
||||||
virtual scriptable::ScriptableModelBase getScriptableModel() override { return scriptable::ScriptableModelBase(); }
|
virtual scriptable::ScriptableModelBase getScriptableModel() override { return scriptable::ScriptableModelBase(); }
|
||||||
|
|
||||||
|
@ -117,6 +123,14 @@ protected:
|
||||||
|
|
||||||
Transform getTransformToCenterWithMaybeOnlyLocalRotation(const EntityItemPointer& entity, bool& success) const;
|
Transform getTransformToCenterWithMaybeOnlyLocalRotation(const EntityItemPointer& entity, bool& success) const;
|
||||||
|
|
||||||
|
// Shared methods for entities that support materials
|
||||||
|
using MaterialMap = std::unordered_map<std::string, graphics::MultiMaterial>;
|
||||||
|
bool needsRenderUpdateFromMaterials() const;
|
||||||
|
void updateMaterials(bool baseMaterialChanged = false);
|
||||||
|
bool materialsTransparent() const;
|
||||||
|
Item::Bound getMaterialBound(RenderArgs* args);
|
||||||
|
void updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& builder);
|
||||||
|
|
||||||
Item::Bound _bound;
|
Item::Bound _bound;
|
||||||
SharedSoundPointer _collisionSound;
|
SharedSoundPointer _collisionSound;
|
||||||
QUuid _changeHandlerId;
|
QUuid _changeHandlerId;
|
||||||
|
@ -137,8 +151,8 @@ protected:
|
||||||
bool _moving { false };
|
bool _moving { false };
|
||||||
Transform _renderTransform;
|
Transform _renderTransform;
|
||||||
|
|
||||||
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
|
MaterialMap _materials;
|
||||||
std::mutex _materialsLock;
|
mutable std::mutex _materialsLock;
|
||||||
|
|
||||||
quint64 _created;
|
quint64 _created;
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,15 @@
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
|
|
||||||
|
#include "RenderPipelines.h"
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
|
||||||
GizmoEntityRenderer::GizmoEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {}
|
GizmoEntityRenderer::GizmoEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
|
||||||
|
_material->setCullFaceMode(graphics::MaterialKey::CullFaceMode::CULL_NONE);
|
||||||
|
addMaterial(graphics::MaterialLayer(_material, 0), "0");
|
||||||
|
}
|
||||||
|
|
||||||
GizmoEntityRenderer::~GizmoEntityRenderer() {
|
GizmoEntityRenderer::~GizmoEntityRenderer() {
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
|
@ -31,12 +36,8 @@ GizmoEntityRenderer::~GizmoEntityRenderer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GizmoEntityRenderer::isTransparent() const {
|
bool GizmoEntityRenderer::needsRenderUpdate() const {
|
||||||
bool ringTransparent = _gizmoType == GizmoType::RING && (_ringProperties.getInnerStartAlpha() < 1.0f ||
|
return needsRenderUpdateFromMaterials() || Parent::needsRenderUpdate();
|
||||||
_ringProperties.getInnerEndAlpha() < 1.0f || _ringProperties.getOuterStartAlpha() < 1.0f ||
|
|
||||||
_ringProperties.getOuterEndAlpha() < 1.0f);
|
|
||||||
|
|
||||||
return Parent::isTransparent() || ringTransparent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GizmoEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
void GizmoEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||||
|
@ -193,10 +194,20 @@ void GizmoEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateMaterials();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GizmoEntityRenderer::isTransparent() const {
|
||||||
|
bool ringTransparent = _gizmoType == GizmoType::RING && (_ringProperties.getInnerStartAlpha() < 1.0f ||
|
||||||
|
_ringProperties.getInnerEndAlpha() < 1.0f || _ringProperties.getOuterStartAlpha() < 1.0f ||
|
||||||
|
_ringProperties.getOuterEndAlpha() < 1.0f);
|
||||||
|
|
||||||
|
return ringTransparent || Parent::isTransparent() || materialsTransparent();
|
||||||
}
|
}
|
||||||
|
|
||||||
Item::Bound GizmoEntityRenderer::getBound(RenderArgs* args) {
|
Item::Bound GizmoEntityRenderer::getBound(RenderArgs* args) {
|
||||||
auto bound = Parent::getBound(args);
|
auto bound = Parent::getMaterialBound(args);
|
||||||
if (_ringProperties.getHasTickMarks()) {
|
if (_ringProperties.getHasTickMarks()) {
|
||||||
glm::vec3 scale = bound.getScale();
|
glm::vec3 scale = bound.getScale();
|
||||||
for (int i = 0; i < 3; i += 2) {
|
for (int i = 0; i < 3; i += 2) {
|
||||||
|
@ -220,13 +231,8 @@ Item::Bound GizmoEntityRenderer::getBound(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeKey GizmoEntityRenderer::getShapeKey() {
|
ShapeKey GizmoEntityRenderer::getShapeKey() {
|
||||||
auto builder = render::ShapeKey::Builder().withoutCullFace();
|
auto builder = render::ShapeKey::Builder().withDepthBias();
|
||||||
if (isTransparent()) {
|
updateShapeKeyBuilderFromMaterials(builder);
|
||||||
builder.withTranslucent();
|
|
||||||
}
|
|
||||||
if (_primitiveMode == PrimitiveMode::LINES) {
|
|
||||||
builder.withUnlit().withDepthBias();
|
|
||||||
}
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,15 +255,30 @@ void GizmoEntityRenderer::doRender(RenderArgs* args) {
|
||||||
transparent = isTransparent();
|
transparent = isTransparent();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
graphics::MultiMaterial materials;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
materials = _materials["0"];
|
||||||
|
}
|
||||||
|
|
||||||
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
|
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
|
||||||
bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||||
|
|
||||||
geometryCache->bindSimpleProgram(batch, false, transparent, wireframe, true, true, forward, graphics::MaterialKey::CULL_NONE);
|
|
||||||
|
|
||||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true));
|
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true));
|
||||||
batch.setModelTransform(transform);
|
batch.setModelTransform(transform);
|
||||||
|
|
||||||
|
Pipeline pipelineType = getPipelineType(materials);
|
||||||
|
if (pipelineType == Pipeline::PROCEDURAL) {
|
||||||
|
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
|
||||||
|
transparent |= procedural->isFading();
|
||||||
|
procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(transparent));
|
||||||
|
} else if (pipelineType == Pipeline::MATERIAL) {
|
||||||
|
if (RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) {
|
||||||
|
args->_details._materialSwitches++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Background circle
|
// Background circle
|
||||||
geometryCache->renderVertices(batch, wireframe ? gpu::LINE_STRIP : _solidPrimitive, _ringGeometryID);
|
geometryCache->renderVertices(batch, wireframe ? gpu::LINE_STRIP : _solidPrimitive, _ringGeometryID);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include <GizmoEntityItem.h>
|
#include <GizmoEntityItem.h>
|
||||||
|
|
||||||
|
#include <procedural/Procedural.h>
|
||||||
|
|
||||||
namespace render { namespace entities {
|
namespace render { namespace entities {
|
||||||
|
|
||||||
class GizmoEntityRenderer : public TypedEntityRenderer<GizmoEntityItem> {
|
class GizmoEntityRenderer : public TypedEntityRenderer<GizmoEntityItem> {
|
||||||
|
@ -29,10 +31,12 @@ protected:
|
||||||
bool isTransparent() const override;
|
bool isTransparent() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual bool needsRenderUpdate() const override;
|
||||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||||
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
||||||
virtual void doRender(RenderArgs* args) override;
|
virtual void doRender(RenderArgs* args) override;
|
||||||
|
|
||||||
|
std::shared_ptr<graphics::ProceduralMaterial> _material { std::make_shared<graphics::ProceduralMaterial>() };
|
||||||
GizmoType _gizmoType { UNSET_GIZMO_TYPE };
|
GizmoType _gizmoType { UNSET_GIZMO_TYPE };
|
||||||
RingGizmoPropertyGroup _ringProperties;
|
RingGizmoPropertyGroup _ringProperties;
|
||||||
PrimitiveMode _prevPrimitiveMode;
|
PrimitiveMode _prevPrimitiveMode;
|
||||||
|
|
|
@ -10,12 +10,17 @@
|
||||||
|
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
|
#include <graphics/ShaderConstants.h>
|
||||||
|
|
||||||
|
#include "RenderPipelines.h"
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
|
||||||
ImageEntityRenderer::ImageEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
|
ImageEntityRenderer::ImageEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
|
||||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||||
|
_material->setCullFaceMode(graphics::MaterialKey::CullFaceMode::CULL_NONE);
|
||||||
|
addMaterial(graphics::MaterialLayer(_material, 0), "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageEntityRenderer::~ImageEntityRenderer() {
|
ImageEntityRenderer::~ImageEntityRenderer() {
|
||||||
|
@ -25,8 +30,8 @@ ImageEntityRenderer::~ImageEntityRenderer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImageEntityRenderer::isTransparent() const {
|
bool ImageEntityRenderer::needsRenderUpdate() const {
|
||||||
return Parent::isTransparent() || (_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha()) || _alpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
|
return needsRenderUpdateFromMaterials() || Parent::needsRenderUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
void ImageEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||||
|
@ -51,14 +56,34 @@ void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
||||||
_textureIsLoaded = false;
|
_textureIsLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_emissive = entity->getEmissive();
|
|
||||||
_keepAspectRatio = entity->getKeepAspectRatio();
|
_keepAspectRatio = entity->getKeepAspectRatio();
|
||||||
_subImage = entity->getSubImage();
|
_subImage = entity->getSubImage();
|
||||||
|
|
||||||
_color = entity->getColor();
|
|
||||||
_alpha = entity->getAlpha();
|
|
||||||
_pulseProperties = entity->getPulseProperties();
|
_pulseProperties = entity->getPulseProperties();
|
||||||
|
|
||||||
|
bool materialChanged = false;
|
||||||
|
glm::vec3 color = toGlm(entity->getColor());
|
||||||
|
if (_color != color) {
|
||||||
|
_color = color;
|
||||||
|
_material->setAlbedo(color);
|
||||||
|
materialChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float alpha = entity->getAlpha();
|
||||||
|
if (_alpha != alpha) {
|
||||||
|
_alpha = alpha;
|
||||||
|
_material->setOpacity(alpha);
|
||||||
|
materialChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto emissive = entity->getEmissive();
|
||||||
|
if (_emissive != emissive) {
|
||||||
|
_emissive = emissive;
|
||||||
|
_material->setUnlit(_emissive);
|
||||||
|
materialChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMaterials(materialChanged);
|
||||||
|
|
||||||
bool nextTextureLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
|
bool nextTextureLoaded = _texture && (_texture->isLoaded() || _texture->isFailed());
|
||||||
if (!_textureIsLoaded) {
|
if (!_textureIsLoaded) {
|
||||||
emit requestRenderUpdate();
|
emit requestRenderUpdate();
|
||||||
|
@ -79,43 +104,52 @@ void ImageEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
||||||
_textureIsLoaded = nextTextureLoaded;
|
_textureIsLoaded = nextTextureLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImageEntityRenderer::isTransparent() const {
|
||||||
|
bool imageTransparent = _alpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE ||
|
||||||
|
(_textureIsLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha());
|
||||||
|
return imageTransparent || Parent::isTransparent() || materialsTransparent();
|
||||||
|
}
|
||||||
|
|
||||||
|
Item::Bound ImageEntityRenderer::getBound(RenderArgs* args) {
|
||||||
|
return Parent::getMaterialBound(args);
|
||||||
|
}
|
||||||
|
|
||||||
ShapeKey ImageEntityRenderer::getShapeKey() {
|
ShapeKey ImageEntityRenderer::getShapeKey() {
|
||||||
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias();
|
auto builder = render::ShapeKey::Builder().withDepthBias();
|
||||||
if (isTransparent()) {
|
updateShapeKeyBuilderFromMaterials(builder);
|
||||||
builder.withTranslucent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_emissive) {
|
|
||||||
builder.withUnlit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_primitiveMode == PrimitiveMode::LINES) {
|
|
||||||
builder.withWireframe();
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageEntityRenderer::doRender(RenderArgs* args) {
|
void ImageEntityRenderer::doRender(RenderArgs* args) {
|
||||||
glm::vec4 color = glm::vec4(toGlm(_color), _alpha);
|
PerformanceTimer perfTimer("RenderableImageEntityItem::render");
|
||||||
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
|
Q_ASSERT(args->_batch);
|
||||||
Transform transform;
|
|
||||||
withReadLock([&] {
|
|
||||||
transform = _renderTransform;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!_visible || !_texture || !_texture->isLoaded() || color.a == 0.0f) {
|
graphics::MultiMaterial materials;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
materials = _materials["0"];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||||
|
glm::vec4 color = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
|
||||||
|
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
|
||||||
|
|
||||||
|
if (!_texture || !_texture->isLoaded() || color.a == 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(args->_batch);
|
Transform transform;
|
||||||
|
bool transparent;
|
||||||
|
withReadLock([&] {
|
||||||
|
transform = _renderTransform;
|
||||||
|
transparent = isTransparent();
|
||||||
|
});
|
||||||
|
|
||||||
gpu::Batch* batch = args->_batch;
|
gpu::Batch* batch = args->_batch;
|
||||||
|
|
||||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||||
|
|
||||||
batch->setResourceTexture(0, _texture->getGPUTexture());
|
|
||||||
|
|
||||||
float imageWidth = _texture->getWidth();
|
float imageWidth = _texture->getWidth();
|
||||||
float imageHeight = _texture->getHeight();
|
float imageHeight = _texture->getHeight();
|
||||||
float originalWidth = _texture->getOriginalWidth();
|
float originalWidth = _texture->getOriginalWidth();
|
||||||
|
@ -157,10 +191,26 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
batch->setModelTransform(transform);
|
batch->setModelTransform(transform);
|
||||||
|
|
||||||
|
Pipeline pipelineType = getPipelineType(materials);
|
||||||
|
if (pipelineType == Pipeline::PROCEDURAL) {
|
||||||
|
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
|
||||||
|
transparent |= procedural->isFading();
|
||||||
|
procedural->prepare(*batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(transparent));
|
||||||
|
} else if (pipelineType == Pipeline::SIMPLE) {
|
||||||
|
batch->setResourceTexture(0, _texture->getGPUTexture());
|
||||||
|
} else {
|
||||||
|
if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) {
|
||||||
|
args->_details._materialSwitches++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(
|
DependencyManager::get<GeometryCache>()->renderQuad(
|
||||||
*batch, glm::vec2(-0.5f), glm::vec2(0.5f), texCoordBottomLeft, texCoordTopRight,
|
*batch, glm::vec2(-0.5f), glm::vec2(0.5f), texCoordBottomLeft, texCoordTopRight,
|
||||||
color, _geometryId
|
color, _geometryId
|
||||||
);
|
);
|
||||||
|
|
||||||
batch->setResourceTexture(0, nullptr);
|
if (pipelineType == Pipeline::SIMPLE) {
|
||||||
|
// we have to reset this to white for other simple shapes
|
||||||
|
batch->setResourceTexture(graphics::slot::texture::Texture::MaterialAlbedo, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include <ImageEntityItem.h>
|
#include <ImageEntityItem.h>
|
||||||
|
|
||||||
|
#include <procedural/Procedural.h>
|
||||||
|
|
||||||
namespace render { namespace entities {
|
namespace render { namespace entities {
|
||||||
|
|
||||||
class ImageEntityRenderer : public TypedEntityRenderer<ImageEntityItem> {
|
class ImageEntityRenderer : public TypedEntityRenderer<ImageEntityItem> {
|
||||||
|
@ -23,11 +25,13 @@ public:
|
||||||
~ImageEntityRenderer();
|
~ImageEntityRenderer();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Item::Bound getBound(RenderArgs* args) override;
|
||||||
ShapeKey getShapeKey() override;
|
ShapeKey getShapeKey() override;
|
||||||
|
|
||||||
bool isTransparent() const override;
|
bool isTransparent() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual bool needsRenderUpdate() const override;
|
||||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||||
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
||||||
virtual void doRender(RenderArgs* args) override;
|
virtual void doRender(RenderArgs* args) override;
|
||||||
|
@ -40,8 +44,9 @@ private:
|
||||||
bool _keepAspectRatio;
|
bool _keepAspectRatio;
|
||||||
QRect _subImage;
|
QRect _subImage;
|
||||||
|
|
||||||
glm::u8vec3 _color;
|
std::shared_ptr<graphics::ProceduralMaterial> _material { std::make_shared<graphics::ProceduralMaterial>() };
|
||||||
float _alpha;
|
glm::vec3 _color { NAN };
|
||||||
|
float _alpha { NAN };
|
||||||
PulsePropertyGroup _pulseProperties;
|
PulsePropertyGroup _pulseProperties;
|
||||||
|
|
||||||
int _geometryId { 0 };
|
int _geometryId { 0 };
|
||||||
|
|
|
@ -219,6 +219,10 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
|
||||||
builder.withTranslucent();
|
builder.withTranslucent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (drawMaterial) {
|
||||||
|
builder.withCullFaceMode(drawMaterial->getCullFaceMode());
|
||||||
|
}
|
||||||
|
|
||||||
if (drawMaterial && drawMaterial->isProcedural() && drawMaterial->isReady()) {
|
if (drawMaterial && drawMaterial->isProcedural() && drawMaterial->isReady()) {
|
||||||
builder.withOwnPipeline();
|
builder.withOwnPipeline();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -29,26 +29,7 @@ ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Pare
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShapeEntityRenderer::needsRenderUpdate() const {
|
bool ShapeEntityRenderer::needsRenderUpdate() const {
|
||||||
if (resultWithReadLock<bool>([&] {
|
return needsRenderUpdateFromMaterials() || Parent::needsRenderUpdate();
|
||||||
auto mat = _materials.find("0");
|
|
||||||
if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isProcedural() &&
|
|
||||||
mat->second.top().material->isReady()) {
|
|
||||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(mat->second.top().material);
|
|
||||||
if (procedural->isFading()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mat != _materials.end() && mat->second.shouldUpdate()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
})) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Parent::needsRenderUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||||
|
@ -91,155 +72,58 @@ void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
||||||
materialChanged = true;
|
materialChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
withReadLock([&] {
|
updateMaterials(materialChanged);
|
||||||
auto materials = _materials.find("0");
|
|
||||||
if (materials != _materials.end()) {
|
|
||||||
if (materialChanged) {
|
|
||||||
materials->second.setNeedsUpdate(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool requestUpdate = false;
|
|
||||||
if (materials->second.top().material && materials->second.top().material->isProcedural() && materials->second.top().material->isReady()) {
|
|
||||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials->second.top().material);
|
|
||||||
if (procedural->isFading()) {
|
|
||||||
procedural->setIsFading(Interpolate::calculateFadeRatio(procedural->getFadeStartTime()) < 1.0f);
|
|
||||||
requestUpdate = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (materials->second.shouldUpdate()) {
|
|
||||||
RenderPipelines::updateMultiMaterial(materials->second);
|
|
||||||
requestUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestUpdate) {
|
|
||||||
emit requestRenderUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShapeEntityRenderer::isTransparent() const {
|
bool ShapeEntityRenderer::isTransparent() const {
|
||||||
if (_pulseProperties.getAlphaMode() != PulseMode::NONE) {
|
return _pulseProperties.getAlphaMode() != PulseMode::NONE || Parent::isTransparent() || materialsTransparent();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mat = _materials.find("0");
|
|
||||||
if (mat != _materials.end() && mat->second.top().material) {
|
|
||||||
if (mat->second.top().material->isProcedural() && mat->second.top().material->isReady()) {
|
|
||||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(mat->second.top().material);
|
|
||||||
if (procedural->isFading()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mat->second.getMaterialKey().isTranslucent()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Parent::isTransparent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeEntityRenderer::Pipeline ShapeEntityRenderer::getPipelineType(const graphics::MultiMaterial& materials) const {
|
Item::Bound ShapeEntityRenderer::getBound(RenderArgs* args) {
|
||||||
if (materials.top().material && materials.top().material->isProcedural() && materials.top().material->isReady()) {
|
return Parent::getMaterialBound(args);
|
||||||
return Pipeline::PROCEDURAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
graphics::MaterialKey drawMaterialKey = materials.getMaterialKey();
|
|
||||||
if (drawMaterialKey.isEmissive() || drawMaterialKey.isUnlit() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
|
|
||||||
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 Pipeline::MATERIAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Pipeline::SIMPLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeKey ShapeEntityRenderer::getShapeKey() {
|
ShapeKey ShapeEntityRenderer::getShapeKey() {
|
||||||
ShapeKey::Builder builder;
|
ShapeKey::Builder builder;
|
||||||
auto mat = _materials.find("0");
|
updateShapeKeyBuilderFromMaterials(builder);
|
||||||
if (mat != _materials.end() && mat->second.shouldUpdate()) {
|
|
||||||
RenderPipelines::updateMultiMaterial(mat->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isTransparent()) {
|
|
||||||
builder.withTranslucent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_primitiveMode == PrimitiveMode::LINES) {
|
|
||||||
builder.withWireframe();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto pipelineType = getPipelineType(mat->second);
|
|
||||||
if (pipelineType == Pipeline::MATERIAL) {
|
|
||||||
builder.withMaterial();
|
|
||||||
|
|
||||||
graphics::MaterialKey drawMaterialKey = mat->second.getMaterialKey();
|
|
||||||
if (drawMaterialKey.isNormalMap()) {
|
|
||||||
builder.withTangents();
|
|
||||||
}
|
|
||||||
if (drawMaterialKey.isLightMap()) {
|
|
||||||
builder.withLightMap();
|
|
||||||
}
|
|
||||||
if (drawMaterialKey.isUnlit()) {
|
|
||||||
builder.withUnlit();
|
|
||||||
}
|
|
||||||
builder.withCullFaceMode(mat->second.getCullFaceMode());
|
|
||||||
} else if (pipelineType == Pipeline::PROCEDURAL) {
|
|
||||||
builder.withOwnPipeline();
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
Item::Bound ShapeEntityRenderer::getBound(RenderArgs* args) {
|
|
||||||
auto mat = _materials.find("0");
|
|
||||||
if (mat != _materials.end() && mat->second.top().material && mat->second.top().material->isProcedural() &&
|
|
||||||
mat->second.top().material->isReady()) {
|
|
||||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(mat->second.top().material);
|
|
||||||
if (procedural->hasVertexShader() && procedural->hasBoundOperator()) {
|
|
||||||
return procedural->getBound(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Parent::getBound(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||||
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
|
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
|
||||||
Q_ASSERT(args->_batch);
|
Q_ASSERT(args->_batch);
|
||||||
|
|
||||||
gpu::Batch& batch = *args->_batch;
|
|
||||||
|
|
||||||
graphics::MultiMaterial materials;
|
graphics::MultiMaterial materials;
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
{
|
||||||
GeometryCache::Shape geometryShape = geometryCache->getShapeForEntityShape(_shape);
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
glm::vec4 outColor;
|
|
||||||
Pipeline pipelineType;
|
|
||||||
Transform transform;
|
|
||||||
withReadLock([&] {
|
|
||||||
transform = _renderTransform;
|
|
||||||
materials = _materials["0"];
|
materials = _materials["0"];
|
||||||
pipelineType = getPipelineType(materials);
|
}
|
||||||
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
|
||||||
outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||||
|
glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
|
||||||
outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
|
outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
|
||||||
|
|
||||||
if (outColor.a == 0.0f) {
|
if (outColor.a == 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::Batch& batch = *args->_batch;
|
||||||
|
|
||||||
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
|
GeometryCache::Shape geometryShape = geometryCache->getShapeForEntityShape(_shape);
|
||||||
|
Transform transform;
|
||||||
|
withReadLock([&] {
|
||||||
|
transform = _renderTransform;
|
||||||
|
});
|
||||||
|
|
||||||
|
bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES;
|
||||||
|
|
||||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(),
|
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(),
|
||||||
_shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron));
|
_shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron));
|
||||||
batch.setModelTransform(transform);
|
batch.setModelTransform(transform);
|
||||||
|
|
||||||
|
Pipeline pipelineType = getPipelineType(materials);
|
||||||
if (pipelineType == Pipeline::PROCEDURAL) {
|
if (pipelineType == Pipeline::PROCEDURAL) {
|
||||||
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
|
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
|
||||||
outColor = procedural->getColor(outColor);
|
outColor = procedural->getColor(outColor);
|
||||||
|
@ -248,7 +132,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||||
procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
|
procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
if (wireframe) {
|
||||||
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
||||||
} else {
|
} else {
|
||||||
geometryCache->renderShape(batch, geometryShape, outColor);
|
geometryCache->renderShape(batch, geometryShape, outColor);
|
||||||
|
@ -256,12 +140,21 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||||
} else if (pipelineType == Pipeline::SIMPLE) {
|
} else if (pipelineType == Pipeline::SIMPLE) {
|
||||||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||||
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||||
render::ShapePipelinePointer pipeline = geometryCache->getShapePipelinePointer(outColor.a < 1.0f, false,
|
bool forward = _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD;
|
||||||
_renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD, materials.top().material->getCullFaceMode());
|
if (outColor.a >= 1.0f) {
|
||||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
render::ShapePipelinePointer pipeline = geometryCache->getShapePipelinePointer(false, wireframe || materials.top().material->isUnlit(),
|
||||||
geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
forward, materials.top().material->getCullFaceMode());
|
||||||
|
if (wireframe) {
|
||||||
|
geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||||
|
} else {
|
||||||
|
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
|
if (wireframe) {
|
||||||
|
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
||||||
|
} else {
|
||||||
|
geometryCache->renderShape(batch, geometryShape, outColor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) {
|
if (RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) {
|
||||||
|
|
|
@ -35,9 +35,6 @@ private:
|
||||||
virtual void doRender(RenderArgs* args) override;
|
virtual void doRender(RenderArgs* args) override;
|
||||||
virtual bool isTransparent() const override;
|
virtual bool isTransparent() const override;
|
||||||
|
|
||||||
enum Pipeline { SIMPLE, MATERIAL, PROCEDURAL };
|
|
||||||
Pipeline getPipelineType(const graphics::MultiMaterial& materials) const;
|
|
||||||
|
|
||||||
QString _proceduralData;
|
QString _proceduralData;
|
||||||
entity::Shape _shape { entity::Sphere };
|
entity::Shape _shape { entity::Sphere };
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "GLMHelpers.h"
|
#include "GLMHelpers.h"
|
||||||
|
|
||||||
#include "DeferredLightingEffect.h"
|
#include "DeferredLightingEffect.h"
|
||||||
|
#include "RenderPipelines.h"
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
@ -35,6 +36,8 @@ TextEntityRenderer::TextEntityRenderer(const EntityItemPointer& entity) :
|
||||||
if (geometryCache) {
|
if (geometryCache) {
|
||||||
_geometryID = geometryCache->allocateID();
|
_geometryID = geometryCache->allocateID();
|
||||||
}
|
}
|
||||||
|
_material->setCullFaceMode(graphics::MaterialKey::CullFaceMode::CULL_NONE);
|
||||||
|
addMaterial(graphics::MaterialLayer(_material, 0), "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEntityRenderer::~TextEntityRenderer() {
|
TextEntityRenderer::~TextEntityRenderer() {
|
||||||
|
@ -44,41 +47,8 @@ TextEntityRenderer::~TextEntityRenderer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextEntityRenderer::isTransparent() const {
|
bool TextEntityRenderer::needsRenderUpdate() const {
|
||||||
return Parent::isTransparent() || _backgroundAlpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
|
return needsRenderUpdateFromMaterials() || Parent::needsRenderUpdate();
|
||||||
}
|
|
||||||
|
|
||||||
bool TextEntityRenderer::isTextTransparent() const {
|
|
||||||
return resultWithReadLock<bool>([&] {
|
|
||||||
return Parent::isTransparent() || _textAlpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemKey TextEntityRenderer::getKey() {
|
|
||||||
return ItemKey::Builder(Parent::getKey()).withMetaCullGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ShapeKey TextEntityRenderer::getShapeKey() {
|
|
||||||
auto builder = render::ShapeKey::Builder().withoutCullFace();
|
|
||||||
if (isTransparent()) {
|
|
||||||
builder.withTranslucent();
|
|
||||||
}
|
|
||||||
if (_unlit) {
|
|
||||||
builder.withUnlit();
|
|
||||||
}
|
|
||||||
if (_primitiveMode == PrimitiveMode::LINES) {
|
|
||||||
builder.withWireframe();
|
|
||||||
}
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t TextEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
|
|
||||||
auto parentSubs = Parent::metaFetchMetaSubItems(subItems);
|
|
||||||
if (Item::isValidID(_textRenderID)) {
|
|
||||||
subItems.emplace_back(_textRenderID);
|
|
||||||
return parentSubs + 1;
|
|
||||||
}
|
|
||||||
return parentSubs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
void TextEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||||
|
@ -98,58 +68,126 @@ void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe
|
||||||
_lineHeight = entity->getLineHeight();
|
_lineHeight = entity->getLineHeight();
|
||||||
_textColor = toGlm(entity->getTextColor());
|
_textColor = toGlm(entity->getTextColor());
|
||||||
_textAlpha = entity->getTextAlpha();
|
_textAlpha = entity->getTextAlpha();
|
||||||
_backgroundColor = toGlm(entity->getBackgroundColor());
|
|
||||||
_backgroundAlpha = entity->getBackgroundAlpha();
|
|
||||||
_leftMargin = entity->getLeftMargin();
|
_leftMargin = entity->getLeftMargin();
|
||||||
_rightMargin = entity->getRightMargin();
|
_rightMargin = entity->getRightMargin();
|
||||||
_topMargin = entity->getTopMargin();
|
_topMargin = entity->getTopMargin();
|
||||||
_bottomMargin = entity->getBottomMargin();
|
_bottomMargin = entity->getBottomMargin();
|
||||||
_unlit = entity->getUnlit();
|
|
||||||
_font = entity->getFont();
|
_font = entity->getFont();
|
||||||
_effect = entity->getTextEffect();
|
_effect = entity->getTextEffect();
|
||||||
_effectColor = toGlm(entity->getTextEffectColor());
|
_effectColor = toGlm(entity->getTextEffectColor());
|
||||||
_effectThickness = entity->getTextEffectThickness();
|
_effectThickness = entity->getTextEffectThickness();
|
||||||
_alignment = entity->getAlignment();
|
_alignment = entity->getAlignment();
|
||||||
|
|
||||||
|
bool materialChanged = false;
|
||||||
|
glm::vec3 color = toGlm(entity->getBackgroundColor());
|
||||||
|
if (_backgroundColor != color) {
|
||||||
|
_backgroundColor = color;
|
||||||
|
_material->setAlbedo(color);
|
||||||
|
materialChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float alpha = entity->getBackgroundAlpha();
|
||||||
|
if (_backgroundAlpha != alpha) {
|
||||||
|
_backgroundAlpha = alpha;
|
||||||
|
_material->setOpacity(alpha);
|
||||||
|
materialChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto unlit = entity->getUnlit();
|
||||||
|
if (_unlit != unlit) {
|
||||||
|
_unlit = unlit;
|
||||||
|
_material->setUnlit(_unlit);
|
||||||
|
materialChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMaterials(materialChanged);
|
||||||
|
|
||||||
updateTextRenderItem();
|
updateTextRenderItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TextEntityRenderer::isTransparent() const {
|
||||||
|
bool backgroundTransparent = _backgroundAlpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
|
||||||
|
return backgroundTransparent || Parent::isTransparent() || materialsTransparent();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextEntityRenderer::isTextTransparent() const {
|
||||||
|
return Parent::isTransparent() || _textAlpha < 1.0f || _pulseProperties.getAlphaMode() != PulseMode::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item::Bound TextEntityRenderer::getBound(RenderArgs* args) {
|
||||||
|
return Parent::getMaterialBound(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemKey TextEntityRenderer::getKey() {
|
||||||
|
return ItemKey::Builder(Parent::getKey()).withMetaCullGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapeKey TextEntityRenderer::getShapeKey() {
|
||||||
|
auto builder = render::ShapeKey::Builder().withDepthBias();
|
||||||
|
updateShapeKeyBuilderFromMaterials(builder);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t TextEntityRenderer::metaFetchMetaSubItems(ItemIDs& subItems) const {
|
||||||
|
auto parentSubs = Parent::metaFetchMetaSubItems(subItems);
|
||||||
|
if (Item::isValidID(_textRenderID)) {
|
||||||
|
subItems.emplace_back(_textRenderID);
|
||||||
|
return parentSubs + 1;
|
||||||
|
}
|
||||||
|
return parentSubs;
|
||||||
|
}
|
||||||
|
|
||||||
void TextEntityRenderer::doRender(RenderArgs* args) {
|
void TextEntityRenderer::doRender(RenderArgs* args) {
|
||||||
PerformanceTimer perfTimer("RenderableTextEntityItem::render");
|
PerformanceTimer perfTimer("RenderableTextEntityItem::render");
|
||||||
Q_ASSERT(args->_batch);
|
Q_ASSERT(args->_batch);
|
||||||
gpu::Batch& batch = *args->_batch;
|
|
||||||
|
|
||||||
glm::vec4 backgroundColor;
|
graphics::MultiMaterial materials;
|
||||||
Transform transform;
|
{
|
||||||
withReadLock([&] {
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
transform = _renderTransform;
|
materials = _materials["0"];
|
||||||
|
}
|
||||||
|
|
||||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
auto& schema = materials.getSchemaBuffer().get<graphics::MultiMaterial::Schema>();
|
||||||
backgroundColor = glm::vec4(_backgroundColor, fadeRatio * _backgroundAlpha);
|
glm::vec4 backgroundColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
|
||||||
});
|
|
||||||
backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
|
backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
|
||||||
|
|
||||||
if (backgroundColor.a <= 0.0f) {
|
if (backgroundColor.a <= 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::Batch& batch = *args->_batch;
|
||||||
|
|
||||||
|
bool transparent;
|
||||||
|
Transform transform;
|
||||||
|
withReadLock([&] {
|
||||||
|
transparent = isTransparent();
|
||||||
|
transform = _renderTransform;
|
||||||
|
});
|
||||||
|
|
||||||
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode,
|
||||||
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition()));
|
||||||
batch.setModelTransform(transform);
|
batch.setModelTransform(transform);
|
||||||
|
|
||||||
|
Pipeline pipelineType = getPipelineType(materials);
|
||||||
|
if (pipelineType == Pipeline::PROCEDURAL) {
|
||||||
|
auto procedural = std::static_pointer_cast<graphics::ProceduralMaterial>(materials.top().material);
|
||||||
|
transparent |= procedural->isFading();
|
||||||
|
procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(transparent));
|
||||||
|
} else if (pipelineType == Pipeline::MATERIAL) {
|
||||||
|
if (RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) {
|
||||||
|
args->_details._materialSwitches++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
// FIXME: we want to use instanced rendering here, but if textAlpha < 1 and backgroundAlpha < 1, the transparency sorting will be wrong
|
if (pipelineType == Pipeline::SIMPLE) {
|
||||||
//render::ShapePipelinePointer pipeline = geometryCache->getShapePipelinePointer(backgroundColor.a < 1.0f, _unlit,
|
geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), backgroundColor, _geometryID);
|
||||||
// _renderLayer != RenderLayer::WORLD || args->_renderMethod == Args::RenderMethod::FORWARD);
|
} else {
|
||||||
//if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
|
geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), glm::vec2(0.0f), glm::vec2(1.0f), backgroundColor, _geometryID);
|
||||||
// geometryCache->renderWireShapeInstance(args, batch, GeometryCache::Quad, backgroundColor, pipeline);
|
}
|
||||||
//} else {
|
|
||||||
// geometryCache->renderSolidShapeInstance(args, batch, GeometryCache::Quad, backgroundColor, pipeline);
|
|
||||||
//}
|
|
||||||
|
|
||||||
geometryCache->renderQuad(batch, glm::vec2(-0.5), glm::vec2(0.5), backgroundColor, _geometryID);
|
const int TRIANGLES_PER_QUAD = 2;
|
||||||
|
args->_details._trianglesRendered += TRIANGLES_PER_QUAD;
|
||||||
const int TRIANBLES_PER_QUAD = 2;
|
|
||||||
args->_details._trianglesRendered += TRIANBLES_PER_QUAD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QSizeF TextEntityRenderer::textSize(const QString& text) const {
|
QSizeF TextEntityRenderer::textSize(const QString& text) const {
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
#include "RenderableEntityItem.h"
|
#include "RenderableEntityItem.h"
|
||||||
|
|
||||||
|
#include <procedural/Procedural.h>
|
||||||
|
|
||||||
class TextEntityItem;
|
class TextEntityItem;
|
||||||
class TextRenderer3D;
|
class TextRenderer3D;
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
bool isTransparent() const override;
|
bool isTransparent() const override;
|
||||||
bool isTextTransparent() const;
|
bool isTextTransparent() const;
|
||||||
|
Item::Bound getBound(RenderArgs* args) override;
|
||||||
ShapeKey getShapeKey() override;
|
ShapeKey getShapeKey() override;
|
||||||
ItemKey getKey() override;
|
ItemKey getKey() override;
|
||||||
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
|
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
|
||||||
|
@ -41,6 +44,7 @@ protected:
|
||||||
void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
|
void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual bool needsRenderUpdate() const;
|
||||||
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||||
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
|
||||||
virtual void doRender(RenderArgs* args) override;
|
virtual void doRender(RenderArgs* args) override;
|
||||||
|
@ -53,10 +57,12 @@ private:
|
||||||
float _lineHeight;
|
float _lineHeight;
|
||||||
glm::vec3 _textColor;
|
glm::vec3 _textColor;
|
||||||
float _textAlpha;
|
float _textAlpha;
|
||||||
glm::vec3 _backgroundColor;
|
|
||||||
float _backgroundAlpha;
|
|
||||||
bool _unlit;
|
bool _unlit;
|
||||||
|
|
||||||
|
std::shared_ptr<graphics::ProceduralMaterial> _material { std::make_shared<graphics::ProceduralMaterial>() };
|
||||||
|
glm::vec3 _backgroundColor { NAN };
|
||||||
|
float _backgroundAlpha { NAN };
|
||||||
|
|
||||||
float _leftMargin;
|
float _leftMargin;
|
||||||
float _rightMargin;
|
float _rightMargin;
|
||||||
float _topMargin;
|
float _topMargin;
|
||||||
|
|
|
@ -840,10 +840,7 @@ void GLBackend::do_glColor4f(const Batch& batch, size_t paramOffset) {
|
||||||
if (_input._colorAttribute != newColor) {
|
if (_input._colorAttribute != newColor) {
|
||||||
_input._colorAttribute = newColor;
|
_input._colorAttribute = newColor;
|
||||||
glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r);
|
glVertexAttrib4fv(gpu::Stream::COLOR, &_input._colorAttribute.r);
|
||||||
// Color has been changed and is not white. To prevent colors from bleeding
|
_input._hasColorAttribute = true;
|
||||||
// between different objects, we need to set the _hadColorAttribute flag
|
|
||||||
// as if a previous render call had potential colors
|
|
||||||
_input._hadColorAttribute = (newColor != glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
|
||||||
}
|
}
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,36 +348,37 @@ protected:
|
||||||
virtual void updateInput() = 0;
|
virtual void updateInput() = 0;
|
||||||
|
|
||||||
struct InputStageState {
|
struct InputStageState {
|
||||||
bool _invalidFormat{ true };
|
bool _invalidFormat { true };
|
||||||
bool _lastUpdateStereoState{ false };
|
bool _lastUpdateStereoState { false };
|
||||||
bool _hadColorAttribute{ true };
|
bool _hasColorAttribute { false };
|
||||||
FormatReference _format{ GPU_REFERENCE_INIT_VALUE };
|
bool _hadColorAttribute { false };
|
||||||
|
FormatReference _format { GPU_REFERENCE_INIT_VALUE };
|
||||||
std::string _formatKey;
|
std::string _formatKey;
|
||||||
|
|
||||||
typedef std::bitset<MAX_NUM_ATTRIBUTES> ActivationCache;
|
typedef std::bitset<MAX_NUM_ATTRIBUTES> ActivationCache;
|
||||||
ActivationCache _attributeActivation{ 0 };
|
ActivationCache _attributeActivation { 0 };
|
||||||
|
|
||||||
typedef std::bitset<MAX_NUM_INPUT_BUFFERS> BuffersState;
|
typedef std::bitset<MAX_NUM_INPUT_BUFFERS> BuffersState;
|
||||||
|
|
||||||
BuffersState _invalidBuffers{ 0 };
|
BuffersState _invalidBuffers { 0 };
|
||||||
BuffersState _attribBindingBuffers{ 0 };
|
BuffersState _attribBindingBuffers { 0 };
|
||||||
|
|
||||||
std::array<BufferReference, MAX_NUM_INPUT_BUFFERS> _buffers{};
|
std::array<BufferReference, MAX_NUM_INPUT_BUFFERS> _buffers;
|
||||||
std::array<Offset, MAX_NUM_INPUT_BUFFERS> _bufferOffsets{};
|
std::array<Offset, MAX_NUM_INPUT_BUFFERS> _bufferOffsets;
|
||||||
std::array<Offset, MAX_NUM_INPUT_BUFFERS> _bufferStrides{};
|
std::array<Offset, MAX_NUM_INPUT_BUFFERS> _bufferStrides;
|
||||||
std::array<GLuint, MAX_NUM_INPUT_BUFFERS> _bufferVBOs{};
|
std::array<GLuint, MAX_NUM_INPUT_BUFFERS> _bufferVBOs;
|
||||||
|
|
||||||
glm::vec4 _colorAttribute{ 0.0f };
|
glm::vec4 _colorAttribute { 1.0f };
|
||||||
|
|
||||||
BufferReference _indexBuffer{};
|
BufferReference _indexBuffer;
|
||||||
Offset _indexBufferOffset{ 0 };
|
Offset _indexBufferOffset { 0 };
|
||||||
Type _indexBufferType{ UINT32 };
|
Type _indexBufferType { UINT32 };
|
||||||
|
|
||||||
BufferReference _indirectBuffer{};
|
BufferReference _indirectBuffer;
|
||||||
Offset _indirectBufferOffset{ 0 };
|
Offset _indirectBufferOffset { 0 };
|
||||||
Offset _indirectBufferStride{ 0 };
|
Offset _indirectBufferStride { 0 };
|
||||||
|
|
||||||
GLuint _defaultVAO{ 0 };
|
GLuint _defaultVAO { 0 };
|
||||||
} _input;
|
} _input;
|
||||||
|
|
||||||
virtual void initTransform() = 0;
|
virtual void initTransform() = 0;
|
||||||
|
|
|
@ -103,6 +103,9 @@ void GLBackend::resetInputStage() {
|
||||||
reset(_input._format);
|
reset(_input._format);
|
||||||
_input._formatKey.clear();
|
_input._formatKey.clear();
|
||||||
_input._invalidFormat = false;
|
_input._invalidFormat = false;
|
||||||
|
_input._hasColorAttribute = false;
|
||||||
|
_input._hadColorAttribute = false;
|
||||||
|
_input._colorAttribute = vec4(1.0f);
|
||||||
_input._attributeActivation.reset();
|
_input._attributeActivation.reset();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < _input._buffers.size(); i++) {
|
for (uint32_t i = 0; i < _input._buffers.size(); i++) {
|
||||||
|
@ -159,15 +162,15 @@ void GLBackend::updateInput() {
|
||||||
_input._invalidFormat |= (isStereoNow != _input._lastUpdateStereoState);
|
_input._invalidFormat |= (isStereoNow != _input._lastUpdateStereoState);
|
||||||
#endif
|
#endif
|
||||||
_input._lastUpdateStereoState = isStereoNow;
|
_input._lastUpdateStereoState = isStereoNow;
|
||||||
|
|
||||||
|
bool hasColorAttribute = _input._hasColorAttribute;
|
||||||
|
|
||||||
if (_input._invalidFormat) {
|
if (_input._invalidFormat) {
|
||||||
InputStageState::ActivationCache newActivation;
|
InputStageState::ActivationCache newActivation;
|
||||||
|
|
||||||
// Assign the vertex format required
|
// Assign the vertex format required
|
||||||
auto format = acquire(_input._format);
|
auto format = acquire(_input._format);
|
||||||
if (format) {
|
if (format) {
|
||||||
bool hasColorAttribute{ false };
|
|
||||||
|
|
||||||
_input._attribBindingBuffers.reset();
|
_input._attribBindingBuffers.reset();
|
||||||
|
|
||||||
const auto& attributes = format->getAttributes();
|
const auto& attributes = format->getAttributes();
|
||||||
|
@ -186,12 +189,12 @@ void GLBackend::updateInput() {
|
||||||
uint8_t locationCount = attrib._element.getLocationCount();
|
uint8_t locationCount = attrib._element.getLocationCount();
|
||||||
GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()];
|
GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()];
|
||||||
|
|
||||||
GLuint offset = (GLuint)attrib._offset;;
|
GLuint offset = (GLuint)attrib._offset;
|
||||||
GLboolean isNormalized = attrib._element.isNormalized();
|
GLboolean isNormalized = attrib._element.isNormalized();
|
||||||
|
|
||||||
GLenum perLocationSize = attrib._element.getLocationSize();
|
GLenum perLocationSize = attrib._element.getLocationSize();
|
||||||
|
|
||||||
hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR);
|
hasColorAttribute |= slot == Stream::COLOR;
|
||||||
|
|
||||||
for (GLuint locNum = 0; locNum < locationCount; ++locNum) {
|
for (GLuint locNum = 0; locNum < locationCount; ++locNum) {
|
||||||
GLuint attriNum = (GLuint)(slot + locNum);
|
GLuint attriNum = (GLuint)(slot + locNum);
|
||||||
|
@ -224,14 +227,11 @@ void GLBackend::updateInput() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_input._hadColorAttribute && !hasColorAttribute) {
|
if (!hasColorAttribute && _input._hadColorAttribute) {
|
||||||
// The previous input stage had a color attribute but this one doesn't so reset
|
// The previous input stage had a color attribute but this one doesn't, so reset the color to pure white.
|
||||||
// color to pure white.
|
_input._colorAttribute = glm::vec4(1.0f);
|
||||||
const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
glVertexAttrib4fv(Stream::COLOR, &_input._colorAttribute.r);
|
||||||
glVertexAttrib4fv(Stream::COLOR, &white.r);
|
|
||||||
_input._colorAttribute = white;
|
|
||||||
}
|
}
|
||||||
_input._hadColorAttribute = hasColorAttribute;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manage Activation what was and what is expected now
|
// Manage Activation what was and what is expected now
|
||||||
|
@ -253,6 +253,9 @@ void GLBackend::updateInput() {
|
||||||
_stats._ISNumFormatChanges++;
|
_stats._ISNumFormatChanges++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_input._hadColorAttribute = hasColorAttribute;
|
||||||
|
_input._hasColorAttribute = false;
|
||||||
|
|
||||||
if (_input._invalidBuffers.any()) {
|
if (_input._invalidBuffers.any()) {
|
||||||
auto vbo = _input._bufferVBOs.data();
|
auto vbo = _input._bufferVBOs.data();
|
||||||
auto offset = _input._bufferOffsets.data();
|
auto offset = _input._bufferOffsets.data();
|
||||||
|
@ -276,4 +279,3 @@ void GLBackend::updateInput() {
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ void GL41Backend::updateInput() {
|
||||||
#endif
|
#endif
|
||||||
_input._lastUpdateStereoState = isStereoNow;
|
_input._lastUpdateStereoState = isStereoNow;
|
||||||
|
|
||||||
|
bool hasColorAttribute = _input._hasColorAttribute;
|
||||||
|
|
||||||
if (_input._invalidFormat || _input._invalidBuffers.any()) {
|
if (_input._invalidFormat || _input._invalidBuffers.any()) {
|
||||||
|
|
||||||
auto format = acquire(_input._format);
|
auto format = acquire(_input._format);
|
||||||
|
@ -71,8 +73,6 @@ void GL41Backend::updateInput() {
|
||||||
|
|
||||||
// now we need to bind the buffers and assign the attrib pointers
|
// now we need to bind the buffers and assign the attrib pointers
|
||||||
if (format) {
|
if (format) {
|
||||||
bool hasColorAttribute{ false };
|
|
||||||
|
|
||||||
const auto& buffers = _input._buffers;
|
const auto& buffers = _input._buffers;
|
||||||
const auto& offsets = _input._bufferOffsets;
|
const auto& offsets = _input._bufferOffsets;
|
||||||
const auto& strides = _input._bufferStrides;
|
const auto& strides = _input._bufferStrides;
|
||||||
|
@ -110,7 +110,7 @@ void GL41Backend::updateInput() {
|
||||||
uintptr_t pointer = (uintptr_t)(attrib._offset + offsets[bufferNum]);
|
uintptr_t pointer = (uintptr_t)(attrib._offset + offsets[bufferNum]);
|
||||||
GLboolean isNormalized = attrib._element.isNormalized();
|
GLboolean isNormalized = attrib._element.isNormalized();
|
||||||
|
|
||||||
hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR);
|
hasColorAttribute |= slot == Stream::COLOR;
|
||||||
|
|
||||||
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
|
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
|
||||||
if (attrib._element.isInteger()) {
|
if (attrib._element.isInteger()) {
|
||||||
|
@ -132,17 +132,16 @@ void GL41Backend::updateInput() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_input._hadColorAttribute && !hasColorAttribute) {
|
if (!hasColorAttribute && _input._hadColorAttribute) {
|
||||||
// The previous input stage had a color attribute but this one doesn't so reset
|
// The previous input stage had a color attribute but this one doesn't, so reset the color to pure white.
|
||||||
// color to pure white.
|
_input._colorAttribute = glm::vec4(1.0f);
|
||||||
const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
glVertexAttrib4fv(Stream::COLOR, &_input._colorAttribute.r);
|
||||||
glVertexAttrib4fv(Stream::COLOR, &white.r);
|
|
||||||
_input._colorAttribute = white;
|
|
||||||
}
|
}
|
||||||
_input._hadColorAttribute = hasColorAttribute;
|
|
||||||
}
|
}
|
||||||
// everything format related should be in sync now
|
// everything format related should be in sync now
|
||||||
_input._invalidFormat = false;
|
_input._invalidFormat = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
_input._hadColorAttribute = hasColorAttribute;
|
||||||
|
_input._hasColorAttribute = false;
|
||||||
|
}
|
||||||
|
|
|
@ -35,14 +35,14 @@ void GL45Backend::updateInput() {
|
||||||
#endif
|
#endif
|
||||||
_input._lastUpdateStereoState = isStereoNow;
|
_input._lastUpdateStereoState = isStereoNow;
|
||||||
|
|
||||||
|
bool hasColorAttribute = _input._hasColorAttribute;
|
||||||
|
|
||||||
if (_input._invalidFormat) {
|
if (_input._invalidFormat) {
|
||||||
InputStageState::ActivationCache newActivation;
|
InputStageState::ActivationCache newActivation;
|
||||||
|
|
||||||
// Assign the vertex format required
|
// Assign the vertex format required
|
||||||
auto format = acquire(_input._format);
|
auto format = acquire(_input._format);
|
||||||
if (format) {
|
if (format) {
|
||||||
bool hasColorAttribute{ false };
|
|
||||||
|
|
||||||
_input._attribBindingBuffers.reset();
|
_input._attribBindingBuffers.reset();
|
||||||
|
|
||||||
const auto& attributes = format->getAttributes();
|
const auto& attributes = format->getAttributes();
|
||||||
|
@ -61,12 +61,12 @@ void GL45Backend::updateInput() {
|
||||||
uint8_t locationCount = attrib._element.getLocationCount();
|
uint8_t locationCount = attrib._element.getLocationCount();
|
||||||
GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()];
|
GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()];
|
||||||
|
|
||||||
GLuint offset = (GLuint)attrib._offset;;
|
GLuint offset = (GLuint)attrib._offset;
|
||||||
GLboolean isNormalized = attrib._element.isNormalized();
|
GLboolean isNormalized = attrib._element.isNormalized();
|
||||||
|
|
||||||
GLenum perLocationSize = attrib._element.getLocationSize();
|
GLenum perLocationSize = attrib._element.getLocationSize();
|
||||||
|
|
||||||
hasColorAttribute = hasColorAttribute || (slot == Stream::COLOR);
|
hasColorAttribute |= slot == Stream::COLOR;
|
||||||
|
|
||||||
for (GLuint locNum = 0; locNum < locationCount; ++locNum) {
|
for (GLuint locNum = 0; locNum < locationCount; ++locNum) {
|
||||||
GLuint attriNum = (GLuint)(slot + locNum);
|
GLuint attriNum = (GLuint)(slot + locNum);
|
||||||
|
@ -99,14 +99,11 @@ void GL45Backend::updateInput() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_input._hadColorAttribute && !hasColorAttribute) {
|
if (!hasColorAttribute && _input._hadColorAttribute) {
|
||||||
// The previous input stage had a color attribute but this one doesn't so reset
|
// The previous input stage had a color attribute but this one doesn't, so reset the color to pure white.
|
||||||
// color to pure white.
|
_input._colorAttribute = glm::vec4(1.0f);
|
||||||
const auto white = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
glVertexAttrib4fv(Stream::COLOR, &_input._colorAttribute.r);
|
||||||
glVertexAttrib4fv(Stream::COLOR, &white.r);
|
|
||||||
_input._colorAttribute = white;
|
|
||||||
}
|
}
|
||||||
_input._hadColorAttribute = hasColorAttribute;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manage Activation what was and what is expected now
|
// Manage Activation what was and what is expected now
|
||||||
|
@ -128,6 +125,9 @@ void GL45Backend::updateInput() {
|
||||||
_stats._ISNumFormatChanges++;
|
_stats._ISNumFormatChanges++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_input._hadColorAttribute = hasColorAttribute;
|
||||||
|
_input._hasColorAttribute = false;
|
||||||
|
|
||||||
if (_input._invalidBuffers.any()) {
|
if (_input._invalidBuffers.any()) {
|
||||||
auto vbo = _input._bufferVBOs.data();
|
auto vbo = _input._bufferVBOs.data();
|
||||||
auto offset = _input._bufferOffsets.data();
|
auto offset = _input._bufferOffsets.data();
|
||||||
|
|
|
@ -821,14 +821,12 @@ void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape) {
|
||||||
|
|
||||||
void GeometryCache::renderShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) {
|
void GeometryCache::renderShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) {
|
||||||
batch.setInputFormat(getSolidStreamFormat());
|
batch.setInputFormat(getSolidStreamFormat());
|
||||||
// Color must be set after input format
|
|
||||||
batch._glColor4f(color.r, color.g, color.b, color.a);
|
batch._glColor4f(color.r, color.g, color.b, color.a);
|
||||||
_shapes[shape].draw(batch);
|
_shapes[shape].draw(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) {
|
void GeometryCache::renderWireShape(gpu::Batch& batch, Shape shape, const glm::vec4& color) {
|
||||||
batch.setInputFormat(getWireStreamFormat());
|
batch.setInputFormat(getWireStreamFormat());
|
||||||
// Color must be set after input format
|
|
||||||
batch._glColor4f(color.r, color.g, color.b, color.a);
|
batch._glColor4f(color.r, color.g, color.b, color.a);
|
||||||
_shapes[shape].drawWire(batch);
|
_shapes[shape].drawWire(batch);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue