secondlife/viewer#2421: Do not calculate and store silhouette edges for nearly every geometric prim with a corner

master
Cosmic Linden 2024-08-28 15:59:03 -07:00
parent 5c16ae1375
commit f23f28c8f9
2 changed files with 246 additions and 184 deletions

View File

@ -2710,7 +2710,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
}
bool LLVolume::isMeshAssetLoaded()
bool LLVolume::isMeshAssetLoaded() const
{
return mIsMeshAssetLoaded;
}
@ -2733,7 +2733,7 @@ void LLVolume::setMeshAssetUnavaliable(bool unavaliable)
}
}
bool LLVolume::isMeshAssetUnavaliable()
bool LLVolume::isMeshAssetUnavaliable() const
{
return mIsMeshAssetUnavaliable;
}
@ -3730,6 +3730,207 @@ S32 LLVolume::getNumTriangles(S32* vcount) const
return triangle_count;
}
void LLVolumeFace::generateSilhouetteEdge(const LLVolume* volume, std::vector<S32>& edge) const
{
llassert(edge.empty()); // edge is supposed to be a scratch array
if (volume->isMeshAssetLoaded()) { return; }
if (mTypeMask & CAP_MASK)
{
// Logic copied from LLVolumeFace::createCap - indicates a face created via
// createUnCutCubeCap.
if (!(mTypeMask & HOLLOW_MASK) &&
!(mTypeMask & OPEN_MASK) &&
((volume->getParams().getPathParams().getBegin()==0.0f)&&
(volume->getParams().getPathParams().getEnd()==1.0f))&&
(volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE &&
volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE)
)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfgse - CAP_MASK");
const LLAlignedArray<LLVector4a,64>& profile = volume->getProfile().mProfile;
S32 grid_size = (profile.size()-1)/4;
edge.resize(mNumIndices);
llassert(edge.size() == 6*grid_size*grid_size);
S32 cur_edge = 0;
for(S32 gx = 0;gx<grid_size;gx++)
{
for(S32 gy = 0;gy<grid_size;gy++)
{
if (mTypeMask & TOP_MASK)
{
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gx > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1; // Mark face to higlight it
}
if (gy < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
if (gx < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
if (gy > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
}
else
{
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gy > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
if (gx < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
if (gy < grid_size - 1)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
if (gx > 0)
{
edge[cur_edge++] = edge_value;
}
else
{
edge[cur_edge++] = -1;
}
edge[cur_edge++] = edge_value;
}
}
}
}
}
else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfgse - END_MASK or SIDE_MASK");
edge.resize(mNumIndices);
llassert(edge.size() == 6*(mNumS-1)*(mNumT-1));
S32 cur_edge = 0;
const bool flat_face = mTypeMask & FLAT_MASK;
for (S32 t = 0; t < (mNumT-1); t++)
{
for (S32 s = 0; s < (mNumS-1); s++)
{
// bottom left/top right neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+s*2+1;
if (t < mNumT-2)
{ // top right/top left neighbor face
edge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on T
edge[cur_edge++] = s*2+1;
}
if (s > 0)
{ // top left/bottom left neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on S
edge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
}
if (t > 0)
{ // bottom left/bottom right neighbor face
edge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on T
edge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
}
if (s < mNumS-2)
{ // bottom right/top right neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
edge[cur_edge++] = -1;
}
else
{ // wrap on S
edge[cur_edge++] = (mNumS-1)*2*t;
}
// top right/bottom left neighbor face
edge[cur_edge++] = (mNumS-1)*2*t+s*2;
}
}
}
else
{
LL_ERRS() << "Unknown/uninitialized face type!" << LL_ENDL;
}
}
//-----------------------------------------------------------------------------
// generateSilhouetteVertices()
@ -3761,6 +3962,13 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
}
S32 cur_index = 0;
// Scratch array for per-face silhouette edge information. This also has a
// lot of dev-only debug information that we might not care about anymore.
// (see DEBUG_SILHOUETTE_EDGE_MAP)
// *TODO: Consider removing the debug associated with
// DEBUG_SILHOUETTE_EDGE_MAP, and remove its associated computational
// overhead in generateSilhouetteEdge.
std::vector<S32> edge;
//for each face
for (face_list_t::iterator iter = mVolumeFaces.begin();
iter != mVolumeFaces.end(); ++iter)
@ -3768,7 +3976,16 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
LLVolumeFace& face = *iter;
if (!(face_mask & (0x1 << cur_index++)) ||
face.mNumIndices == 0 || face.mEdge.empty())
face.mNumIndices == 0)
{
continue;
}
// Attempt to generate "edge" info for this silhouette, which is used
// for some prims. If the edge array remains empty, then this
// silhouette generation method is not supported for this face.
edge.clear();
face.generateSilhouetteEdge(this, edge);
if (edge.empty())
{
continue;
}
@ -3782,7 +3999,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
{
for (S32 k = 0; k < 3; k++)
{
S32 index = face.mEdge[j * 3 + k];
S32 index = edge[j * 3 + k];
if (index == -1)
{
@ -3834,7 +4051,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
//for each edge
for (S32 k = 0; k < 3; k++) {
S32 nIndex = face.mEdge[j*3+k];
S32 nIndex = edge[j*3+k];
if (nIndex <= -1) {
continue;
}
@ -3949,7 +4166,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
// *FIX IF NEEDED: this does not deal with neighboring degenerate faces
for (S32 k = 0; k < 3; k++)
{
S32 index = face.mEdge[j*3+k];
S32 index = edge[j*3+k];
if (index != -1)
{
fFacing[j] = fFacing[index];
@ -3961,10 +4178,10 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
//for each edge
for (S32 k = 0; k < 3; k++) {
S32 index = face.mEdge[j*3+k];
S32 index = edge[j*3+k];
if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) {
//our neighbor is degenerate, make him face our direction
fFacing[face.mEdge[j*3+k]] = fFacing[j];
fFacing[edge[j*3+k]] = fFacing[j];
continue;
}
@ -5775,30 +5992,16 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build)
if (!partial_build)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcuccm - generate indices");
resizeIndices(grid_size*grid_size*6);
if (!volume->isMeshAssetLoaded())
{
S32 size = grid_size * grid_size * 6;
try
{
mEdge.resize(size);
}
catch (std::bad_alloc&)
{
LL_WARNS("LLVOLUME") << "Resize of mEdge to " << size << " failed" << LL_ENDL;
return false;
}
}
U16* out = mIndices;
S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
int cur_edge = 0;
for(S32 gx = 0;gx<grid_size;gx++)
{
for(S32 gy = 0;gy<grid_size;gy++)
{
if (mTypeMask & TOP_MASK)
@ -5808,47 +6011,6 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build)
*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
}
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gx > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1; // Mark face to higlight it
}
if (gy < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
if (gx < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
if (gy > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
}
else
{
@ -5856,48 +6018,6 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build)
{
*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
}
S32 edge_value = grid_size * 2 * gy + gx * 2;
if (gy > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
if (gx < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
if (gy < grid_size - 1)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
if (gx > 0)
{
mEdge[cur_edge++] = edge_value;
}
else
{
mEdge[cur_edge++] = -1;
}
mEdge[cur_edge++] = edge_value;
}
}
}
@ -6377,6 +6497,8 @@ void LLVolumeFace::createTangents()
void LLVolumeFace::resizeVertices(S32 num_verts)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
ll_aligned_free<64>(mPositions);
//DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
ll_aligned_free_16(mTangents);
@ -6499,6 +6621,8 @@ void LLVolumeFace::allocateJointIndices(S32 num_verts)
void LLVolumeFace::resizeIndices(S32 num_indices)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
ll_aligned_free_16(mIndices);
llassert(num_indices % 3 == 0);
@ -6591,19 +6715,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
{
resizeVertices(num_vertices);
resizeIndices(num_indices);
if (!volume->isMeshAssetLoaded())
{
try
{
mEdge.resize(num_indices);
}
catch (std::bad_alloc&)
{
LL_WARNS("LLVOLUME") << "Resize of mEdge to " << num_indices << " failed" << LL_ENDL;
return false;
}
}
}
LL_CHECK_MEMORY
@ -6618,6 +6729,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
bool test = (mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2;
// Copy the vertices into the array
{ LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcs - copy verts");
for (t = mBeginT; t < end_t; t++)
{
tt = path_data[t].mTexT;
@ -6702,6 +6814,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
cur_vertex++;
}
}
}
LL_CHECK_MEMORY
mCenter->clear();
@ -6755,11 +6868,11 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
mCenter->mul(0.5f);
S32 cur_index = 0;
S32 cur_edge = 0;
bool flat_face = mTypeMask & FLAT_MASK;
if (!partial_build)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcs - generate indices");
// Now we generate the indices.
for (t = 0; t < (mNumT-1); t++)
{
@ -6771,64 +6884,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build)
mIndices[cur_index++] = s + mNumS*t; //bottom left
mIndices[cur_index++] = s+1 + mNumS*t; //bottom right
mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right
// bottom left/top right neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1;
if (t < mNumT-2)
{ // top right/top left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on T
mEdge[cur_edge++] = s*2+1;
}
if (s > 0)
{ // top left/bottom left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on S
mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1;
}
if (t > 0)
{ // bottom left/bottom right neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2;
}
else if (mNumT <= 3 || volume->getPath().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on T
mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2;
}
if (s < mNumS-2)
{ // bottom right/top right neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2;
}
else if (flat_face || volume->getProfile().isOpen())
{ // no neighbor
mEdge[cur_edge++] = -1;
}
else
{ // wrap on S
mEdge[cur_edge++] = (mNumS-1)*2*t;
}
// top right/bottom left neighbor face
mEdge[cur_edge++] = (mNumS-1)*2*t+s*2;
}
}
}

View File

@ -918,6 +918,15 @@ public:
// Get a reference to the octree, which may be null
const LLVolumeOctree* getOctree() const;
// Part of silhouette generation (used by selection outlines)
// Populates the provided edge array with numbers corresponding to
// *partial* logic of whether a particular index should be rendered
// as a silhouette edge. -1 indicates the index should be rendered as a
// silhouette edge. See generateSilhouetteVertices for the full logic.
// Silhouette edges can only be generated for some types of prims. If a
// silhouette edge cannot be generated, the edge array will be left empty.
void generateSilhouetteEdge(const LLVolume* volume, std::vector<S32>& edge) const;
enum
{
SINGLE_MASK = 0x0001,
@ -963,8 +972,6 @@ public:
// indexes for mPositions/mNormals/mTexCoords
U16* mIndices;
std::vector<S32> mEdge;
//list of skin weights for rigged volumes
// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
// mWeights.size() should be empty or match mVertices.size()
@ -1113,9 +1120,9 @@ private:
public:
virtual void setMeshAssetLoaded(bool loaded);
virtual bool isMeshAssetLoaded();
virtual bool isMeshAssetLoaded() const;
virtual void setMeshAssetUnavaliable(bool unavaliable);
virtual bool isMeshAssetUnavaliable();
virtual bool isMeshAssetUnavaliable() const;
protected:
bool mUnique;