SL-18095 WIP -- Allow mikktspace generator to add more vertices (skip re-welding step for now).

master
Dave Parks 2022-09-09 20:56:22 -05:00
parent dfe19c257d
commit c822da9fe6
5 changed files with 187 additions and 566 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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
}

View File

@ -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);