diff options
-rw-r--r-- | autobuild.xml | 44 | ||||
-rw-r--r-- | indra/cmake/LLMath.cmake | 3 | ||||
-rw-r--r-- | indra/llmath/llvolume.cpp | 272 | ||||
-rw-r--r-- | indra/llmath/llvolume.h | 7 | ||||
-rw-r--r-- | indra/newview/app_settings/settings.xml | 11 | ||||
-rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl | 29 | ||||
-rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl | 28 | ||||
-rw-r--r-- | indra/newview/llface.cpp | 11 |
8 files changed, 337 insertions, 68 deletions
diff --git a/autobuild.xml b/autobuild.xml index bf20cb788e..e984551455 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1836,6 +1836,50 @@ <key>version</key> <string>0.16.561408</string> </map> + <key>mikktspace</key> + <map> + <key>canonical_repo</key> + <string>https://bitbucket.org/lindenlab/3p-mikktspace</string> + <key>copyright</key> + <string>Copyright (C) 2011 by Morten S. Mikkelsen</string> + <key>description</key> + <string>Mikktspace Tangent Generator</string> + <key>license</key> + <string>Copyright (C) 2011 by Morten S. Mikkelsen</string> + <key>license_file</key> + <string>mikktspace.txt</string> + <key>name</key> + <string>mikktspace</string> + <key>platforms</key> + <map> + <key>darwin64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>b48b7ac0792d3ea8f087d99d9e4a29d8</string> + <key>url</key> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104415/914944/mikktspace-1-darwin64-574859.tar.bz2</string> + </map> + <key>name</key> + <string>darwin64</string> + </map> + <key>windows64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>02e9e5b6fe6788f4d2babb83ec544843</string> + <key>url</key> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/104406/914909/mikktspace-1-windows64-574859.tar.bz2</string> + </map> + <key>name</key> + <string>windows64</string> + </map> + </map> + <key>version</key> + <string>1</string> + </map> <key>minizip-ng</key> <map> <key>canonical_repo</key> diff --git a/indra/cmake/LLMath.cmake b/indra/cmake/LLMath.cmake index 893920ae6f..3cbb7ad561 100644 --- a/indra/cmake/LLMath.cmake +++ b/indra/cmake/LLMath.cmake @@ -1,5 +1,8 @@ # -*- cmake -*- +include(Variables) +include(Mikktspace) + set(LLMATH_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llmath ) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 4a069b0f63..539db9d0e1 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -32,6 +32,7 @@ #include <stdint.h> #endif #include <cmath> +#include <unordered_map> #include "llerror.h" @@ -52,6 +53,9 @@ #include "llmeshoptimizer.h" #include "lltimer.h" +#include "mikktspace/mikktspace.h" +#include "mikktspace/mikktspace.c" // insert mikktspace implementation into llvolume object file + #define DEBUG_SILHOUETTE_BINORMALS 0 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette #define DEBUG_SILHOUETTE_EDGE_MAP 0 // DaveP: Use this to display edge map using the silhouette @@ -2096,9 +2100,9 @@ void LLVolume::regen() createVolumeFaces(); } -void LLVolume::genTangents(S32 face) +void LLVolume::genTangents(S32 face, bool mikktspace) { - mVolumeFaces[face].createTangents(); + mVolumeFaces[face].createTangents(mikktspace); } LLVolume::~LLVolume() @@ -4797,6 +4801,17 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) mTangents = NULL; } + if (src.mMikktSpaceTangents) + { + allocateTangents(src.mNumVertices, true); + LLVector4a::memcpyNonAliased16((F32*)mMikktSpaceTangents, (F32*)src.mMikktSpaceTangents, vert_size); + } + else + { + ll_aligned_free_16(mMikktSpaceTangents); + mMikktSpaceTangents = nullptr; + } + if (src.mWeights) { llassert(!mWeights); // don't orphan an old alloc here accidentally @@ -4867,6 +4882,8 @@ void LLVolumeFace::freeData() mIndices = NULL; ll_aligned_free_16(mTangents); mTangents = NULL; + ll_aligned_free_16(mMikktSpaceTangents); + mMikktSpaceTangents = nullptr; ll_aligned_free_16(mWeights); mWeights = NULL; @@ -4988,6 +5005,9 @@ void LLVolumeFace::remap() ll_aligned_free_16(mTangents); mTangents = NULL; + ll_aligned_free_16(mMikktSpaceTangents); + mMikktSpaceTangents = nullptr; + // Assign new values mIndices = remap_indices; mPositions = remap_positions; @@ -5514,6 +5534,12 @@ bool LLVolumeFace::cacheOptimize() } } + 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) { @@ -5526,11 +5552,11 @@ bool LLVolumeFace::cacheOptimize() return false; } } + // ===================================================================================== - //allocate mapping of old indices to new indices + //allocate mapping of old indices to new indices std::vector<S32> new_idx; - - try + try { new_idx.resize(mNumVertices, -1); } @@ -5673,6 +5699,7 @@ void LLVolumeFace::swapData(LLVolumeFace& rhs) llswap(rhs.mPositions, mPositions); llswap(rhs.mNormals, mNormals); llswap(rhs.mTangents, mTangents); + llswap(rhs.mMikktSpaceTangents, mMikktSpaceTangents); llswap(rhs.mTexCoords, mTexCoords); llswap(rhs.mIndices,mIndices); llswap(rhs.mNumVertices, mNumVertices); @@ -6380,37 +6407,217 @@ 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); -void LLVolumeFace::createTangents() + +// data structures for tangent generation + +// key for summing tangents +// We will blend tangents wherever a common position and normal is found +struct MikktKey { - LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + // Position + LLVector3 p; + // Normal + LLVector3 n; - if (!mTangents) - { - allocateTangents(mNumVertices); + bool operator==(const MikktKey& rhs) const { return p == rhs.p && n == rhs.n; } +}; - //generate tangents - //LLVector4a* pos = mPositions; - //LLVector2* tc = (LLVector2*) mTexCoords; - LLVector4a* binorm = (LLVector4a*) mTangents; +// 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; +}; - LLVector4a* end = mTangents+mNumVertices; - while (binorm < end) - { - (*binorm++).clear(); - } +// 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; +}; - binorm = mTangents; - CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices/3, mIndices, mTangents); +void LLVolumeFace::createTangents(bool mikktspace) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - //normalize tangents - for (U32 i = 0; i < mNumVertices; i++) - { - //binorm[i].normalize3fast(); - //bump map/planar projection code requires normals to be normalized - mNormals[i].normalize3fast(); - } - } + auto& tangents = mikktspace ? mMikktSpaceTangents : mTangents; + + if (!tangents) + { + allocateTangents(mNumVertices, mikktspace); + + if (mikktspace) + { + 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; + } + } + 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); + } + + //normalize normals + for (U32 i = 0; i < mNumVertices; i++) + { + //bump map/planar projection code requires normals to be normalized + mNormals[i].normalize3fast(); + } + } } void LLVolumeFace::resizeVertices(S32 num_verts) @@ -6511,10 +6718,11 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con mNumVertices++; } -void LLVolumeFace::allocateTangents(S32 num_verts) +void LLVolumeFace::allocateTangents(S32 num_verts, bool mikktspace) { - ll_aligned_free_16(mTangents); - mTangents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + auto& buff = mikktspace ? mMikktSpaceTangents : mTangents; + ll_aligned_free_16(buff); + buff = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); } void LLVolumeFace::allocateWeights(S32 num_verts) diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 9697952f5b..8c604c5d1a 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -870,10 +870,10 @@ private: public: BOOL create(LLVolume* volume, BOOL partial_build = FALSE); - void createTangents(); + void createTangents(bool mikktspace = false); void resizeVertices(S32 num_verts); - void allocateTangents(S32 num_verts); + void allocateTangents(S32 num_verts, bool mikktspace = false); void allocateWeights(S32 num_verts); void allocateJointIndices(S32 num_verts); void resizeIndices(S32 num_indices); @@ -947,6 +947,7 @@ public: LLVector4a* mPositions; // Contains vertices, nortmals and texcoords LLVector4a* mNormals; // pointer into mPositions LLVector4a* mTangents; + LLVector4a* mMikktSpaceTangents = nullptr; // for GLTF rendering, use mikkt space tangents LLVector2* mTexCoords; // pointer into mPositions // mIndices contains mNumIndices amount of elements. @@ -1028,7 +1029,7 @@ public: void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); } void regen(); - void genTangents(S32 face); + void genTangents(S32 face, bool mikktspace = false); BOOL isConvex() const; BOOL isCap(S32 face); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index cd33690075..9508c1dc2d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10558,6 +10558,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>RenderUseMikktSpace</key> + <map> + <key>Comment</key> + <string>Use Mikkt Space tangents on GLTF materials.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>RenderUseTriStrips</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl index f5b5698305..69019667de 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl @@ -42,6 +42,8 @@ uniform vec3 emissiveColor; #ifdef HAS_NORMAL_MAP uniform sampler2D bumpMap; + VARYING vec3 vary_tangent; + flat in float vary_sign; #endif #ifdef HAS_EMISSIVE_MAP @@ -66,9 +68,6 @@ VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; #ifdef HAS_NORMAL_MAP VARYING vec3 vary_normal; -VARYING vec3 vary_mat0; -VARYING vec3 vary_mat1; -VARYING vec3 vary_mat2; VARYING vec2 vary_texcoord1; #endif @@ -94,21 +93,14 @@ void main() vec3 col = vertex_color.rgb * albedo.rgb; -#ifdef HAS_NORMAL_MAP - vec4 norm = texture2D(bumpMap, vary_texcoord1.xy); - norm.xyz = normalize(norm.xyz * 2 - 1); - - vec3 tnorm = vec3(dot(norm.xyz,vary_mat0), - dot(norm.xyz,vary_mat1), - dot(norm.xyz,vary_mat2)); -#else - vec4 norm = vec4(0,0,0,1.0); -// vec3 tnorm = vary_normal; - vec3 tnorm = vec3(0,0,1); -#endif + // from mikktspace.com + vec4 vNt = texture2D(bumpMap, vary_texcoord1.xy)*2.0-1.0; + float sign = vary_sign; + vec3 vN = vary_normal; + vec3 vT = vary_tangent.xyz; - tnorm = normalize(tnorm.xyz); - norm.xyz = tnorm.xyz; + vec3 vB = sign * cross(vN, vT); + vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); // RGB = Occlusion, Roughness, Metal // default values, see LLViewerTexture::sDefaultPBRORMImagep @@ -155,6 +147,9 @@ void main() tnorm *= gl_FrontFacing ? 1.0 : -1.0; + //col = vec3(0,0,0); + //emissive = vary_tangent.xyz*0.5+0.5; + //emissive = vec3(vary_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 diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl index a2606ed771..e17d91af38 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl @@ -59,13 +59,7 @@ ATTRIBUTE vec2 texcoord0; ATTRIBUTE vec4 tangent; ATTRIBUTE vec2 texcoord1; -VARYING vec3 vary_mat0; -VARYING vec3 vary_mat1; -VARYING vec3 vary_mat2; - VARYING vec2 vary_texcoord1; -#else -VARYING vec3 vary_normal; #endif #ifdef HAS_SPECULAR_MAP @@ -75,6 +69,10 @@ VARYING vec2 vary_texcoord2; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +VARYING vec3 vary_tangent; +flat out float vary_sign; + +VARYING vec3 vary_normal; void main() { @@ -113,9 +111,9 @@ void main() 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); + //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 @@ -123,12 +121,16 @@ vary_normal = n; vec3 n = normalize(normal_matrix * normal); #ifdef HAS_NORMAL_MAP vec3 t = normalize(normal_matrix * tangent.xyz); - vec3 b = cross(n,t)*tangent.w; + vary_tangent = t; + vary_sign = tangent.w; + vary_normal = n; + + //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); + //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 diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 52aacb607c..f35b4b6d91 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -2166,14 +2166,19 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range); F32* tangents = (F32*) tangent.get(); - mVObjp->getVolume()->genTangents(f); + LLGLTFMaterial* gltf_mat = tep->getGLTFMaterial(); + static LLCachedControl<bool> use_mikktspace(gSavedSettings, "RenderUseMikktSpace"); + bool mikktspace = use_mikktspace && gltf_mat != nullptr; + + mVObjp->getVolume()->genTangents(f, mikktspace); LLVector4Logical mask; mask.clear(); mask.setElement<3>(); - LLVector4a* src = vf.mTangents; - LLVector4a* end = vf.mTangents+num_vertices; + LLVector4a* tbuff = mikktspace ? vf.mMikktSpaceTangents : vf.mTangents; + LLVector4a* src = tbuff; + LLVector4a* end = tbuff+num_vertices; while (src < end) { |