SL-18095 WIP -- Allow mikktspace generator to add more vertices (skip re-welding step for now).
parent
dfe19c257d
commit
c822da9fe6
|
|
@ -2102,7 +2102,12 @@ void LLVolume::regen()
|
|||
|
||||
void LLVolume::genTangents(S32 face, bool mikktspace)
|
||||
{
|
||||
mVolumeFaces[face].createTangents(mikktspace);
|
||||
// generate legacy tangents for the specified face
|
||||
// if mikktspace is true, only generate tangents if mikktspace tangents are not present (handles the case for non-mesh prims)
|
||||
if (!mikktspace || mVolumeFaces[face].mMikktSpaceTangents == nullptr)
|
||||
{
|
||||
mVolumeFaces[face].createTangents();
|
||||
}
|
||||
}
|
||||
|
||||
LLVolume::~LLVolume()
|
||||
|
|
@ -5373,252 +5378,155 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// data structures for tangent generation
|
||||
|
||||
struct MikktData
|
||||
{
|
||||
LLVolumeFace* face;
|
||||
std::vector<LLVector3> p;
|
||||
std::vector<LLVector3> n;
|
||||
std::vector<LLVector2> tc;
|
||||
std::vector<LLVector4> w;
|
||||
std::vector<LLVector4> t;
|
||||
|
||||
MikktData(LLVolumeFace* f)
|
||||
: face(f)
|
||||
{
|
||||
U32 count = face->mNumIndices;
|
||||
|
||||
p.resize(count);
|
||||
n.resize(count);
|
||||
tc.resize(count);
|
||||
t.resize(count);
|
||||
|
||||
if (face->mWeights)
|
||||
{
|
||||
w.resize(count);
|
||||
}
|
||||
|
||||
for (int i = 0; i < face->mNumIndices; ++i)
|
||||
{
|
||||
U32 idx = face->mIndices[i];
|
||||
|
||||
p[i].set(face->mPositions[idx].getF32ptr());
|
||||
n[i].set(face->mNormals[idx].getF32ptr());
|
||||
tc[i].set(face->mTexCoords[idx]);
|
||||
|
||||
if (face->mWeights)
|
||||
{
|
||||
w[i].set(face->mWeights[idx].getF32ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool LLVolumeFace::cacheOptimize()
|
||||
{ //optimize for vertex cache according to Forsyth method:
|
||||
// http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
|
||||
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
|
||||
llassert(!mOptimized);
|
||||
mOptimized = TRUE;
|
||||
|
||||
LLVCacheLRU cache;
|
||||
allocateTangents(mNumVertices, true);
|
||||
|
||||
SMikkTSpaceInterface ms;
|
||||
|
||||
ms.m_getNumFaces = [](const SMikkTSpaceContext* pContext)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
return face->mNumIndices / 3;
|
||||
};
|
||||
|
||||
ms.m_getNumVerticesOfFace = [](const SMikkTSpaceContext* pContext, const int iFace)
|
||||
{
|
||||
return 3;
|
||||
};
|
||||
|
||||
ms.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
S32 idx = face->mIndices[iFace * 3 + iVert];
|
||||
auto& vert = face->mPositions[idx];
|
||||
F32* v = vert.getF32ptr();
|
||||
fvPosOut[0] = v[0];
|
||||
fvPosOut[1] = v[1];
|
||||
fvPosOut[2] = v[2];
|
||||
};
|
||||
|
||||
ms.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
S32 idx = face->mIndices[iFace * 3 + iVert];
|
||||
auto& norm = face->mNormals[idx];
|
||||
F32* n = norm.getF32ptr();
|
||||
fvNormOut[0] = n[0];
|
||||
fvNormOut[1] = n[1];
|
||||
fvNormOut[2] = n[2];
|
||||
};
|
||||
|
||||
ms.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
S32 idx = face->mIndices[iFace * 3 + iVert];
|
||||
auto& tc = face->mTexCoords[idx];
|
||||
fvTexcOut[0] = tc.mV[0];
|
||||
fvTexcOut[1] = tc.mV[1];
|
||||
};
|
||||
|
||||
ms.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
S32 i = iFace * 3 + iVert;
|
||||
S32 idx = face->mIndices[i];
|
||||
|
||||
LLVector3 p(face->mPositions[idx].getF32ptr());
|
||||
LLVector3 n(face->mNormals[idx].getF32ptr());
|
||||
LLVector3 t(fvTangent);
|
||||
|
||||
data->t[i].set(fvTangent);
|
||||
data->t[i].mV[3] = fSign;
|
||||
};
|
||||
|
||||
ms.m_setTSpace = nullptr;
|
||||
|
||||
MikktData data(this);
|
||||
|
||||
SMikkTSpaceContext ctx = { &ms, &data };
|
||||
|
||||
genTangSpaceDefault(&ctx);
|
||||
|
||||
if (mNumVertices < 3 || mNumIndices < 3)
|
||||
{ //nothing to do
|
||||
return true;
|
||||
}
|
||||
resizeVertices(data.p.size());
|
||||
resizeIndices(data.p.size());
|
||||
|
||||
if (!data.w.empty())
|
||||
{
|
||||
allocateWeights(data.w.size());
|
||||
}
|
||||
|
||||
//mapping of vertices to triangles and indices
|
||||
std::vector<LLVCacheVertexData> vertex_data;
|
||||
allocateTangents(mNumVertices, true);
|
||||
|
||||
//mapping of triangles do vertices
|
||||
std::vector<LLVCacheTriangleData> triangle_data;
|
||||
for (int i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
mIndices[i] = i;
|
||||
|
||||
try
|
||||
{
|
||||
triangle_data.resize(mNumIndices / 3);
|
||||
vertex_data.resize(mNumVertices);
|
||||
mPositions[i].load3(data.p[i].mV);
|
||||
mNormals[i].load3(data.n[i].mV);
|
||||
mTexCoords[i] = data.tc[i];
|
||||
|
||||
mMikktSpaceTangents[i].loadua(data.t[i].mV);
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; i++)
|
||||
{ //populate vertex data and triangle data arrays
|
||||
U16 idx = mIndices[i];
|
||||
U32 tri_idx = i / 3;
|
||||
|
||||
vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
|
||||
vertex_data[idx].mIdx = idx;
|
||||
triangle_data[tri_idx].mVertex[i % 3] = &(vertex_data[idx]);
|
||||
if (mWeights)
|
||||
{
|
||||
mWeights[i].loadua(data.w[i].mV);
|
||||
}
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
{
|
||||
// resize or push_back failed
|
||||
LL_WARNS("LLVOLUME") << "Resize for " << mNumVertices << " vertices failed" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*F32 pre_acmr = 1.f;
|
||||
//measure cache misses from before rebuild
|
||||
{
|
||||
LLVCacheFIFO test_cache;
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
test_cache.addVertex(&vertex_data[mIndices[i]]);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mNumVertices; i++)
|
||||
{
|
||||
vertex_data[i].mCacheTag = -1;
|
||||
}
|
||||
|
||||
pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
|
||||
}*/
|
||||
|
||||
for (U32 i = 0; i < mNumVertices; i++)
|
||||
{ //initialize score values (no cache -- might try a fifo cache here)
|
||||
LLVCacheVertexData& data = vertex_data[i];
|
||||
|
||||
data.mScore = find_vertex_score(data);
|
||||
data.mActiveTriangles = data.mTriangles.size();
|
||||
|
||||
for (U32 j = 0; j < data.mActiveTriangles; ++j)
|
||||
{
|
||||
data.mTriangles[j]->mScore += data.mScore;
|
||||
}
|
||||
}
|
||||
|
||||
//sort triangle data by score
|
||||
std::sort(triangle_data.begin(), triangle_data.end());
|
||||
|
||||
std::vector<U16> new_indices;
|
||||
|
||||
LLVCacheTriangleData* tri;
|
||||
|
||||
//prime pump by adding first triangle to cache;
|
||||
tri = &(triangle_data[0]);
|
||||
cache.addTriangle(tri);
|
||||
new_indices.push_back(tri->mVertex[0]->mIdx);
|
||||
new_indices.push_back(tri->mVertex[1]->mIdx);
|
||||
new_indices.push_back(tri->mVertex[2]->mIdx);
|
||||
tri->complete();
|
||||
|
||||
U32 breaks = 0;
|
||||
for (U32 i = 1; i < mNumIndices/3; ++i)
|
||||
{
|
||||
cache.updateScores();
|
||||
tri = cache.mBestTriangle;
|
||||
if (!tri)
|
||||
{
|
||||
breaks++;
|
||||
for (U32 j = 0; j < triangle_data.size(); ++j)
|
||||
{
|
||||
if (triangle_data[j].mActive)
|
||||
{
|
||||
tri = &(triangle_data[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cache.addTriangle(tri);
|
||||
new_indices.push_back(tri->mVertex[0]->mIdx);
|
||||
new_indices.push_back(tri->mVertex[1]->mIdx);
|
||||
new_indices.push_back(tri->mVertex[2]->mIdx);
|
||||
tri->complete();
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
mIndices[i] = new_indices[i];
|
||||
}
|
||||
|
||||
/*F32 post_acmr = 1.f;
|
||||
//measure cache misses from after rebuild
|
||||
{
|
||||
LLVCacheFIFO test_cache;
|
||||
for (U32 i = 0; i < mNumVertices; i++)
|
||||
{
|
||||
vertex_data[i].mCacheTag = -1;
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
test_cache.addVertex(&vertex_data[mIndices[i]]);
|
||||
}
|
||||
|
||||
post_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
|
||||
}*/
|
||||
|
||||
//optimize for pre-TnL cache
|
||||
|
||||
//allocate space for new buffer
|
||||
S32 num_verts = mNumVertices;
|
||||
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
LLVector4a* pos = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+size);
|
||||
if (pos == NULL)
|
||||
{
|
||||
LL_WARNS("LLVOLUME") << "Allocation of positions vector[" << sizeof(LLVector4a) * 2 * num_verts + size << "] failed. " << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
LLVector4a* norm = pos + num_verts;
|
||||
LLVector2* tc = (LLVector2*) (norm + num_verts);
|
||||
|
||||
LLVector4a* wght = NULL;
|
||||
if (mWeights)
|
||||
{
|
||||
wght = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
if (wght == NULL)
|
||||
{
|
||||
ll_aligned_free<64>(pos);
|
||||
LL_WARNS("LLVOLUME") << "Allocation of weights[" << sizeof(LLVector4a) * num_verts << "] failed" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
llassert(mTangents == nullptr); // cache optimize called too late, tangents already generated
|
||||
llassert(mMikktSpaceTangents == nullptr);
|
||||
|
||||
// =====================================================================================
|
||||
// DEPRECATED -- cacheOptimize should always be called before tangents are generated
|
||||
// =====================================================================================
|
||||
LLVector4a* binorm = NULL;
|
||||
if (mTangents)
|
||||
{
|
||||
binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
if (binorm == NULL)
|
||||
{
|
||||
ll_aligned_free<64>(pos);
|
||||
ll_aligned_free_16(wght);
|
||||
LL_WARNS("LLVOLUME") << "Allocation of binormals[" << sizeof(LLVector4a)*num_verts << "] failed" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// =====================================================================================
|
||||
|
||||
//allocate mapping of old indices to new indices
|
||||
std::vector<S32> new_idx;
|
||||
try
|
||||
{
|
||||
new_idx.resize(mNumVertices, -1);
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
{
|
||||
ll_aligned_free<64>(pos);
|
||||
ll_aligned_free_16(wght);
|
||||
ll_aligned_free_16(binorm);
|
||||
LL_WARNS("LLVOLUME") << "Resize failed: " << mNumVertices << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
S32 cur_idx = 0;
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
U16 idx = mIndices[i];
|
||||
if (new_idx[idx] == -1)
|
||||
{ //this vertex hasn't been added yet
|
||||
new_idx[idx] = cur_idx;
|
||||
|
||||
//copy vertex data
|
||||
pos[cur_idx] = mPositions[idx];
|
||||
norm[cur_idx] = mNormals[idx];
|
||||
tc[cur_idx] = mTexCoords[idx];
|
||||
if (mWeights)
|
||||
{
|
||||
wght[cur_idx] = mWeights[idx];
|
||||
}
|
||||
if (mTangents)
|
||||
{
|
||||
binorm[cur_idx] = mTangents[idx];
|
||||
}
|
||||
|
||||
cur_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mNumIndices; ++i)
|
||||
{
|
||||
mIndices[i] = new_idx[mIndices[i]];
|
||||
}
|
||||
|
||||
ll_aligned_free<64>(mPositions);
|
||||
// DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
|
||||
ll_aligned_free_16(mWeights);
|
||||
ll_aligned_free_16(mTangents);
|
||||
#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS
|
||||
ll_aligned_free_16(mJointIndices);
|
||||
ll_aligned_free_16(mJustWeights);
|
||||
mJustWeights = NULL;
|
||||
mJointIndices = NULL; // filled in later as necessary by skinning code for acceleration
|
||||
#endif
|
||||
|
||||
mPositions = pos;
|
||||
mNormals = norm;
|
||||
mTexCoords = tc;
|
||||
mWeights = wght;
|
||||
mTangents = binorm;
|
||||
|
||||
//std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
|
||||
//LL_INFOS() << result << LL_ENDL;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -6407,209 +6315,25 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
|
|||
void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal,
|
||||
const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent);
|
||||
|
||||
|
||||
// data structures for tangent generation
|
||||
|
||||
// key for summing tangents
|
||||
// We will blend tangents wherever a common position and normal is found
|
||||
struct MikktKey
|
||||
{
|
||||
// Position
|
||||
LLVector3 p;
|
||||
// Normal
|
||||
LLVector3 n;
|
||||
|
||||
bool operator==(const MikktKey& rhs) const { return p == rhs.p && n == rhs.n; }
|
||||
};
|
||||
|
||||
// sum of tangents and list of signs and index array indices for a given position and normal combination
|
||||
// sign must be kept separate from summed tangent because a single position and normal may have a different
|
||||
// tangent facing where UV seams exist
|
||||
struct MikktTangent
|
||||
{
|
||||
// tangent vector
|
||||
LLVector3 t;
|
||||
// signs
|
||||
std::vector<F32> s;
|
||||
// indices (in index array)
|
||||
std::vector<S32> i;
|
||||
};
|
||||
|
||||
// hash function for MikktTangent
|
||||
namespace boost
|
||||
{
|
||||
template <>
|
||||
struct hash<LLVector3>
|
||||
{
|
||||
std::size_t operator()(LLVector3 const& k) const
|
||||
{
|
||||
size_t seed = 0;
|
||||
boost::hash_combine(seed, k.mV[0]);
|
||||
boost::hash_combine(seed, k.mV[1]);
|
||||
boost::hash_combine(seed, k.mV[2]);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<MikktKey>
|
||||
{
|
||||
std::size_t operator()(MikktKey const& k) const
|
||||
{
|
||||
size_t seed = 0;
|
||||
boost::hash_combine(seed, k.p);
|
||||
boost::hash_combine(seed, k.n);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// boost adapter
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<MikktKey>
|
||||
{
|
||||
std::size_t operator()(MikktKey const& k) const
|
||||
{
|
||||
return boost::hash<MikktKey>()(k);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct MikktData
|
||||
{
|
||||
LLVolumeFace* face;
|
||||
std::unordered_map<MikktKey, MikktTangent > tangents;
|
||||
};
|
||||
|
||||
|
||||
void LLVolumeFace::createTangents(bool mikktspace)
|
||||
void LLVolumeFace::createTangents()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
|
||||
|
||||
auto& tangents = mikktspace ? mMikktSpaceTangents : mTangents;
|
||||
|
||||
if (!tangents)
|
||||
|
||||
if (!mTangents)
|
||||
{
|
||||
allocateTangents(mNumVertices, mikktspace);
|
||||
allocateTangents(mNumVertices);
|
||||
|
||||
//generate tangents
|
||||
LLVector4a* ptr = (LLVector4a*)mTangents;
|
||||
|
||||
if (mikktspace)
|
||||
LLVector4a* end = mTangents + mNumVertices;
|
||||
while (ptr < end)
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("mikktspace");
|
||||
SMikkTSpaceInterface ms;
|
||||
|
||||
ms.m_getNumFaces = [](const SMikkTSpaceContext* pContext)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
return face->mNumIndices / 3;
|
||||
};
|
||||
|
||||
ms.m_getNumVerticesOfFace = [](const SMikkTSpaceContext* pContext, const int iFace)
|
||||
{
|
||||
return 3;
|
||||
};
|
||||
|
||||
ms.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
S32 idx = face->mIndices[iFace * 3 + iVert];
|
||||
auto& vert = face->mPositions[idx];
|
||||
F32* v = vert.getF32ptr();
|
||||
fvPosOut[0] = v[0];
|
||||
fvPosOut[1] = v[1];
|
||||
fvPosOut[2] = v[2];
|
||||
};
|
||||
|
||||
ms.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
S32 idx = face->mIndices[iFace * 3 + iVert];
|
||||
auto& norm = face->mNormals[idx];
|
||||
F32* n = norm.getF32ptr();
|
||||
fvNormOut[0] = n[0];
|
||||
fvNormOut[1] = n[1];
|
||||
fvNormOut[2] = n[2];
|
||||
};
|
||||
|
||||
ms.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
S32 idx = face->mIndices[iFace * 3 + iVert];
|
||||
auto& tc = face->mTexCoords[idx];
|
||||
fvTexcOut[0] = tc.mV[0];
|
||||
fvTexcOut[1] = tc.mV[1];
|
||||
};
|
||||
|
||||
ms.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert)
|
||||
{
|
||||
MikktData* data = (MikktData*)pContext->m_pUserData;
|
||||
LLVolumeFace* face = data->face;
|
||||
S32 i = iFace * 3 + iVert;
|
||||
S32 idx = face->mIndices[i];
|
||||
|
||||
LLVector3 p(face->mPositions[idx].getF32ptr());
|
||||
LLVector3 n(face->mNormals[idx].getF32ptr());
|
||||
LLVector3 t(fvTangent);
|
||||
|
||||
MikktKey key = { p, n };
|
||||
|
||||
MikktTangent& mt = data->tangents[key];
|
||||
mt.t += t;
|
||||
mt.s.push_back(fSign);
|
||||
mt.i.push_back(i);
|
||||
};
|
||||
|
||||
ms.m_setTSpace = nullptr;
|
||||
|
||||
MikktData data;
|
||||
data.face = this;
|
||||
|
||||
SMikkTSpaceContext ctx = { &ms, &data };
|
||||
|
||||
genTangSpaceDefault(&ctx);
|
||||
|
||||
for (U32 i = 0; i < mNumVertices; ++i)
|
||||
{
|
||||
MikktKey key = { LLVector3(mPositions[i].getF32ptr()), LLVector3(mNormals[i].getF32ptr()) };
|
||||
MikktTangent& t = data.tangents[key];
|
||||
|
||||
//set tangent
|
||||
mMikktSpaceTangents[i].load3(t.t.mV);
|
||||
mMikktSpaceTangents[i].normalize3fast();
|
||||
|
||||
//set sign
|
||||
F32 sign = 0.f;
|
||||
for (int j = 0; j < t.i.size(); ++j)
|
||||
{
|
||||
if (mIndices[t.i[j]] == i)
|
||||
{
|
||||
sign = t.s[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
llassert(sign != 0.f);
|
||||
mMikktSpaceTangents[i].getF32ptr()[3] = sign;
|
||||
}
|
||||
(*ptr++).clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
//generate tangents
|
||||
LLVector4a* ptr = (LLVector4a*)tangents;
|
||||
|
||||
LLVector4a* end = mTangents + mNumVertices;
|
||||
while (ptr < end)
|
||||
{
|
||||
(*ptr++).clear();
|
||||
}
|
||||
|
||||
CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices / 3, mIndices, tangents);
|
||||
}
|
||||
CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices / 3, mIndices, mTangents);
|
||||
|
||||
//normalize normals
|
||||
for (U32 i = 0; i < mNumVertices; i++)
|
||||
|
|
@ -6618,6 +6342,7 @@ void LLVolumeFace::createTangents(bool mikktspace)
|
|||
mNormals[i].normalize3fast();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLVolumeFace::resizeVertices(S32 num_verts)
|
||||
|
|
|
|||
|
|
@ -870,7 +870,7 @@ private:
|
|||
public:
|
||||
|
||||
BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
|
||||
void createTangents(bool mikktspace = false);
|
||||
void createTangents();
|
||||
|
||||
void resizeVertices(S32 num_verts);
|
||||
void allocateTangents(S32 num_verts, bool mikktspace = false);
|
||||
|
|
|
|||
|
|
@ -25,61 +25,34 @@
|
|||
|
||||
/*[EXTRA_CODE_HERE]*/
|
||||
|
||||
#define DEBUG_PBR_LIGHT_TYPE 0 // Output Diffuse=0.75, Emissive=0, ORM=0,0,0
|
||||
|
||||
#define DEBUG_BASIC 0
|
||||
#define DEBUG_VERTEX 0
|
||||
#define DEBUG_NORMAL_MAP 0 // Output packed normal map "as is" to diffuse
|
||||
#define DEBUG_NORMAL_OUT 0 // Output unpacked normal to diffuse
|
||||
#define DEBUG_ORM 0 // Output Occlusion Roughness Metal "as is" to diffuse
|
||||
#define DEBUG_POSITION 0
|
||||
|
||||
uniform sampler2D diffuseMap; //always in sRGB space
|
||||
|
||||
uniform float metallicFactor;
|
||||
uniform float roughnessFactor;
|
||||
uniform vec3 emissiveColor;
|
||||
uniform sampler2D bumpMap;
|
||||
uniform sampler2D emissiveMap;
|
||||
uniform sampler2D specularMap; // Packed: Occlusion, Metal, Roughness
|
||||
|
||||
#ifdef HAS_NORMAL_MAP
|
||||
uniform sampler2D bumpMap;
|
||||
VARYING vec3 vary_tangent;
|
||||
flat in float vary_sign;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_EMISSIVE_MAP
|
||||
uniform sampler2D emissiveMap;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPECULAR_MAP
|
||||
uniform sampler2D specularMap; // Packed: Occlusion, Metal, Roughness
|
||||
#endif
|
||||
|
||||
uniform samplerCube environmentMap;
|
||||
uniform mat3 env_mat;
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_data[4];
|
||||
#else
|
||||
#define frag_data gl_FragData
|
||||
#endif
|
||||
|
||||
VARYING vec3 vary_position;
|
||||
VARYING vec4 vertex_color;
|
||||
VARYING vec2 vary_texcoord0;
|
||||
#ifdef HAS_NORMAL_MAP
|
||||
VARYING vec3 vary_normal;
|
||||
VARYING vec2 vary_texcoord1;
|
||||
#endif
|
||||
VARYING vec3 vary_tangent;
|
||||
flat in float vary_sign;
|
||||
|
||||
#ifdef HAS_SPECULAR_MAP
|
||||
VARYING vec2 vary_texcoord2;
|
||||
#endif
|
||||
VARYING vec2 vary_texcoord0;
|
||||
VARYING vec2 vary_texcoord1;
|
||||
VARYING vec2 vary_texcoord2;
|
||||
|
||||
uniform float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff()
|
||||
|
||||
vec2 encode_normal(vec3 n);
|
||||
vec3 linear_to_srgb(vec3 c);
|
||||
|
||||
uniform mat3 normal_matrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
// IF .mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
|
||||
|
|
@ -94,11 +67,11 @@ void main()
|
|||
vec3 col = vertex_color.rgb * albedo.rgb;
|
||||
|
||||
// from mikktspace.com
|
||||
vec4 vNt = texture2D(bumpMap, vary_texcoord1.xy)*2.0-1.0;
|
||||
vec3 vNt = texture2D(bumpMap, vary_texcoord1.xy).xyz*2.0-1.0;
|
||||
float sign = vary_sign;
|
||||
vec3 vN = vary_normal;
|
||||
vec3 vT = vary_tangent.xyz;
|
||||
|
||||
|
||||
vec3 vB = sign * cross(vN, vT);
|
||||
vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
|
||||
|
||||
|
|
@ -107,49 +80,20 @@ void main()
|
|||
// occlusion 1.0
|
||||
// roughness 0.0
|
||||
// metal 0.0
|
||||
#ifdef HAS_SPECULAR_MAP
|
||||
vec3 spec = texture2D(specularMap, vary_texcoord2.xy).rgb;
|
||||
#else
|
||||
vec3 spec = vec3(1,0,0);
|
||||
#endif
|
||||
|
||||
spec.g *= roughnessFactor;
|
||||
spec.b *= metallicFactor;
|
||||
|
||||
vec3 emissive = emissiveColor;
|
||||
#ifdef HAS_EMISSIVE_MAP
|
||||
emissive *= texture2D(emissiveMap, vary_texcoord0.xy).rgb;
|
||||
#endif
|
||||
|
||||
#if DEBUG_PBR_LIGHT_TYPE
|
||||
col.rgb = vec3(0.75);
|
||||
emissive = vec3(0);
|
||||
spec.rgb = vec3(0);
|
||||
#endif
|
||||
#if DEBUG_BASIC
|
||||
col.rgb = vec3( 1, 0, 1 );
|
||||
#endif
|
||||
#if DEBUG_VERTEX
|
||||
col.rgb = vertex_color.rgb;
|
||||
#endif
|
||||
#if DEBUG_NORMAL_MAP
|
||||
col.rgb = texture2D(bumpMap, vary_texcoord1.xy).rgb;
|
||||
#endif
|
||||
#if DEBUG_NORMAL_OUT
|
||||
col.rgb = vary_normal;
|
||||
#endif
|
||||
#if DEBUG_ORM
|
||||
col.rgb = linear_to_srgb(spec);
|
||||
#endif
|
||||
#if DEBUG_POSITION
|
||||
col.rgb = vary_position.xyz;
|
||||
#endif
|
||||
|
||||
tnorm *= gl_FrontFacing ? 1.0 : -1.0;
|
||||
|
||||
//spec.rgb = vec3(1,1,0);
|
||||
//col = vec3(0,0,0);
|
||||
//emissive = vary_tangent.xyz*0.5+0.5;
|
||||
//emissive = vec3(vary_sign*0.5+0.5);
|
||||
//emissive = vec3(sign*0.5+0.5);
|
||||
// See: C++: addDeferredAttachments(), GLSL: softenLightF
|
||||
frag_data[0] = vec4(col, 0.0); // Diffuse
|
||||
frag_data[1] = vec4(emissive, vertex_color.a); // PBR sRGB Emissive
|
||||
|
|
|
|||
|
|
@ -37,41 +37,24 @@ uniform mat3 normal_matrix;
|
|||
uniform mat4 modelview_projection_matrix;
|
||||
#endif
|
||||
|
||||
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
|
||||
|
||||
#if !defined(HAS_SKIN)
|
||||
uniform mat4 modelview_matrix;
|
||||
#endif
|
||||
|
||||
VARYING vec3 vary_position;
|
||||
|
||||
#endif
|
||||
|
||||
uniform mat4 texture_matrix0;
|
||||
|
||||
ATTRIBUTE vec3 position;
|
||||
ATTRIBUTE vec4 diffuse_color;
|
||||
ATTRIBUTE vec3 normal;
|
||||
ATTRIBUTE vec2 texcoord0;
|
||||
|
||||
|
||||
#ifdef HAS_NORMAL_MAP
|
||||
ATTRIBUTE vec4 tangent;
|
||||
ATTRIBUTE vec2 texcoord0;
|
||||
ATTRIBUTE vec2 texcoord1;
|
||||
|
||||
VARYING vec2 vary_texcoord1;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPECULAR_MAP
|
||||
ATTRIBUTE vec2 texcoord2;
|
||||
|
||||
VARYING vec2 vary_texcoord0;
|
||||
VARYING vec2 vary_texcoord1;
|
||||
VARYING vec2 vary_texcoord2;
|
||||
#endif
|
||||
|
||||
VARYING vec4 vertex_color;
|
||||
VARYING vec2 vary_texcoord0;
|
||||
|
||||
VARYING vec3 vary_tangent;
|
||||
flat out float vary_sign;
|
||||
|
||||
VARYING vec3 vary_normal;
|
||||
|
||||
void main()
|
||||
|
|
@ -83,64 +66,28 @@ void main()
|
|||
|
||||
vec3 pos = (mat*vec4(position.xyz,1.0)).xyz;
|
||||
|
||||
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
|
||||
vary_position = pos;
|
||||
#endif
|
||||
|
||||
gl_Position = projection_matrix*vec4(pos,1.0);
|
||||
|
||||
#else
|
||||
//transform vertex
|
||||
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
|
||||
|
||||
#endif
|
||||
|
||||
vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
|
||||
|
||||
#ifdef HAS_NORMAL_MAP
|
||||
vary_texcoord1 = (texture_matrix0 * vec4(texcoord1,0,1)).xy;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPECULAR_MAP
|
||||
vary_texcoord2 = (texture_matrix0 * vec4(texcoord2,0,1)).xy;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SKIN
|
||||
vec3 n = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
|
||||
#ifdef HAS_NORMAL_MAP
|
||||
vec3 t = normalize((mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz);
|
||||
vec3 b = cross(n, t)*tangent.w;
|
||||
|
||||
//vary_mat0 = vec3(t.x, b.x, n.x);
|
||||
//vary_mat1 = vec3(t.y, b.y, n.y);
|
||||
//vary_mat2 = vec3(t.z, b.z, n.z);
|
||||
#else //HAS_NORMAL_MAP
|
||||
vary_normal = n;
|
||||
#endif //HAS_NORMAL_MAP
|
||||
vec3 n = (mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz;
|
||||
vec3 t = (mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz;
|
||||
#else //HAS_SKIN
|
||||
vec3 n = normalize(normal_matrix * normal);
|
||||
#ifdef HAS_NORMAL_MAP
|
||||
vec3 t = normalize(normal_matrix * tangent.xyz);
|
||||
vary_tangent = t;
|
||||
vary_sign = tangent.w;
|
||||
vary_normal = n;
|
||||
vec3 n = normal_matrix * normal;
|
||||
vec3 t = normal_matrix * tangent.xyz;
|
||||
#endif
|
||||
|
||||
//vec3 b = cross(n,t)*tangent.w;
|
||||
//vec3 t = cross(b,n) * binormal.w;
|
||||
|
||||
//vary_mat0 = vec3(t.x, b.x, n.x);
|
||||
//vary_mat1 = vec3(t.y, b.y, n.y);
|
||||
//vary_mat2 = vec3(t.z, b.z, n.z);
|
||||
#else //HAS_NORMAL_MAP
|
||||
vary_normal = n;
|
||||
#endif //HAS_NORMAL_MAP
|
||||
#endif //HAS_SKIN
|
||||
vary_tangent = normalize(t);
|
||||
vary_sign = tangent.w;
|
||||
vary_normal = normalize(n);
|
||||
|
||||
vertex_color = diffuse_color;
|
||||
|
||||
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
|
||||
#if !defined(HAS_SKIN)
|
||||
vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2177,6 +2177,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
|||
mask.setElement<3>();
|
||||
|
||||
LLVector4a* tbuff = mikktspace ? vf.mMikktSpaceTangents : vf.mTangents;
|
||||
if (tbuff == nullptr)
|
||||
{ // non-mesh prims will not have mikktspace tangents
|
||||
tbuff = vf.mTangents;
|
||||
}
|
||||
|
||||
LLVector4a* src = tbuff;
|
||||
LLVector4a* end = tbuff+num_vertices;
|
||||
|
||||
|
|
@ -2184,7 +2189,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
|||
{
|
||||
LLVector4a tangent_out;
|
||||
mat_normal.rotate(*src, tangent_out);
|
||||
tangent_out.normalize3fast();
|
||||
tangent_out.normalize3();
|
||||
tangent_out.setSelectWithMask(mask, *src, tangent_out);
|
||||
tangent_out.store4a(tangents);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue