mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 16:41:02 +02:00
Merge pull request #5256 from Atlante45/fix_billboard
Fix display name z-fighting
This commit is contained in:
commit
3842e748b5
6 changed files with 117 additions and 63 deletions
|
@ -750,7 +750,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co
|
||||||
const int text_y = -nameDynamicRect.height() / 2;
|
const int text_y = -nameDynamicRect.height() / 2;
|
||||||
|
|
||||||
// Compute background position/size
|
// Compute background position/size
|
||||||
static const float SLIGHTLY_BEHIND = -0.05f;
|
static const float SLIGHTLY_IN_FRONT = 0.1f;
|
||||||
const int border = 0.1f * nameDynamicRect.height();
|
const int border = 0.1f * nameDynamicRect.height();
|
||||||
const int left = text_x - border;
|
const int left = text_x - border;
|
||||||
const int bottom = text_y - border;
|
const int bottom = text_y - border;
|
||||||
|
@ -765,16 +765,16 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum) co
|
||||||
|
|
||||||
// Compute display name transform
|
// Compute display name transform
|
||||||
auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize());
|
auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize());
|
||||||
|
batch.setModelTransform(textTransform);
|
||||||
// Render background slightly behind to avoid z-fighting
|
|
||||||
auto backgroundTransform = textTransform;
|
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, true, true, true);
|
||||||
backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_BEHIND));
|
|
||||||
batch.setModelTransform(backgroundTransform);
|
|
||||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
|
|
||||||
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
|
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
|
||||||
bevelDistance, backgroundColor);
|
bevelDistance, backgroundColor);
|
||||||
// Render actual name
|
// Render actual name
|
||||||
QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
|
QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
|
||||||
|
|
||||||
|
// Render text slightly in front to avoid z-fighting
|
||||||
|
textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT * renderer->getFontSize()));
|
||||||
batch.setModelTransform(textTransform);
|
batch.setModelTransform(textTransform);
|
||||||
renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor);
|
renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "Text3DOverlay.h"
|
#include "Text3DOverlay.h"
|
||||||
|
|
||||||
|
#include <DeferredLightingEffect.h>
|
||||||
#include <RenderDeferredTask.h>
|
#include <RenderDeferredTask.h>
|
||||||
#include <TextRenderer3D.h>
|
#include <TextRenderer3D.h>
|
||||||
|
|
||||||
|
@ -114,6 +115,7 @@ void Text3DOverlay::render(RenderArgs* args) {
|
||||||
|
|
||||||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
|
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
|
||||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
|
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
|
||||||
|
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, true, false, true);
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor);
|
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor);
|
||||||
|
|
||||||
// Same font properties as textSize()
|
// Same font properties as textSize()
|
||||||
|
|
|
@ -36,10 +36,6 @@ void RenderableTextEntityItem::render(RenderArgs* args) {
|
||||||
glm::vec4 backgroundColor = glm::vec4(toGlm(getBackgroundColorX()), 1.0f);
|
glm::vec4 backgroundColor = glm::vec4(toGlm(getBackgroundColorX()), 1.0f);
|
||||||
glm::vec3 dimensions = getDimensions();
|
glm::vec3 dimensions = getDimensions();
|
||||||
|
|
||||||
Transform transformToTopLeft = getTransformToCenter();
|
|
||||||
transformToTopLeft.postTranslate(glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left
|
|
||||||
transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed
|
|
||||||
|
|
||||||
// Render background
|
// Render background
|
||||||
glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, SLIGHTLY_BEHIND);
|
glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, SLIGHTLY_BEHIND);
|
||||||
glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, SLIGHTLY_BEHIND);
|
glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, SLIGHTLY_BEHIND);
|
||||||
|
@ -48,15 +44,22 @@ void RenderableTextEntityItem::render(RenderArgs* args) {
|
||||||
// Batch render calls
|
// Batch render calls
|
||||||
Q_ASSERT(args->_batch);
|
Q_ASSERT(args->_batch);
|
||||||
gpu::Batch& batch = *args->_batch;
|
gpu::Batch& batch = *args->_batch;
|
||||||
|
|
||||||
|
Transform transformToTopLeft = getTransformToCenter();
|
||||||
|
if (getFaceCamera()) {
|
||||||
|
//rotate about vertical to face the camera
|
||||||
|
glm::vec3 dPosition = args->_viewFrustum->getPosition() - getPosition();
|
||||||
|
// If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
|
||||||
|
float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
|
||||||
|
glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
|
||||||
|
transformToTopLeft.setRotation(orientation);
|
||||||
|
}
|
||||||
|
transformToTopLeft.postTranslate(glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left
|
||||||
|
transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed
|
||||||
|
|
||||||
batch.setModelTransform(transformToTopLeft);
|
batch.setModelTransform(transformToTopLeft);
|
||||||
|
|
||||||
//rotate about vertical to face the camera
|
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, false, false, true);
|
||||||
if (getFaceCamera()) {
|
|
||||||
transformToTopLeft.postRotate(args->_viewFrustum->getOrientation());
|
|
||||||
batch.setModelTransform(transformToTopLeft);
|
|
||||||
}
|
|
||||||
|
|
||||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, false);
|
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, minCorner, maxCorner, backgroundColor);
|
DependencyManager::get<GeometryCache>()->renderQuad(batch, minCorner, maxCorner, backgroundColor);
|
||||||
|
|
||||||
float scale = _lineHeight / _textRenderer->getFontSize();
|
float scale = _lineHeight / _textRenderer->getFontSize();
|
||||||
|
|
|
@ -589,7 +589,7 @@ void GLBackend::do_setStateAntialiasedLineEnable(bool enable) {
|
||||||
|
|
||||||
void GLBackend::do_setStateDepthBias(Vec2 bias) {
|
void GLBackend::do_setStateDepthBias(Vec2 bias) {
|
||||||
if ( (bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) {
|
if ( (bias.x != _pipeline._stateCache.depthBias) || (bias.y != _pipeline._stateCache.depthBiasSlopeScale)) {
|
||||||
if ((bias.x != 0.f) || (bias.y != 0.f)) {
|
if ((bias.x != 0.0f) || (bias.y != 0.0f)) {
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
glEnable(GL_POLYGON_OFFSET_LINE);
|
glEnable(GL_POLYGON_OFFSET_LINE);
|
||||||
glEnable(GL_POLYGON_OFFSET_POINT);
|
glEnable(GL_POLYGON_OFFSET_POINT);
|
||||||
|
|
|
@ -50,37 +50,44 @@
|
||||||
|
|
||||||
static const std::string glowIntensityShaderHandle = "glowIntensity";
|
static const std::string glowIntensityShaderHandle = "glowIntensity";
|
||||||
|
|
||||||
|
gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config) {
|
||||||
|
auto it = _simplePrograms.find(config);
|
||||||
|
if (it != _simplePrograms.end()) {
|
||||||
|
return it.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
|
if (config.isCulled()) {
|
||||||
|
state->setCullMode(gpu::State::CULL_BACK);
|
||||||
|
} else {
|
||||||
|
state->setCullMode(gpu::State::CULL_NONE);
|
||||||
|
}
|
||||||
|
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||||
|
if (config.hasDepthBias()) {
|
||||||
|
state->setDepthBias(1.0f);
|
||||||
|
state->setDepthBiasSlopeScale(1.0f);
|
||||||
|
}
|
||||||
|
state->setBlendFunction(false,
|
||||||
|
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||||
|
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||||
|
|
||||||
|
gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
|
||||||
|
gpu::PipelinePointer pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
|
||||||
|
_simplePrograms.insert(config, pipeline);
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
||||||
auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert)));
|
auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert)));
|
||||||
auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag)));
|
auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag)));
|
||||||
auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag)));
|
auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag)));
|
||||||
|
|
||||||
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS));
|
_simpleShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS));
|
||||||
gpu::ShaderPointer programEmissive = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive));
|
_emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive));
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
gpu::Shader::BindingSet slotBindings;
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
|
||||||
gpu::Shader::makeProgram(*programEmissive, slotBindings);
|
gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
|
||||||
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
|
||||||
state->setCullMode(gpu::State::CULL_BACK);
|
|
||||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
|
||||||
state->setBlendFunction(false,
|
|
||||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
|
||||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
|
||||||
|
|
||||||
|
|
||||||
gpu::StatePointer stateCullNone = gpu::StatePointer(new gpu::State());
|
|
||||||
stateCullNone->setCullMode(gpu::State::CULL_NONE);
|
|
||||||
stateCullNone->setDepthTest(true, true, gpu::LESS_EQUAL);
|
|
||||||
stateCullNone->setBlendFunction(false,
|
|
||||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
|
||||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
|
||||||
|
|
||||||
_simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
|
|
||||||
_simpleProgramCullNone = gpu::PipelinePointer(gpu::Pipeline::create(program, stateCullNone));
|
|
||||||
_simpleProgramEmissive = gpu::PipelinePointer(gpu::Pipeline::create(programEmissive, state));
|
|
||||||
_simpleProgramEmissiveCullNone = gpu::PipelinePointer(gpu::Pipeline::create(programEmissive, stateCullNone));
|
|
||||||
|
|
||||||
_viewState = viewState;
|
_viewState = viewState;
|
||||||
loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations);
|
loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations);
|
||||||
|
@ -117,21 +124,12 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
||||||
lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET));
|
lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool emmisive) {
|
void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled,
|
||||||
if (emmisive) {
|
bool emmisive, bool depthBias) {
|
||||||
if (culled) {
|
SimpleProgramKey config{textured, culled, emmisive, depthBias};
|
||||||
batch.setPipeline(_simpleProgramEmissive);
|
batch.setPipeline(getPipeline(config));
|
||||||
} else {
|
|
||||||
batch.setPipeline(_simpleProgramEmissiveCullNone);
|
if (!config.isTextured()) {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (culled) {
|
|
||||||
batch.setPipeline(_simpleProgram);
|
|
||||||
} else {
|
|
||||||
batch.setPipeline(_simpleProgramCullNone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!textured) {
|
|
||||||
// If it is not textured, bind white texture and keep using textured pipeline
|
// If it is not textured, bind white texture and keep using textured pipeline
|
||||||
batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
class AbstractViewStateInterface;
|
class AbstractViewStateInterface;
|
||||||
class RenderArgs;
|
class RenderArgs;
|
||||||
|
class SimpleProgramKey;
|
||||||
|
|
||||||
/// Handles deferred lighting for the bits that require it (voxels...)
|
/// Handles deferred lighting for the bits that require it (voxels...)
|
||||||
class DeferredLightingEffect : public Dependency {
|
class DeferredLightingEffect : public Dependency {
|
||||||
|
@ -34,7 +35,8 @@ public:
|
||||||
void init(AbstractViewStateInterface* viewState);
|
void init(AbstractViewStateInterface* viewState);
|
||||||
|
|
||||||
/// Sets up the state necessary to render static untextured geometry with the simple program.
|
/// Sets up the state necessary to render static untextured geometry with the simple program.
|
||||||
void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, bool emmisive = false);
|
void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
|
||||||
|
bool emmisive = false, bool depthBias = false);
|
||||||
|
|
||||||
//// Renders a solid sphere with the simple program.
|
//// Renders a solid sphere with the simple program.
|
||||||
void renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color);
|
void renderSolidSphere(gpu::Batch& batch, float radius, int slices, int stacks, const glm::vec4& color);
|
||||||
|
@ -95,11 +97,11 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);
|
static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);
|
||||||
|
gpu::PipelinePointer getPipeline(SimpleProgramKey config);
|
||||||
|
|
||||||
gpu::PipelinePointer _simpleProgram;
|
gpu::ShaderPointer _simpleShader;
|
||||||
gpu::PipelinePointer _simpleProgramCullNone;
|
gpu::ShaderPointer _emissiveShader;
|
||||||
gpu::PipelinePointer _simpleProgramEmissive;
|
QHash<SimpleProgramKey, gpu::PipelinePointer> _simplePrograms;
|
||||||
gpu::PipelinePointer _simpleProgramEmissiveCullNone;
|
|
||||||
|
|
||||||
ProgramObject _directionalSkyboxLight;
|
ProgramObject _directionalSkyboxLight;
|
||||||
LightLocations _directionalSkyboxLightLocations;
|
LightLocations _directionalSkyboxLightLocations;
|
||||||
|
@ -160,4 +162,53 @@ private:
|
||||||
model::SkyboxPointer _skybox;
|
model::SkyboxPointer _skybox;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SimpleProgramKey {
|
||||||
|
public:
|
||||||
|
enum FlagBit {
|
||||||
|
IS_TEXTURED_FLAG = 0,
|
||||||
|
IS_CULLED_FLAG,
|
||||||
|
IS_EMISSIVE_FLAG,
|
||||||
|
HAS_DEPTH_BIAS_FLAG,
|
||||||
|
|
||||||
|
NUM_FLAGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Flag {
|
||||||
|
IS_TEXTURED = (1 << IS_TEXTURED_FLAG),
|
||||||
|
IS_CULLED = (1 << IS_CULLED_FLAG),
|
||||||
|
IS_EMISSIVE = (1 << IS_EMISSIVE_FLAG),
|
||||||
|
HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG),
|
||||||
|
};
|
||||||
|
typedef unsigned short Flags;
|
||||||
|
|
||||||
|
bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); }
|
||||||
|
|
||||||
|
bool isTextured() const { return isFlag(IS_TEXTURED); }
|
||||||
|
bool isCulled() const { return isFlag(IS_CULLED); }
|
||||||
|
bool isEmissive() const { return isFlag(IS_EMISSIVE); }
|
||||||
|
bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); }
|
||||||
|
|
||||||
|
Flags _flags = 0;
|
||||||
|
short _spare = 0;
|
||||||
|
|
||||||
|
int getRaw() const { return *reinterpret_cast<const int*>(this); }
|
||||||
|
|
||||||
|
|
||||||
|
SimpleProgramKey(bool textured = false, bool culled = true,
|
||||||
|
bool emissive = false, bool depthBias = false) {
|
||||||
|
_flags = (textured ? IS_TEXTURED : 0) | (culled ? IS_CULLED : 0) |
|
||||||
|
(emissive ? IS_EMISSIVE : 0) | (depthBias ? HAS_DEPTH_BIAS : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleProgramKey(int bitmask) : _flags(bitmask) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline uint qHash(const SimpleProgramKey& key, uint seed) {
|
||||||
|
return qHash(key.getRaw(), seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) {
|
||||||
|
return a.getRaw() == b.getRaw();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // hifi_DeferredLightingEffect_h
|
#endif // hifi_DeferredLightingEffect_h
|
||||||
|
|
Loading…
Reference in a new issue