SL-17532 Potential fix for some rigged mesh draw order issues.
parent
0fe8493b5a
commit
616f2b639b
|
|
@ -202,7 +202,7 @@ VARYING vec2 vary_texcoord2;
|
|||
uniform float env_intensity;
|
||||
uniform vec4 specular_color; // specular color RGB and specular exponent (glossiness) in alpha
|
||||
|
||||
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK)
|
||||
#ifdef HAS_ALPHA_MASK
|
||||
uniform float minimum_alpha;
|
||||
#endif
|
||||
|
||||
|
|
@ -227,11 +227,12 @@ void main()
|
|||
vec4 diffcol = texture2D(diffuseMap, vary_texcoord0.xy);
|
||||
diffcol.rgb *= vertex_color.rgb;
|
||||
|
||||
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK)
|
||||
|
||||
// Comparing floats cast from 8-bit values, produces acne right at the 8-bit transition points
|
||||
float bias = 0.001953125; // 1/512, or half an 8-bit quantization
|
||||
if (diffcol.a < minimum_alpha-bias)
|
||||
#ifdef HAS_ALPHA_MASK
|
||||
#if DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND
|
||||
if (diffcol.a*vertex_color.a < minimum_alpha)
|
||||
#else
|
||||
if (diffcol.a < minimum_alpha)
|
||||
#endif
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ public:
|
|||
inline LLFace* getFace(const S32 i) const;
|
||||
inline S32 getNumFaces() const;
|
||||
face_list_t& getFaces() { return mFaces; }
|
||||
const face_list_t& getFaces() const { return mFaces; }
|
||||
|
||||
//void removeFace(const S32 i); // SJB: Avoid using this, it's slow
|
||||
LLFace* addFace(LLFacePool *poolp, LLViewerTexture *texturep);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@
|
|||
#include "llglcommonfunc.h"
|
||||
#include "llvoavatar.h"
|
||||
|
||||
#pragma optimize("", off)
|
||||
|
||||
BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
|
||||
|
||||
#define current_shader (LLGLSLShader::sCurBoundShaderPtr)
|
||||
|
|
@ -58,8 +60,11 @@ static BOOL deferred_render = FALSE;
|
|||
|
||||
// minimum alpha before discarding a fragment
|
||||
static const F32 MINIMUM_ALPHA = 0.004f; // ~ 1/255
|
||||
static const F32 MINIMUM_RIGGED_ALPHA = MINIMUM_ALPHA;
|
||||
|
||||
// minimum alpha before discarding a fragment when rendering impostors
|
||||
static const F32 MINIMUM_IMPOSTOR_ALPHA = 0.1f;
|
||||
static const F32 MINIMUM_IMPOSTOR_RIGGED_ALPHA = 0.1f;
|
||||
|
||||
LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
|
||||
LLRenderPass(type), target_shader(NULL),
|
||||
|
|
@ -111,11 +116,25 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d
|
|||
|
||||
if (LLPipeline::sImpostorRender)
|
||||
{
|
||||
shader->setMinimumAlpha(MINIMUM_IMPOSTOR_ALPHA);
|
||||
if (shader->mRiggedVariant == shader)
|
||||
{
|
||||
shader->setMinimumAlpha(MINIMUM_IMPOSTOR_RIGGED_ALPHA);
|
||||
}
|
||||
else
|
||||
{
|
||||
shader->setMinimumAlpha(MINIMUM_IMPOSTOR_ALPHA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shader->setMinimumAlpha(MINIMUM_ALPHA);
|
||||
if (shader->mRiggedVariant == shader)
|
||||
{
|
||||
shader->setMinimumAlpha(MINIMUM_RIGGED_ALPHA);
|
||||
}
|
||||
else
|
||||
{
|
||||
shader->setMinimumAlpha(MINIMUM_ALPHA);
|
||||
}
|
||||
}
|
||||
if (textureGamma)
|
||||
{
|
||||
|
|
@ -147,6 +166,10 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
|
|||
(LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
|
||||
prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms)
|
||||
|
||||
for (int i = 0; i < LLMaterial::SHADER_COUNT; ++i)
|
||||
{
|
||||
prepare_alpha_shader(LLPipeline::sUnderWaterRender ? &gDeferredMaterialWaterProgram[i] : &gDeferredMaterialProgram[i], false, false); // note: bindDeferredShader will get called during render loop for materials
|
||||
}
|
||||
|
||||
// first pass, render rigged objects only and render to depth buffer
|
||||
forwardRender(true);
|
||||
|
|
@ -184,7 +207,7 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
|
|||
}
|
||||
|
||||
//set some generic parameters for forward (non-deferred) rendering
|
||||
static void prepare_forward_shader(LLGLSLShader* shader, F32 minimum_alpha)
|
||||
static void prepare_forward_shader(LLGLSLShader* shader, F32 minimum_alpha, F32 minimum_rigged_alpha)
|
||||
{
|
||||
shader->bind();
|
||||
shader->setMinimumAlpha(minimum_alpha);
|
||||
|
|
@ -193,7 +216,7 @@ static void prepare_forward_shader(LLGLSLShader* shader, F32 minimum_alpha)
|
|||
//also prepare rigged variant
|
||||
if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
|
||||
{
|
||||
prepare_forward_shader(shader->mRiggedVariant, minimum_alpha);
|
||||
prepare_forward_shader(shader->mRiggedVariant, minimum_rigged_alpha, minimum_rigged_alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,12 +234,20 @@ void LLDrawPoolAlpha::render(S32 pass)
|
|||
(LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
|
||||
|
||||
F32 minimum_alpha = MINIMUM_ALPHA;
|
||||
F32 minimum_rigged_alpha = MINIMUM_RIGGED_ALPHA;
|
||||
if (LLPipeline::sImpostorRender)
|
||||
{
|
||||
minimum_alpha = MINIMUM_IMPOSTOR_ALPHA;
|
||||
minimum_rigged_alpha = MINIMUM_IMPOSTOR_RIGGED_ALPHA;
|
||||
}
|
||||
|
||||
prepare_forward_shader(fullbright_shader, minimum_alpha, minimum_rigged_alpha);
|
||||
prepare_forward_shader(simple_shader, minimum_alpha, minimum_rigged_alpha);
|
||||
|
||||
for (int i = 0; i < LLMaterial::SHADER_COUNT; ++i)
|
||||
{
|
||||
prepare_forward_shader(LLPipeline::sUnderWaterRender ? &gDeferredMaterialWaterProgram[i] : &gDeferredMaterialProgram[i], minimum_alpha, minimum_rigged_alpha);
|
||||
}
|
||||
prepare_forward_shader(fullbright_shader, minimum_alpha);
|
||||
prepare_forward_shader(simple_shader, minimum_alpha);
|
||||
|
||||
//first pass -- rigged only and drawn to depth buffer
|
||||
forwardRender(true);
|
||||
|
|
|
|||
|
|
@ -1567,6 +1567,62 @@ void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
|
|||
}
|
||||
}
|
||||
|
||||
// return false if drawable is rigged and:
|
||||
// - a linked rigged drawable has a different spatial group
|
||||
// - a linked rigged drawable face has the wrong draw order index
|
||||
bool check_rigged_group(LLDrawable* drawable)
|
||||
{
|
||||
if (drawable->isState(LLDrawable::RIGGED))
|
||||
{
|
||||
LLSpatialGroup* group = drawable->getSpatialGroup();
|
||||
LLDrawable* root = drawable->getRoot();
|
||||
|
||||
if (root->isState(LLDrawable::RIGGED) && root->getSpatialGroup() != group)
|
||||
{
|
||||
llassert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
S32 last_draw_index = -1;
|
||||
if (root->isState(LLDrawable::RIGGED))
|
||||
{
|
||||
for (auto& face : root->getFaces())
|
||||
{
|
||||
if ((S32) face->getDrawOrderIndex() <= last_draw_index)
|
||||
{
|
||||
llassert(false);
|
||||
return false;
|
||||
}
|
||||
last_draw_index = face->getDrawOrderIndex();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& child : root->getVObj()->getChildren())
|
||||
{
|
||||
if (child->mDrawable->isState(LLDrawable::RIGGED))
|
||||
{
|
||||
for (auto& face : child->mDrawable->getFaces())
|
||||
{
|
||||
if ((S32) face->getDrawOrderIndex() <= last_draw_index)
|
||||
{
|
||||
llassert(false);
|
||||
return false;
|
||||
}
|
||||
last_draw_index = face->getDrawOrderIndex();
|
||||
}
|
||||
}
|
||||
|
||||
if (child->mDrawable->getSpatialGroup() != group)
|
||||
{
|
||||
llassert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void renderOctree(LLSpatialGroup* group)
|
||||
{
|
||||
//render solid object bounding box, color
|
||||
|
|
@ -1611,6 +1667,9 @@ void renderOctree(LLSpatialGroup* group)
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
llassert(check_rigged_group(drawable));
|
||||
|
||||
if (!group->getSpatialPartition()->isBridge())
|
||||
{
|
||||
gGL.pushMatrix();
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ public:
|
|||
return lhs->mAvatarp < rhs->mAvatarp;
|
||||
}
|
||||
|
||||
return lhs->mRenderOrder > rhs->mRenderOrder;
|
||||
return lhs->mRenderOrder < rhs->mRenderOrder;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1484,6 +1484,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
|
|||
|
||||
gDeferredMaterialProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
|
||||
|
||||
if (alpha_mode != 0)
|
||||
{
|
||||
gDeferredMaterialProgram[i].mFeatures.hasAlphaMask = true;
|
||||
gDeferredMaterialProgram[i].addPermutation("HAS_ALPHA_MASK", "1");
|
||||
}
|
||||
|
||||
if (use_sun_shadow)
|
||||
{
|
||||
gDeferredMaterialProgram[i].addPermutation("HAS_SUN_SHADOW", "1");
|
||||
|
|
@ -1542,6 +1548,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
|
|||
}
|
||||
|
||||
gDeferredMaterialWaterProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
|
||||
if (alpha_mode != 0)
|
||||
{
|
||||
gDeferredMaterialWaterProgram[i].mFeatures.hasAlphaMask = true;
|
||||
gDeferredMaterialWaterProgram[i].addPermutation("HAS_ALPHA_MASK", "1");
|
||||
}
|
||||
|
||||
if (use_sun_shadow)
|
||||
{
|
||||
gDeferredMaterialWaterProgram[i].addPermutation("HAS_SUN_SHADOW", "1");
|
||||
|
|
|
|||
|
|
@ -5480,7 +5480,7 @@ static inline void add_face(T*** list, U32* count, T* face)
|
|||
{
|
||||
if (count[1] < MAX_FACE_COUNT)
|
||||
{
|
||||
face->setDrawOrderIndex(count[1]);
|
||||
//face->setDrawOrderIndex(count[1]);
|
||||
list[1][count[1]++] = face;
|
||||
}
|
||||
}
|
||||
|
|
@ -5488,15 +5488,40 @@ static inline void add_face(T*** list, U32* count, T* face)
|
|||
{
|
||||
if (count[0] < MAX_FACE_COUNT)
|
||||
{
|
||||
face->setDrawOrderIndex(count[0]);
|
||||
//face->setDrawOrderIndex(count[0]);
|
||||
list[0][count[0]++] = face;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return index into linkset for given object (0 for root prim)
|
||||
U32 get_linkset_index(LLVOVolume* vobj)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
|
||||
if (vobj->isRootEdit())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLViewerObject* root = vobj->getRootEdit();
|
||||
U32 idx = 1;
|
||||
for (auto& child : root->getChildren())
|
||||
{
|
||||
if (child == vobj)
|
||||
{
|
||||
return idx;
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
|
||||
llassert(false);
|
||||
return idx; //should never get here
|
||||
}
|
||||
|
||||
void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
|
||||
|
||||
if (group->changeLOD())
|
||||
{
|
||||
group->mLastUpdateDistance = group->mDistance;
|
||||
|
|
@ -5655,6 +5680,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
|||
avatar->addAttachmentOverridesForObject(vobj, NULL, false);
|
||||
}
|
||||
|
||||
U32 linkset_index = get_linkset_index(vobj);
|
||||
|
||||
// Standard rigged mesh attachments:
|
||||
bool rigged = !vobj->isAnimatedObject() && skinInfo && vobj->isAttachment();
|
||||
// Animated objects. Have to check for isRiggedMesh() to
|
||||
|
|
@ -5674,6 +5701,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
|||
continue;
|
||||
}
|
||||
|
||||
// order by linkset index first and face index second
|
||||
facep->setDrawOrderIndex(linkset_index * 100 + i);
|
||||
|
||||
//ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
|
||||
// batch, it will recover its vertex buffer reference from the spatial group
|
||||
facep->setVertexBuffer(NULL);
|
||||
|
|
@ -5698,11 +5728,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
|||
if (facep->isState(LLFace::RIGGED))
|
||||
{
|
||||
//face is not rigged but used to be, remove from rigged face pool
|
||||
LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
|
||||
if (pool)
|
||||
{
|
||||
pool->removeFace(facep);
|
||||
}
|
||||
facep->clearState(LLFace::RIGGED);
|
||||
facep->mAvatar = NULL;
|
||||
facep->mSkinInfo = NULL;
|
||||
|
|
@ -6158,6 +6183,13 @@ struct CompareBatchBreakerRigged
|
|||
}
|
||||
};
|
||||
|
||||
struct CompareDrawOrder
|
||||
{
|
||||
bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
|
||||
{
|
||||
return lhs->getDrawOrderIndex() < rhs->getDrawOrderIndex();
|
||||
}
|
||||
};
|
||||
|
||||
U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL rigged)
|
||||
{
|
||||
|
|
@ -6202,6 +6234,11 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
|
|||
//sort faces by things that break batches, including avatar and mesh id
|
||||
std::sort(faces, faces + face_count, CompareBatchBreakerRigged());
|
||||
}
|
||||
else
|
||||
{
|
||||
// preserve legacy draw order for rigged faces
|
||||
std::sort(faces, faces + face_count, CompareDrawOrder());
|
||||
}
|
||||
}
|
||||
else if (!distance_sort)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue