Merge branch 'release/materials_featurette' of https://github.com/secondlife/viewer

# Conflicts:
#	indra/newview/CMakeLists.txt
#	indra/newview/llmanip.cpp
#	indra/newview/llmaniptranslate.cpp
#	indra/newview/llselectmgr.h
#	indra/newview/pipeline.h
master
Ansariel 2024-04-24 22:05:15 +02:00
commit f4250bcfaf
79 changed files with 2967 additions and 1501 deletions

View File

@ -2098,6 +2098,18 @@
</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, Copyright (C) 2022 Blender Authors</string>
<key>description</key>
<string>Mikktspace Tangent Generator</string>
<key>license</key>
<string>Apache 2.0</string>
<key>license_file</key>
<string>mikktspace.txt</string>
<key>name</key>
<string>mikktspace</string>
<key>platforms</key>
<map>
<key>darwin64</key>
@ -2105,58 +2117,46 @@
<key>archive</key>
<map>
<key>hash</key>
<string>6cc1585dba85b0226a2e7033a7e2a2ceaae7c983</string>
<string>65edf85c36a10001e32bdee582bec4732137208b</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-darwin64-5cee1f4.tar.zst</string>
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-darwin64-8756084692.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>6b7d01ad54e4a88a001f66840c32329cedb28202</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-windows64-5cee1f4.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>edc9782bf209e17ad1845498b42f16d733582082</string>
<string>fa9dcee4584df7e7271fdf69c08e6fd3122a47fc</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-linux64-5cee1f4.tar.zst</string>
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-linux64-8756084692.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>130b33a70bdb3a8a188376c6a91840bdb61380a8</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-windows64-8756084692.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>license</key>
<string>Copyright (C) 2011 by Morten S. Mikkelsen</string>
<key>license_file</key>
<string>mikktspace.txt</string>
<key>copyright</key>
<string>Copyright (C) 2011 by Morten S. Mikkelsen</string>
<key>version</key>
<string>1</string>
<key>name</key>
<string>mikktspace</string>
<key>canonical_repo</key>
<string>https://bitbucket.org/lindenlab/3p-mikktspace</string>
<key>description</key>
<string>Mikktspace Tangent Generator</string>
</map>
<key>minizip-ng</key>
<map>
@ -2525,76 +2525,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>description</key>
<string>OpenAL Soft is a software implementation of the OpenAL 3D audio API.</string>
</map>
<key>openexr</key>
<map>
<key>canonical_repo</key>
<string>https://github.com/secondlife/3p-openexr</string>
<key>copyright</key>
<string>Copyright (c) Contributors to the OpenEXR Project. All rights reserved.</string>
<key>description</key>
<string>OpenEXR provides the specification and reference implementation of the EXR file format, the professional-grade image storage format of the motion picture industry.</string>
<key>license</key>
<string>OpenEXR</string>
<key>license_file</key>
<string>LICENSES/openexr.txt</string>
<key>name</key>
<string>openexr</string>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>17cd63922214b588d9a36137fadf927237ec0f25</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openexr/releases/download/v1.10/openexr-3.2.2-darwin64-df7544d.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>b092658ab5ec009a5875e8b6e5b7109730ad6846</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openexr/releases/download/v1.10/openexr-3.2.2-linux64-df7544d.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>c511ae9a3e401375af2199b498a75f32cebc010f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openexr/releases/download/v1.10/openexr-3.2.2-windows64-df7544d.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>source_type</key>
<string>git</string>
<key>vcs_branch</key>
<string>debug_autobuild</string>
<key>vcs_revision</key>
<string>5cd1075295c17b5f7085e83d5c16b13c7ecb2eb1</string>
<key>vcs_url</key>
<string>https://github.com/secondlife/3p-openexr</string>
<key>version</key>
<string>3.2.2</string>
</map>
<key>openjpeg</key>
<map>
<key>platforms</key>
@ -3419,6 +3349,46 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>description</key>
<string>zlib data compression library for the next generation systems</string>
</map>
<key>tinyexr</key>
<map>
<key>platforms</key>
<map>
<key>common</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>9e0092c6a3aed1cb40a9e26df689c42c68142c9d</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-tinyexr/releases/download/v1.0.8-r1/tinyexr-v1.0.8-common-8755737750.tar.zst</string>
</map>
<key>name</key>
<string>common</string>
</map>
</map>
<key>license</key>
<string>3-clause BSD</string>
<key>license_file</key>
<string>LICENSES/tinyexr_license.txt</string>
<key>copyright</key>
<string>Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.</string>
<key>version</key>
<string>v1.0.8</string>
<key>name</key>
<string>tinyexr</string>
<key>vcs_branch</key>
<string>dependabot/github_actions/secondlife/action-autobuild-4</string>
<key>vcs_revision</key>
<string>4dc4d1d90d82a22843e2adf5130f9ecb5ee5769e</string>
<key>vcs_url</key>
<string>https://github.com/secondlife/3p-tinyexr</string>
<key>description</key>
<string>tinyexr import library</string>
<key>source_type</key>
<string>git</string>
</map>
</map>
<key>package_description</key>
<map>

View File

@ -58,6 +58,8 @@ set(cmake_SOURCE_FILES
PulseAudio.cmake
Python.cmake
TemplateCheck.cmake
TinyEXR.cmake
TinyGLTF.cmake
Tut.cmake
UI.cmake
UnixInstall.cmake

View File

@ -61,12 +61,6 @@ if(WINDOWS)
glod.dll # <FS:Beq> restore GLOD
libhunspell.dll
uriparser.dll
Iex-3_2.dll
IlmThread-3_2.dll
Imath-3_1.dll
OpenEXR-3_2.dll
OpenEXRCore-3_2.dll
OpenEXRUtil-3_2.dll
)
# ICU4C (same filenames for 32 and 64 bit builds)

View File

@ -1,18 +0,0 @@
# -*- cmake -*-
include(Prebuilt)
include_guard()
add_library( ll::openexr INTERFACE IMPORTED )
if(USE_CONAN )
target_link_libraries( ll::openexr INTERFACE CONAN_PKG::openexr )
return()
endif()
use_prebuilt_binary(openexr)
target_link_libraries( ll::openexr INTERFACE Iex-3_2 IlmThread-3_2 Imath-3_1 OpenEXR-3_2 OpenEXRCore-3_2 OpenEXRUtil-3_2)
target_include_directories( ll::openexr SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/OpenEXR ${LIBS_PREBUILT_DIR}/include/Imath)

View File

@ -0,0 +1,7 @@
# -*- cmake -*-
include(Prebuilt)
use_prebuilt_binary(tinyexr)
set(TINYEXR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tinyexr)

View File

@ -37,8 +37,8 @@ template <class Object> class LLStrider
};
U32 mSkip;
public:
LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); }
LLStrider(Object* first) { mObjectp = first; mSkip = sizeof(Object); }
~LLStrider() { }
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}

View File

@ -34,8 +34,8 @@
class LLMatrix4a
{
public:
LL_ALIGN_16(LLVector4a mMatrix[4]);
LL_ALIGN_16(LLVector4a mMatrix[4]);
LLMatrix4a()
{
@ -56,6 +56,16 @@ public:
return (F32*)&mMatrix;
}
inline LLMatrix4& asMatrix4()
{
return *(LLMatrix4*)this;
}
inline const LLMatrix4& asMatrix4() const
{
return *(LLMatrix4*)this;
}
inline void clear()
{
mMatrix[0].clear();

View File

@ -53,8 +53,7 @@
#include "lltimer.h"
#include "llvolumeoctree.h"
#include "mikktspace/mikktspace.h"
#include "mikktspace/mikktspace.c" // insert mikktspace implementation into llvolume object file
#include "mikktspace/mikktspace.hh"
#include "meshoptimizer/meshoptimizer.h"
@ -5474,6 +5473,40 @@ struct MikktData
}
}
}
uint32_t GetNumFaces()
{
return uint32_t(face->mNumIndices / 3);
}
uint32_t GetNumVerticesOfFace(const uint32_t face_num)
{
return 3;
}
mikk::float3 GetPosition(const uint32_t face_num, const uint32_t vert_num)
{
F32* v = p[face_num * 3 + vert_num].mV;
return mikk::float3(v);
}
mikk::float3 GetTexCoord(const uint32_t face_num, const uint32_t vert_num)
{
F32* uv = tc[face_num * 3 + vert_num].mV;
return mikk::float3(uv[0], uv[1], 1.0f);
}
mikk::float3 GetNormal(const uint32_t face_num, const uint32_t vert_num)
{
F32* normal = n[face_num * 3 + vert_num].mV;
return mikk::float3(normal);
}
void SetTangentSpace(const uint32_t face_num, const uint32_t vert_num, mikk::float3 T, bool orientation)
{
S32 i = face_num * 3 + vert_num;
t[i].set(T.x, T.y, T.z, orientation ? 1.0f : -1.0f);
}
};
bool LLVolumeFace::cacheOptimize(bool gen_tangents)
@ -5486,62 +5519,9 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
{ // generate mikkt space tangents before cache optimizing since the index buffer may change
// a bit of a hack to do this here, but this function gets called exactly once for the lifetime of a mesh
// and is executed on a background thread
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;
F32* v = data->p[iFace * 3 + iVert].mV;
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;
F32* n = data->n[iFace * 3 + iVert].mV;
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;
F32* tc = data->tc[iFace * 3 + iVert].mV;
fvTexcOut[0] = tc[0];
fvTexcOut[1] = tc[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;
S32 i = iFace * 3 + iVert;
data->t[i].set(fvTangent);
data->t[i].mV[3] = fSign;
};
ms.m_setTSpace = nullptr;
MikktData data(this);
SMikkTSpaceContext ctx = { &ms, &data };
genTangSpaceDefault(&ctx);
mikk::Mikktspace ctx(data);
ctx.genTangSpace();
//re-weld
meshopt_Stream mos[] =
@ -5562,9 +5542,6 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
if (vert_count < 65535 && vert_count != 0)
{
std::vector<U32> indices;
indices.resize(mNumIndices);
//copy results back into volume
resizeVertices(vert_count);

View File

@ -62,7 +62,7 @@ public:
LL_ALIGN_16(LLVector4a mPositionGroup);
const LLVector4a* mV[3];
U16 mIndex[3];
U32 mIndex[3];
F32 mRadius;
mutable S32 mBinIndex;

View File

@ -49,7 +49,6 @@ public:
bool hasShadows = false;
bool hasAmbientOcclusion = false;
bool hasSrgb = false;
bool encodesNormal = false; // include: shaders\class1\environment\encodeNormF.glsl
bool isDeferred = false;
bool hasScreenSpaceReflections = false;
bool disableTextureIndex = false;

View File

@ -2124,10 +2124,6 @@ void LLRender::diffuseColor3f(F32 r, F32 g, F32 b)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f);
}
else
{
glColor3f(r,g,b);
}
}
void LLRender::diffuseColor3fv(const F32* c)
@ -2139,10 +2135,6 @@ void LLRender::diffuseColor3fv(const F32* c)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f);
}
else
{
glColor3fv(c);
}
}
void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
@ -2154,10 +2146,6 @@ void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a);
}
else
{
glColor4f(r,g,b,a);
}
}
void LLRender::diffuseColor4fv(const F32* c)
@ -2169,10 +2157,6 @@ void LLRender::diffuseColor4fv(const F32* c)
{
shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c);
}
else
{
glColor4fv(c);
}
}
void LLRender::diffuseColor4ubv(const U8* c)
@ -2184,10 +2168,6 @@ void LLRender::diffuseColor4ubv(const U8* c)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f);
}
else
{
glColor4ubv(c);
}
}
void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a)
@ -2199,10 +2179,6 @@ void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f);
}
else
{
glColor4ub(r,g,b,a);
}
}

View File

@ -264,14 +264,6 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
if (features->encodesNormal)
{
if (!shader->attachFragmentObject("environment/encodeNormF.glsl"))
{
return FALSE;
}
}
if (features->hasAtmospherics || features->isDeferred)
{
if (!shader->attachFragmentObject("windlight/atmosphericsFuncs.glsl")) {

View File

@ -757,8 +757,8 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
llassert(mGLBuffer == sGLRenderBuffer);
llassert(mGLIndices == sGLRenderIndices);
gGL.syncMatrices();
glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
(GLvoid*) (indices_offset * sizeof(U16)));
glDrawRangeElements(sGLMode[mode], start, end, count, mIndicesType,
(GLvoid*) (indices_offset * (size_t) mIndicesStride));
}
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
@ -1155,7 +1155,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
}
// flush the given byte range
// target -- "targret" parameter for glBufferSubData
// target -- "target" parameter for glBufferSubData
// start -- first byte to copy
// end -- last byte to copy (NOT last byte + 1)
// data -- mMappedData or mMappedIndexData
@ -1317,6 +1317,8 @@ bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, U32 index,
}
bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, U32 index, S32 count)
{
llassert(mIndicesStride == 2); // cannot access 32-bit indices with U16 strider
llassert(mIndicesType == GL_UNSIGNED_SHORT);
return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count);
}
bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index, S32 count)
@ -1534,4 +1536,39 @@ void LLVertexBuffer::setColorData(const LLColor4U* data)
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data);
}
void LLVertexBuffer::setNormalData(const LLVector4a* data)
{
llassert(sGLRenderBuffer == mGLBuffer);
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + sTypeSize[TYPE_NORMAL] * getNumVerts() - 1, (U8*) data);
}
void LLVertexBuffer::setTangentData(const LLVector4a* data)
{
llassert(sGLRenderBuffer == mGLBuffer);
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + sTypeSize[TYPE_TANGENT] * getNumVerts() - 1, (U8*) data);
}
void LLVertexBuffer::setWeight4Data(const LLVector4a* data)
{
llassert(sGLRenderBuffer == mGLBuffer);
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + sTypeSize[TYPE_WEIGHT4] * getNumVerts() - 1, (U8*) data);
}
void LLVertexBuffer::setIndexData(const U16* data)
{
llassert(sGLRenderIndices == mGLIndices);
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U16) * getNumIndices() - 1, (U8*) data);
}
void LLVertexBuffer::setIndexData(const U32* data)
{
llassert(sGLRenderIndices == mGLIndices);
if (mIndicesType != GL_UNSIGNED_INT)
{ // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices
mIndicesType = GL_UNSIGNED_INT;
mIndicesStride = 4;
mNumIndices /= 2;
}
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U32) * getNumIndices() - 1, (U8*)data);
}

View File

@ -194,9 +194,13 @@ public:
// </FS:Ansariel>
void setPositionData(const LLVector4a* data);
void setNormalData(const LLVector4a* data);
void setTangentData(const LLVector4a* data);
void setWeight4Data(const LLVector4a* data);
void setTexCoordData(const LLVector2* data);
void setColorData(const LLColor4U* data);
void setIndexData(const U16* data);
void setIndexData(const U32* data);
U32 getNumVerts() const { return mNumVerts; }
U32 getNumIndices() const { return mNumIndices; }
@ -228,6 +232,8 @@ protected:
U32 mGLIndices = 0; // GL IBO handle
U32 mNumVerts = 0; // Number of vertices allocated
U32 mNumIndices = 0; // Number of indices allocated
U32 mIndicesType = GL_UNSIGNED_SHORT; // type of indices in index buffer
U32 mIndicesStride = 2; // size of each index in bytes
U32 mOffsets[TYPE_MAX]; // byte offsets into mMappedData of each attribute
U8* mMappedData = nullptr; // pointer to currently mapped data (NULL if unmapped)

View File

@ -35,11 +35,11 @@ include(LLWindow)
include(NDOF)
include(NVAPI)
include(OPENAL)
include(OpenEXR)
include(OpenGL)
include(OpenSSL)
include(PNG)
include(TemplateCheck)
include(TinyEXR)
include(ThreeJS)
include(Tracy)
include(UI)
@ -187,7 +187,9 @@ set(viewer_SOURCE_FILES
gltfscenemanager.cpp
gltf/asset.cpp
gltf/accessor.cpp
gltf/primitive.cpp
gltf/animation.cpp
groupchatlistener.cpp
llaccountingcostmanager.cpp
llaisapi.cpp
@ -986,7 +988,10 @@ set(viewer_HEADER_FILES
gltfscenemanager.h
groupchatlistener.h
gltf/asset.h
gltf/accessor.h
gltf/buffer_util.h
gltf/primitive.h
gltf/animation.h
llaccountingcost.h
llaccountingcostmanager.h
llaisapi.h
@ -2184,12 +2189,6 @@ if (WINDOWS)
media_plugin_cef
media_plugin_libvlc
#media_plugin_example # <FS:Ansariel> Don't package example plugin
${SHARED_LIB_STAGING_DIR}/Iex-3_2.dll
${SHARED_LIB_STAGING_DIR}/IlmThread-3_2.dll
${SHARED_LIB_STAGING_DIR}/Imath-3_1.dll
${SHARED_LIB_STAGING_DIR}/OpenEXR-3_2.dll
${SHARED_LIB_STAGING_DIR}/OpenEXRCore-3_2.dll
${SHARED_LIB_STAGING_DIR}/OpenEXRUtil-3_2.dll
)
# <FS:Ansariel> Only copy OpenJPEG dll if needed
@ -2397,7 +2396,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}
ll::bugsplat
ll::tracy
ll::icu4c
ll::openexr
fs::glod # <FS:Beq/> restore GLOD dependencies
fs::discord # <FS:Ansariel> Discord support
)

View File

@ -25,7 +25,7 @@
/*[EXTRA_CODE_HERE]*/
out vec4 frag_data[3];
out vec4 frag_data[4];
uniform sampler2D diffuseMap;
@ -35,7 +35,6 @@ in vec3 vary_normal;
in vec2 vary_texcoord0;
in vec3 vary_position;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
@ -52,6 +51,7 @@ void main()
frag_data[0] = vec4(diff.rgb, 0.0);
frag_data[1] = vec4(0,0,0,0);
vec3 nvn = normalize(vary_normal);
frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS);
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
}

View File

@ -40,12 +40,12 @@ uniform float kern_scale;
in vec2 vary_fragcoord;
vec4 getPosition(vec2 pos_screen);
vec3 getNorm(vec2 pos_screen);
vec4 getNorm(vec2 pos_screen);
void main()
{
vec2 tc = vary_fragcoord.xy;
vec3 norm = getNorm(tc);
vec4 norm = getNorm(tc);
vec3 pos = getPosition(tc).xyz;
vec4 ccol = texture(lightMap, tc).rgba;

View File

@ -39,8 +39,6 @@ in vec4 vertex_color;
in vec2 vary_texcoord0;
in vec3 vary_position;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
{
@ -64,6 +62,6 @@ void main()
frag_data[1] = vertex_color.aaaa; // spec
//frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
vec3 nvn = normalize(tnorm);
frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
frag_data[2] = vec4(nvn, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(vertex_color.a, 0, 0, 0);
}

View File

@ -50,6 +50,7 @@ SOFTWARE.
uniform sampler2D normalMap;
uniform sampler2D depthMap;
uniform sampler2D emissiveRect;
uniform sampler2D projectionMap; // rgba
uniform sampler2D brdfLut;
@ -140,40 +141,20 @@ vec2 getScreenCoordinate(vec2 screenpos)
return sc - vec2(1.0, 1.0);
}
// See: https://aras-p.info/texts/CompactNormalStorage.html
// Method #4: Spheremap Transform, Lambert Azimuthal Equal-Area projection
vec3 getNorm(vec2 screenpos)
vec4 getNorm(vec2 screenpos)
{
vec2 enc = texture(normalMap, screenpos.xy).xy;
vec2 fenc = enc*4-2;
float f = dot(fenc,fenc);
float g = sqrt(1-f/4);
vec3 n;
n.xy = fenc*g;
n.z = 1-f/2;
return n;
}
vec3 getNormalFromPacked(vec4 packedNormalEnvIntensityFlags)
{
vec2 enc = packedNormalEnvIntensityFlags.xy;
vec2 fenc = enc*4-2;
float f = dot(fenc,fenc);
float g = sqrt(1-f/4);
vec3 n;
n.xy = fenc*g;
n.z = 1-f/2;
return normalize(n); // TODO: Is this normalize redundant?
return texture(normalMap, screenpos.xy);
}
// return packedNormalEnvIntensityFlags since GBUFFER_FLAG_HAS_PBR needs .w
// See: C++: addDeferredAttachments(), GLSL: softenLightF
vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity)
{
vec4 packedNormalEnvIntensityFlags = texture(normalMap, screenpos.xy);
n = getNormalFromPacked( packedNormalEnvIntensityFlags );
envIntensity = packedNormalEnvIntensityFlags.z;
return packedNormalEnvIntensityFlags;
vec4 norm = texture(normalMap, screenpos.xy);
n = norm.xyz;
envIntensity = texture(emissiveRect, screenpos.xy).r;
return norm;
}
// get linear depth value given a depth buffer sample d and znear and zfar values

View File

@ -37,8 +37,6 @@ in vec3 vary_normal;
in vec4 vertex_color;
in vec2 vary_texcoord0;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
@ -55,7 +53,7 @@ void main()
frag_data[0] = vec4(col.rgb, 0.0);
frag_data[1] = vec4(0,0,0,0); // spec
vec3 nvn = normalize(vary_normal);
frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS);
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
}

View File

@ -35,8 +35,6 @@ uniform float minimum_alpha;
in vec4 vertex_color;
in vec2 vary_texcoord0;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
@ -53,6 +51,6 @@ void main()
frag_data[0] = vec4(col.rgb, 0.0);
frag_data[1] = vec4(0,0,0,0);
vec3 nvn = normalize(vary_normal);
frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS);
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
}

View File

@ -34,8 +34,6 @@ uniform sampler2D diffuseMap;
in vec3 vary_normal;
in vec2 vary_texcoord0;
vec2 encode_normal(vec3 n);
void main()
{
vec4 col = texture(diffuseMap, vary_texcoord0.xy);
@ -48,7 +46,7 @@ void main()
frag_data[0] = vec4(col.rgb, 0.0);
frag_data[1] = vec4(0,0,0,0); // spec
vec3 nvn = normalize(vary_normal);
frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS);
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
}

View File

@ -34,7 +34,6 @@ in vec4 vertex_color;
in vec2 vary_texcoord0;
in vec3 vary_position;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
@ -45,7 +44,7 @@ void main()
frag_data[1] = vertex_color.aaaa; // spec
//frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
vec3 nvn = normalize(vary_normal);
frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(vertex_color.a, 0, 0, 0);
}

View File

@ -33,7 +33,6 @@ in vec2 vary_texcoord0;
in vec3 vary_position;
void mirrorClip(vec3 pos);
vec2 encode_normal(vec3 n);
vec3 linear_to_srgb(vec3 c);
void main()
@ -47,6 +46,6 @@ void main()
frag_data[0] = vec4(col, 0.0);
frag_data[1] = vec4(spec, vertex_color.a); // spec
vec3 nvn = normalize(vary_normal);
frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(vertex_color.a, 0, 0, 0);
}

View File

@ -37,7 +37,6 @@ uniform sampler2D specularMap;
in vec2 vary_texcoord0;
vec3 linear_to_srgb(vec3 c);
vec2 encode_normal (vec3 n);
void main()
{
@ -53,6 +52,6 @@ void main()
frag_data[0] = vec4(col.rgb, 0.0);
frag_data[1] = spec;
frag_data[2] = vec4(encode_normal(norm.xyz),0,GBUFFER_FLAG_HAS_ATMOS);
frag_data[2] = vec4(norm.xyz, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
}

View File

@ -54,7 +54,6 @@ in vec2 emissive_texcoord;
uniform float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff()
vec2 encode_normal(vec3 n);
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
@ -110,7 +109,7 @@ void main()
// See: C++: addDeferredAttachments(), GLSL: softenLightF
frag_data[0] = max(vec4(col, 0.0), vec4(0)); // Diffuse
frag_data[1] = max(vec4(spec.rgb,vertex_color.a), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal.
frag_data[2] = max(vec4(encode_normal(tnorm), vertex_color.a, GBUFFER_FLAG_HAS_PBR), vec4(0)); // normal, environment intensity, flags
frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags
frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive
}

View File

@ -140,7 +140,6 @@ flat in float vary_sign;
in vec4 vary_texcoord0;
in vec4 vary_texcoord1;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 position);
float terrain_mix(TerrainMix tm, vec4 tms4);
@ -342,7 +341,7 @@ void main()
#endif
frag_data[0] = max(vec4(mix.col.xyz, 0.0), vec4(0)); // Diffuse
frag_data[1] = max(vec4(orm.rgb, base_color_factor_alpha), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal.
frag_data[2] = max(vec4(encode_normal(tnorm), base_color_factor_alpha, GBUFFER_FLAG_HAS_PBR), vec4(0)); // normal, environment intensity, flags
frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, flags
frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive
}

View File

@ -38,7 +38,6 @@ in vec3 vary_normal;
in vec4 vary_texcoord0;
in vec4 vary_texcoord1;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 position);
void main()
@ -61,7 +60,7 @@ void main()
frag_data[0] = outColor;
frag_data[1] = vec4(0.0,0.0,0.0,-1.0);
vec3 nvn = normalize(vary_normal);
frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS);
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
}

View File

@ -36,8 +36,6 @@ in vec3 vary_position;
uniform float minimum_alpha;
vec2 encode_normal(vec3 n);
void mirrorClip(vec3 pos);
void main()
{
@ -51,6 +49,6 @@ void main()
frag_data[0] = vec4(vertex_color.rgb*col.rgb, 0.0);
frag_data[1] = vec4(0,0,0,0);
vec3 nvn = normalize(vary_normal);
frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS);
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
frag_data[3] = vec4(0);
}

View File

@ -1,34 +0,0 @@
/**
* @file encodeNormF.glsl
*
* $LicenseInfo:firstyear=2018&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2018, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
// Lambert Azimuthal Equal-Area projection
// See: https://aras-p.info/texts/CompactNormalStorage.html
// Also see: A_bit_more_deferred_-_CryEngine3.ppt
vec2 encode_normal(vec3 n)
{
float f = sqrt(8 * n.z + 8);
return n.xy / f + 0.5;
}

View File

@ -68,7 +68,6 @@ void waterClip(vec3 pos);
vec3 srgb_to_linear(vec3 c);
vec3 linear_to_srgb(vec3 c);
vec2 encode_normal (vec3 n);
vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);

View File

@ -35,7 +35,7 @@ in vec2 vary_fragcoord;
uniform vec3 sun_dir;
uniform float shadow_bias;
vec3 getNorm(vec2 pos_screen);
vec4 getNorm(vec2 pos_screen);
vec4 getPosition(vec2 pos_screen);
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
@ -45,13 +45,13 @@ void main()
{
vec2 pos_screen = vary_fragcoord.xy;
vec4 pos = getPosition(pos_screen);
vec3 norm = getNorm(pos_screen);
vec4 norm = getNorm(pos_screen);
vec4 col;
col.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen);
col.r = sampleDirectionalShadow(pos.xyz, norm.xyz, pos_screen);
col.g = 1.0f;
col.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen);
col.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen);
col.b = sampleSpotShadow(pos.xyz, norm.xyz, 0, pos_screen);
col.a = sampleSpotShadow(pos.xyz, norm.xyz, 1, pos_screen);
frag_color = clamp(col, vec4(0), vec4(1));
}

View File

@ -32,7 +32,7 @@ out vec4 frag_color;
in vec2 vary_fragcoord;
vec4 getPosition(vec2 pos_screen);
vec3 getNorm(vec2 pos_screen);
vec4 getNorm(vec2 pos_screen);
float sampleDirectionalShadow(vec3 shadow_pos, vec3 norm, vec2 pos_screen);
float sampleSpotShadow(vec3 shadow_pos, vec3 norm, int index, vec2 pos_screen);
@ -42,13 +42,13 @@ void main()
{
vec2 pos_screen = vary_fragcoord.xy;
vec4 pos = getPosition(pos_screen);
vec3 norm = getNorm(pos_screen);
vec4 norm = getNorm(pos_screen);
vec4 col;
col.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen);
col.g = calcAmbientOcclusion(pos, norm, pos_screen);
col.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen);
col.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen);
col.r = sampleDirectionalShadow(pos.xyz, norm.xyz, pos_screen);
col.g = calcAmbientOcclusion(pos, norm.xyz, pos_screen);
col.b = sampleSpotShadow(pos.xyz, norm.xyz, 0, pos_screen);
col.a = sampleSpotShadow(pos.xyz, norm.xyz, 1, pos_screen);
frag_color = clamp(col, vec4(0), vec4(1));
}

View File

@ -33,7 +33,7 @@ uniform vec3 moon_dir;
uniform int sun_up_factor;
in vec2 vary_fragcoord;
vec3 getNorm(vec2 pos_screen);
vec4 getNorm(vec2 pos_screen);
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
@ -53,8 +53,7 @@ void main()
vec2 tc = vary_fragcoord.xy;
float depth = getDepth(tc.xy);
vec4 pos = getPositionWithDepth(tc, depth);
vec4 norm = texture(normalMap, tc);
norm.xyz = getNorm(tc);
vec4 norm = getNorm(tc);
vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;
vec3 color = vec3(0);

View File

@ -216,8 +216,6 @@ in vec3 vary_normal;
in vec4 vertex_color;
in vec2 vary_texcoord0;
vec2 encode_normal(vec3 n);
// get the transformed normal and apply glossiness component from normal map
vec3 getNormal(inout float glossiness)
{
@ -306,8 +304,6 @@ void main()
float glossiness = specular_color.a;
vec3 norm = getNormal(glossiness);
vec2 abnormal = encode_normal(norm.xyz);
float emissive = getEmissive(diffcol);
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
@ -417,10 +413,12 @@ void main()
float flag = GBUFFER_FLAG_HAS_ATMOS;
frag_data[0] = vec4(diffcol.rgb, emissive); // gbuffer is sRGB for legacy materials
frag_data[1] = vec4(spec.rgb, glossiness); // XYZ = Specular color. W = Specular exponent.
frag_data[2] = vec4(encode_normal(norm), env, flag);; // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog)
frag_data[3] = vec4(0);
frag_data[0] = max(vec4(diffcol.rgb, emissive), vec4(0)); // gbuffer is sRGB for legacy materials
frag_data[1] = max(vec4(spec.rgb, glossiness), vec4(0)); // XYZ = Specular color. W = Specular exponent.
frag_data[2] = vec4(norm, flag); // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog)
frag_data[3] = vec4(env, 0, 0, 0);
#endif
}

View File

@ -48,7 +48,7 @@ in vec4 vary_fragcoord;
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
float calcLegacyDistanceAttenuation(float distance, float falloff);
vec4 getPosition(vec2 pos_screen);
vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity);
vec4 getNorm(vec2 screenpos);
vec2 getScreenXY(vec4 clip);
vec2 getScreenCoord(vec4 clip);
vec3 srgb_to_linear(vec3 c);
@ -74,9 +74,8 @@ void main()
discard;
}
float envIntensity; // not used for this shader
vec3 n;
vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG()
vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG()
vec3 n = norm.xyz;
vec4 spec = texture(specularRect, tc);
vec3 diffuse = texture(diffuseRect, tc).rgb;

View File

@ -52,7 +52,7 @@ uniform vec4 viewport;
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
float calcLegacyDistanceAttenuation(float distance, float falloff);
vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity);
vec4 getNorm(vec2 screenpos);
vec4 getPosition(vec2 pos_screen);
vec2 getScreenXY(vec4 clip);
vec2 getScreenCoord(vec4 clip);
@ -72,9 +72,8 @@ void main()
vec2 tc = getScreenCoord(vary_fragcoord);
vec3 pos = getPosition(tc).xyz;
float envIntensity;
vec3 n;
vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG()
vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG()
vec3 n = norm.xyz;
vec3 diffuse = texture(diffuseRect, tc).rgb;
vec4 spec = texture(specularRect, tc);

View File

@ -40,14 +40,13 @@ uniform sampler2D specularRect;
uniform sampler2D diffuseRect;
uniform sampler2D diffuseMap;
vec3 getNorm(vec2 screenpos);
vec4 getNorm(vec2 screenpos);
float getDepth(vec2 pos_screen);
float linearDepth(float d, float znear, float zfar);
float linearDepth01(float d, float znear, float zfar);
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
vec4 getPosition(vec2 pos_screen);
vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity);
float random (vec2 uv);
@ -57,9 +56,7 @@ void main()
{
vec2 tc = vary_fragcoord.xy;
float depth = linearDepth01(getDepth(tc), zNear, zFar);
float envIntensity;
vec3 n;
vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG()
vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG()
vec3 pos = getPositionWithDepth(tc, getDepth(tc)).xyz;
vec4 spec = texture(specularRect, tc);
vec2 hitpixel;
@ -84,7 +81,7 @@ void main()
vec4 collectedColor = vec4(0);
float w = tapScreenSpaceReflection(4, tc, pos, n, collectedColor, diffuseMap, 0);
float w = tapScreenSpaceReflection(4, tc, pos, norm.xyz, collectedColor, diffuseMap, 0);
collectedColor.rgb *= specCol.rgb;

View File

@ -61,7 +61,7 @@ in vec2 vary_fragcoord;
uniform mat4 inv_proj;
uniform vec2 screen_res;
vec3 getNorm(vec2 pos_screen);
vec4 getNorm(vec2 pos_screen);
vec4 getPositionWithDepth(vec2 pos_screen, float depth);
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
@ -128,13 +128,13 @@ void main()
vec2 tc = vary_fragcoord.xy;
float depth = getDepth(tc.xy);
vec4 pos = getPositionWithDepth(tc, depth);
vec4 norm = texture(normalMap, tc);
float envIntensity = norm.z;
norm.xyz = getNorm(tc);
vec4 norm = getNorm(tc);
vec3 colorEmissive = texture(emissiveRect, tc).rgb;
float envIntensity = colorEmissive.r;
vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;
vec4 baseColor = texture(diffuseRect, tc);
vec4 spec = texture(specularRect, vary_fragcoord.xy); // NOTE: PBR linear Emissive
vec4 spec = texture(specularRect, tc); // NOTE: PBR linear Emissive
#if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO)
vec2 scol_ambocc = texture(lightMap, vary_fragcoord.xy).rg;
@ -169,12 +169,12 @@ void main()
if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
{
vec3 orm = texture(specularRect, tc).rgb;
vec3 orm = spec.rgb;
float perceptualRoughness = orm.g;
float metallic = orm.b;
float ao = orm.r;
vec3 colorEmissive = texture(emissiveRect, tc).rgb;
// PBR IBL
float gloss = 1.0 - perceptualRoughness;
@ -192,12 +192,12 @@ void main()
else if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_HDRI))
{
// actual HDRI sky, just copy color value
color = texture(emissiveRect, tc).rgb;
color = colorEmissive.rgb;
}
else if (GET_GBUFFER_FLAG(GBUFFER_FLAG_SKIP_ATMOS))
{
//should only be true of WL sky, port over base color value and scale for fake HDR
color = texture(emissiveRect, tc).rgb;
color = colorEmissive.rgb;
color = srgb_to_linear(color);
color *= sky_hdr_scale;
}

View File

@ -72,7 +72,7 @@ uniform mat4 inv_proj;
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
float calcLegacyDistanceAttenuation(float distance, float falloff);
bool clipProjectedLightVars(vec3 center, vec3 pos, out float dist, out float l_dist, out vec3 lv, out vec4 proj_tc );
vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity);
vec4 getNorm(vec2 screenpos);
vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv);
vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv );
vec2 getScreenCoord(vec4 clip);
@ -121,9 +121,8 @@ void main()
shadow = clamp(shadow, 0.0, 1.0);
}
float envIntensity;
vec3 n;
vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity);
vec4 norm = getNorm(tc);
vec3 n = norm.xyz;
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
if (dist_atten <= 0.0)
@ -145,7 +144,6 @@ void main()
if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
{
vec3 colorEmissive = texture(emissiveRect, tc).rgb;
vec3 orm = spec.rgb;
float perceptualRoughness = orm.g;
float metallic = orm.b;
@ -182,6 +180,8 @@ void main()
}
else
{
float envIntensity = texture(emissiveRect, tc).r;
diffuse = srgb_to_linear(diffuse);
spec.rgb = srgb_to_linear(spec.rgb);

View File

@ -56,7 +56,6 @@ void main()
}
vec4 pos = getPositionWithDepth(tc, depth);
vec4 norm = texture(normalMap, tc);
vec4 fogged = getWaterFogView(pos.xyz);

View File

@ -0,0 +1,66 @@
/**
* @file accessor.cpp
* @brief LL GLTF Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "../llviewerprecompiledheaders.h"
#include "asset.h"
using namespace LL::GLTF;
const Buffer& Buffer::operator=(const tinygltf::Buffer& src)
{
mData = src.data;
mName = src.name;
mUri = src.uri;
return *this;
}
const BufferView& BufferView::operator=(const tinygltf::BufferView& src)
{
mBuffer = src.buffer;
mByteLength = src.byteLength;
mByteOffset = src.byteOffset;
mByteStride = src.byteStride;
mTarget = src.target;
mName = src.name;
return *this;
}
const Accessor& Accessor::operator=(const tinygltf::Accessor& src)
{
mBufferView = src.bufferView;
mByteOffset = src.byteOffset;
mComponentType = src.componentType;
mCount = src.count;
mType = src.type;
mNormalized = src.normalized;
mName = src.name;
mMax = src.maxValues;
mMin = src.minValues;
return *this;
}

View File

@ -0,0 +1,95 @@
#pragma once
/**
* @file asset.h
* @brief LL GLTF Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "../lltinygltfhelper.h"
#include "llstrider.h"
// LL GLTF Implementation
namespace LL
{
namespace GLTF
{
class Asset;
constexpr S32 INVALID_INDEX = -1;
class Buffer
{
public:
std::vector<U8> mData;
std::string mName;
std::string mUri;
const Buffer& operator=(const tinygltf::Buffer& src);
};
class BufferView
{
public:
S32 mBuffer = INVALID_INDEX;
S32 mByteLength;
S32 mByteOffset;
S32 mByteStride;
S32 mTarget;
S32 mComponentType;
std::string mName;
const BufferView& operator=(const tinygltf::BufferView& src);
};
class Accessor
{
public:
S32 mBufferView = INVALID_INDEX;
S32 mByteOffset;
S32 mComponentType;
S32 mCount;
std::vector<double> mMax;
std::vector<double> mMin;
enum class Type : S32
{
SCALAR = TINYGLTF_TYPE_SCALAR,
VEC2 = TINYGLTF_TYPE_VEC2,
VEC3 = TINYGLTF_TYPE_VEC3,
VEC4 = TINYGLTF_TYPE_VEC4,
MAT2 = TINYGLTF_TYPE_MAT2,
MAT3 = TINYGLTF_TYPE_MAT3,
MAT4 = TINYGLTF_TYPE_MAT4
};
S32 mType;
bool mNormalized;
std::string mName;
const Accessor& operator=(const tinygltf::Accessor& src);
};
}
}

View File

@ -0,0 +1,287 @@
/**
* @file animation.cpp
* @brief LL GLTF Animation Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "../llviewerprecompiledheaders.h"
#include "asset.h"
#include "buffer_util.h"
using namespace LL::GLTF;
void Animation::allocateGLResources(Asset& asset)
{
if (!mSamplers.empty())
{
mMinTime = FLT_MAX;
mMaxTime = -FLT_MAX;
for (auto& sampler : mSamplers)
{
sampler.allocateGLResources(asset);
mMinTime = llmin(sampler.mMinTime, mMinTime);
mMaxTime = llmax(sampler.mMaxTime, mMaxTime);
}
}
else
{
mMinTime = mMaxTime = 0.f;
}
for (auto& channel : mRotationChannels)
{
channel.allocateGLResources(asset, mSamplers[channel.mSampler]);
}
for (auto& channel : mTranslationChannels)
{
channel.allocateGLResources(asset, mSamplers[channel.mSampler]);
}
}
void Animation::update(Asset& asset, F32 dt)
{
mTime += dt;
apply(asset, mTime);
}
void Animation::apply(Asset& asset, float time)
{
// convert time to animation loop time
time = fmod(time, mMaxTime - mMinTime) + mMinTime;
// apply each channel
for (auto& channel : mRotationChannels)
{
channel.apply(asset, mSamplers[channel.mSampler], time);
}
for (auto& channel : mTranslationChannels)
{
channel.apply(asset, mSamplers[channel.mSampler], time);
}
};
void Animation::Sampler::allocateGLResources(Asset& asset)
{
Accessor& accessor = asset.mAccessors[mInput];
mMinTime = accessor.mMin[0];
mMaxTime = accessor.mMax[0];
mFrameTimes.resize(accessor.mCount);
LLStrider<F32> frame_times = mFrameTimes.data();
copy(asset, accessor, frame_times);
}
void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t)
{
if (time < mMinTime)
{
frameIndex = 0;
t = 0.0f;
return;
}
if (mFrameTimes.size() > 1)
{
if (time > mMaxTime)
{
frameIndex = mFrameTimes.size() - 2;
t = 1.0f;
return;
}
frameIndex = mFrameTimes.size() - 2;
t = 1.f;
for (U32 i = 0; i < mFrameTimes.size() - 1; i++)
{
if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1])
{
frameIndex = i;
t = (time - mFrameTimes[i]) / (mFrameTimes[i + 1] - mFrameTimes[i]);
return;
}
}
}
else
{
frameIndex = 0;
t = 0.0f;
}
}
void Animation::RotationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler)
{
Accessor& accessor = asset.mAccessors[sampler.mOutput];
copy(asset, accessor, mRotations);
}
void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
{
U32 frameIndex;
F32 t;
Node& node = asset.mNodes[mTarget.mNode];
sampler.getFrameInfo(asset, time, frameIndex, t);
if (sampler.mFrameTimes.size() == 1)
{
node.setRotation(mRotations[0]);
}
else
{
// interpolate
LLQuaternion q0(mRotations[frameIndex].get_value());
LLQuaternion q1(mRotations[frameIndex + 1].get_value());
LLQuaternion qf = slerp(t, q0, q1);
qf.normalize();
node.setRotation(glh::quaternionf(qf.mQ));
}
}
void Animation::TranslationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler)
{
Accessor& accessor = asset.mAccessors[sampler.mOutput];
copy(asset, accessor, mTranslations);
}
void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
{
U32 frameIndex;
F32 t;
Node& node = asset.mNodes[mTarget.mNode];
sampler.getFrameInfo(asset, time, frameIndex, t);
if (sampler.mFrameTimes.size() == 1)
{
node.setTranslation(mTranslations[0]);
}
else
{
// interpolate
const glh::vec3f& v0 = mTranslations[frameIndex];
const glh::vec3f& v1 = mTranslations[frameIndex + 1];
glh::vec3f vf = v0 + t * (v1 - v0);
node.setTranslation(vf);
}
}
void Animation::ScaleChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler)
{
Accessor& accessor = asset.mAccessors[sampler.mOutput];
copy(asset, accessor, mScales);
}
void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time)
{
U32 frameIndex;
F32 t;
Node& node = asset.mNodes[mTarget.mNode];
sampler.getFrameInfo(asset, time, frameIndex, t);
if (sampler.mFrameTimes.size() == 1)
{
node.setScale(mScales[0]);
}
else
{
// interpolate
const glh::vec3f& v0 = mScales[frameIndex];
const glh::vec3f& v1 = mScales[frameIndex + 1];
glh::vec3f vf = v0 + t * (v1 - v0);
node.setScale(vf);
}
}
const Animation& Animation::operator=(const tinygltf::Animation& src)
{
mName = src.name;
mSamplers.resize(src.samplers.size());
for (U32 i = 0; i < src.samplers.size(); ++i)
{
mSamplers[i] = src.samplers[i];
}
for (U32 i = 0; i < src.channels.size(); ++i)
{
if (src.channels[i].target_path == "rotation")
{
mRotationChannels.push_back(RotationChannel());
mRotationChannels.back() = src.channels[i];
}
if (src.channels[i].target_path == "translation")
{
mTranslationChannels.push_back(TranslationChannel());
mTranslationChannels.back() = src.channels[i];
}
if (src.channels[i].target_path == "scale")
{
mScaleChannels.push_back(ScaleChannel());
mScaleChannels.back() = src.channels[i];
}
}
return *this;
}
void Skin::allocateGLResources(Asset& asset)
{
if (mInverseBindMatrices != INVALID_INDEX)
{
Accessor& accessor = asset.mAccessors[mInverseBindMatrices];
copy(asset, accessor, mInverseBindMatricesData);
}
}
const Skin& Skin::operator=(const tinygltf::Skin& src)
{
mName = src.name;
mSkeleton = src.skeleton;
mInverseBindMatrices = src.inverseBindMatrices;
mJoints = src.joints;
return *this;
}

View File

@ -0,0 +1,181 @@
#pragma once
/**
* @file animation.h
* @brief LL GLTF Animation Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "accessor.h"
// LL GLTF Implementation
namespace LL
{
namespace GLTF
{
class Asset;
class Animation
{
public:
class Sampler
{
public:
std::vector<F32> mFrameTimes;
F32 mMinTime = -FLT_MAX;
F32 mMaxTime = FLT_MAX;
S32 mInput = INVALID_INDEX;
S32 mOutput = INVALID_INDEX;
std::string mInterpolation;
void allocateGLResources(Asset& asset);
const Sampler& operator=(const tinygltf::AnimationSampler& src)
{
mInput = src.input;
mOutput = src.output;
mInterpolation = src.interpolation;
return *this;
}
// get the frame index and time for the specified time
// asset -- the asset to reference for Accessors
// time -- the animation time to get the frame info for
// frameIndex -- index of the closest frame that precedes the specified time
// t - interpolant value between the frameIndex and the next frame
void getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t);
};
class Channel
{
public:
class Target
{
public:
S32 mNode = INVALID_INDEX;
std::string mPath;
};
S32 mSampler = INVALID_INDEX;
Target mTarget;
std::string mTargetPath;
std::string mName;
const Channel& operator=(const tinygltf::AnimationChannel& src)
{
mSampler = src.sampler;
mTarget.mNode = src.target_node;
mTarget.mPath = src.target_path;
return *this;
}
};
class RotationChannel : public Channel
{
public:
std::vector<glh::quaternionf> mRotations;
const RotationChannel& operator=(const tinygltf::AnimationChannel& src)
{
Channel::operator=(src);
return *this;
}
// prepare data needed for rendering
// asset -- asset to reference for Accessors
// sampler -- Sampler associated with this channel
void allocateGLResources(Asset& asset, Sampler& sampler);
void apply(Asset& asset, Sampler& sampler, F32 time);
};
class TranslationChannel : public Channel
{
public:
std::vector<glh::vec3f> mTranslations;
const TranslationChannel& operator=(const tinygltf::AnimationChannel& src)
{
Channel::operator=(src);
return *this;
}
// prepare data needed for rendering
// asset -- asset to reference for Accessors
// sampler -- Sampler associated with this channel
void allocateGLResources(Asset& asset, Sampler& sampler);
void apply(Asset& asset, Sampler& sampler, F32 time);
};
class ScaleChannel : public Channel
{
public:
std::vector<glh::vec3f> mScales;
const ScaleChannel& operator=(const tinygltf::AnimationChannel& src)
{
Channel::operator=(src);
return *this;
}
// prepare data needed for rendering
// asset -- asset to reference for Accessors
// sampler -- Sampler associated with this channel
void allocateGLResources(Asset& asset, Sampler& sampler);
void apply(Asset& asset, Sampler& sampler, F32 time);
};
std::string mName;
std::vector<Sampler> mSamplers;
// min/max time values for all samplers combined
F32 mMinTime = 0.f;
F32 mMaxTime = 0.f;
// current time of the animation
F32 mTime = 0.f;
std::vector<RotationChannel> mRotationChannels;
std::vector<TranslationChannel> mTranslationChannels;
std::vector<ScaleChannel> mScaleChannels;
const Animation& operator=(const tinygltf::Animation& src);
void allocateGLResources(Asset& asset);
void update(Asset& asset, float dt);
// apply this animation at the specified time
void apply(Asset& asset, F32 time);
};
}
}

View File

@ -28,6 +28,8 @@
#include "asset.h"
#include "llvolumeoctree.h"
#include "../llviewershadermgr.h"
#include "../llviewercontrol.h"
using namespace LL::GLTF;
@ -66,12 +68,16 @@ LLMatrix4a inverse(const LLMatrix4a& mat);
void Node::updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix)
{
makeMatrixValid();
matMul(mMatrix, parentMatrix, mAssetMatrix);
mAssetMatrixInv = inverse(mAssetMatrix);
S32 my_index = this - &asset.mNodes[0];
for (auto& childIndex : mChildren)
{
Node& child = asset.mNodes[childIndex];
child.mParent = my_index;
child.updateTransforms(asset, mAssetMatrix);
}
}
@ -96,7 +102,7 @@ void Asset::updateRenderTransforms(const LLMatrix4a& modelview)
// use mAssetMatrix to update render transforms from node list
for (auto& node : mNodes)
{
if (node.mMesh != INVALID_INDEX)
//if (node.mMesh != INVALID_INDEX)
{
matMul(node.mAssetMatrix, modelview, node.mRenderMatrix);
}
@ -209,3 +215,450 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
}
void Node::makeMatrixValid()
{
if (!mMatrixValid && mTRSValid)
{
glh::matrix4f rot;
mRotation.get_value(rot);
glh::matrix4f trans;
trans.set_translate(mTranslation);
glh::matrix4f sc;
sc.set_scale(mScale);
glh::matrix4f t;
//t = sc * rot * trans;
//t = trans * rot * sc; // best so far, still wrong on negative scale
//t = sc * trans * rot;
t = trans * sc * rot;
mMatrix.loadu(t.m);
mMatrixValid = true;
}
}
void Node::makeTRSValid()
{
if (!mTRSValid && mMatrixValid)
{
glh::matrix4f t(mMatrix.getF32ptr());
glh::vec4f p = t.get_column(3);
mTranslation.set_value(p.v[0], p.v[1], p.v[2]);
mScale.set_value(t.get_column(0).length(), t.get_column(1).length(), t.get_column(2).length());
mRotation.set_value(t);
mTRSValid = true;
}
}
void Node::setRotation(const glh::quaternionf& q)
{
makeTRSValid();
mRotation = q;
mMatrixValid = false;
}
void Node::setTranslation(const glh::vec3f& t)
{
makeTRSValid();
mTranslation = t;
mMatrixValid = false;
}
void Node::setScale(const glh::vec3f& s)
{
makeTRSValid();
mScale = s;
mMatrixValid = false;
}
const Node& Node::operator=(const tinygltf::Node& src)
{
F32* dstMatrix = mMatrix.getF32ptr();
if (src.matrix.size() == 16)
{
// Node has a transformation matrix, just copy it
for (U32 i = 0; i < 16; ++i)
{
dstMatrix[i] = (F32)src.matrix[i];
}
mMatrixValid = true;
}
else if (!src.rotation.empty() || !src.translation.empty() || !src.scale.empty())
{
// node has rotation/translation/scale, convert to matrix
if (src.rotation.size() == 4)
{
mRotation = glh::quaternionf((F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2], (F32)src.rotation[3]);
}
if (src.translation.size() == 3)
{
mTranslation = glh::vec3f((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]);
}
glh::vec3f scale;
if (src.scale.size() == 3)
{
mScale = glh::vec3f((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]);
}
else
{
mScale.set_value(1.f, 1.f, 1.f);
}
mTRSValid = true;
}
else
{
// node specifies no transformation, set to identity
mMatrix.setIdentity();
}
mChildren = src.children;
mMesh = src.mesh;
mSkin = src.skin;
mName = src.name;
return *this;
}
void Asset::render(bool opaque, bool rigged)
{
if (rigged)
{
gGL.loadIdentity();
}
for (auto& node : mNodes)
{
if (node.mSkin != INVALID_INDEX)
{
if (rigged)
{
Skin& skin = mSkins[node.mSkin];
skin.uploadMatrixPalette(*this, node);
}
else
{
//skip static nodes if we're rendering rigged
continue;
}
}
else if (rigged)
{
// skip rigged nodes if we're not rendering rigged
continue;
}
if (node.mMesh != INVALID_INDEX)
{
Mesh& mesh = mMeshes[node.mMesh];
for (auto& primitive : mesh.mPrimitives)
{
if (!rigged)
{
gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix);
}
bool cull = true;
if (primitive.mMaterial != INVALID_INDEX)
{
Material& material = mMaterials[primitive.mMaterial];
if ((material.mMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) == opaque)
{
continue;
}
material.mMaterial->bind();
cull = !material.mMaterial->mDoubleSided;
}
else
{
if (!opaque)
{
continue;
}
LLFetchedGLTFMaterial::sDefault.bind();
}
LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0);
primitive.mVertexBuffer->setBuffer();
if (primitive.mVertexBuffer->getNumIndices() > 0)
{
primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0);
}
else
{
primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts());
}
}
}
}
}
void Asset::renderOpaque()
{
render(true);
}
void Asset::renderTransparent()
{
render(false);
}
void Asset::update()
{
F32 dt = gFrameTimeSeconds - mLastUpdateTime;
if (dt > 0.f)
{
mLastUpdateTime = gFrameTimeSeconds;
if (mAnimations.size() > 0)
{
static LLCachedControl<U32> anim_idx(gSavedSettings, "GLTFAnimationIndex", 0);
static LLCachedControl<F32> anim_speed(gSavedSettings, "GLTFAnimationSpeed", 1.f);
U32 idx = llclamp(anim_idx(), 0U, mAnimations.size() - 1);
mAnimations[idx].update(*this, dt*anim_speed);
}
updateTransforms();
}
}
void Asset::allocateGLResources(const std::string& filename, const tinygltf::Model& model)
{
// do images first as materials may depend on images
for (auto& image : mImages)
{
image.allocateGLResources();
}
// do materials before meshes as meshes may depend on materials
for (U32 i = 0; i < mMaterials.size(); ++i)
{
mMaterials[i].allocateGLResources(*this);
LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true);
}
for (auto& mesh : mMeshes)
{
mesh.allocateGLResources(*this);
}
for (auto& animation : mAnimations)
{
animation.allocateGLResources(*this);
}
for (auto& skin : mSkins)
{
skin.allocateGLResources(*this);
}
}
const Asset& Asset::operator=(const tinygltf::Model& src)
{
mScenes.resize(src.scenes.size());
for (U32 i = 0; i < src.scenes.size(); ++i)
{
mScenes[i] = src.scenes[i];
}
mNodes.resize(src.nodes.size());
for (U32 i = 0; i < src.nodes.size(); ++i)
{
mNodes[i] = src.nodes[i];
}
mMeshes.resize(src.meshes.size());
for (U32 i = 0; i < src.meshes.size(); ++i)
{
mMeshes[i] = src.meshes[i];
}
mMaterials.resize(src.materials.size());
for (U32 i = 0; i < src.materials.size(); ++i)
{
mMaterials[i] = src.materials[i];
}
mBuffers.resize(src.buffers.size());
for (U32 i = 0; i < src.buffers.size(); ++i)
{
mBuffers[i] = src.buffers[i];
}
mBufferViews.resize(src.bufferViews.size());
for (U32 i = 0; i < src.bufferViews.size(); ++i)
{
mBufferViews[i] = src.bufferViews[i];
}
mTextures.resize(src.textures.size());
for (U32 i = 0; i < src.textures.size(); ++i)
{
mTextures[i] = src.textures[i];
}
mSamplers.resize(src.samplers.size());
for (U32 i = 0; i < src.samplers.size(); ++i)
{
mSamplers[i] = src.samplers[i];
}
mImages.resize(src.images.size());
for (U32 i = 0; i < src.images.size(); ++i)
{
mImages[i] = src.images[i];
}
mAccessors.resize(src.accessors.size());
for (U32 i = 0; i < src.accessors.size(); ++i)
{
mAccessors[i] = src.accessors[i];
}
mAnimations.resize(src.animations.size());
for (U32 i = 0; i < src.animations.size(); ++i)
{
mAnimations[i] = src.animations[i];
}
mSkins.resize(src.skins.size());
for (U32 i = 0; i < src.skins.size(); ++i)
{
mSkins[i] = src.skins[i];
}
return *this;
}
const Material& Material::operator=(const tinygltf::Material& src)
{
mName = src.name;
return *this;
}
void Material::allocateGLResources(Asset& asset)
{
// allocate material
mMaterial = new LLFetchedGLTFMaterial();
}
const Mesh& Mesh::operator=(const tinygltf::Mesh& src)
{
mPrimitives.resize(src.primitives.size());
for (U32 i = 0; i < src.primitives.size(); ++i)
{
mPrimitives[i] = src.primitives[i];
}
mWeights = src.weights;
mName = src.name;
return *this;
}
void Mesh::allocateGLResources(Asset& asset)
{
for (auto& primitive : mPrimitives)
{
primitive.allocateGLResources(asset);
}
}
const Scene& Scene::operator=(const tinygltf::Scene& src)
{
mNodes = src.nodes;
mName = src.name;
return *this;
}
const Texture& Texture::operator=(const tinygltf::Texture& src)
{
mSampler = src.sampler;
mSource = src.source;
mName = src.name;
return *this;
}
const Sampler& Sampler::operator=(const tinygltf::Sampler& src)
{
mMagFilter = src.magFilter;
mMinFilter = src.minFilter;
mWrapS = src.wrapS;
mWrapT = src.wrapT;
mName = src.name;
return *this;
}
void Skin::uploadMatrixPalette(Asset& asset, Node& node)
{
// prepare matrix palette
// modelview will be applied by the shader, so assume matrix palette is in asset space
std::vector<glh::matrix4f> t_mp;
t_mp.resize(mJoints.size());
for (U32 i = 0; i < mJoints.size(); ++i)
{
Node& joint = asset.mNodes[mJoints[i]];
//t_mp[i].set_value(joint.mRenderMatrix.getF32ptr());
//t_mp[i] = t_mp[i] * mInverseBindMatricesData[i];
//t_mp[i].set_value(joint.mRenderMatrix.getF32ptr());
//t_mp[i] = mInverseBindMatricesData[i] * t_mp[i];
t_mp[i].set_value(joint.mRenderMatrix.getF32ptr());
t_mp[i] = t_mp[i] * mInverseBindMatricesData[i];
}
std::vector<F32> glmp;
glmp.resize(mJoints.size() * 12);
F32* mp = glmp.data();
for (U32 i = 0; i < mJoints.size(); ++i)
{
F32* m = (F32*)t_mp[i].m;
U32 idx = i * 12;
mp[idx + 0] = m[0];
mp[idx + 1] = m[1];
mp[idx + 2] = m[2];
mp[idx + 3] = m[12];
mp[idx + 4] = m[4];
mp[idx + 5] = m[5];
mp[idx + 6] = m[6];
mp[idx + 7] = m[13];
mp[idx + 8] = m[8];
mp[idx + 9] = m[9];
mp[idx + 10] = m[10];
mp[idx + 11] = m[14];
}
LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
mJoints.size(),
FALSE,
(GLfloat*)glmp.data());
}

View File

@ -29,86 +29,19 @@
#include "llvertexbuffer.h"
#include "llvolumeoctree.h"
#include "../lltinygltfhelper.h"
#include "accessor.h"
#include "primitive.h"
#include "animation.h"
extern F32SecondsImplicit gFrameTimeSeconds;
// LL GLTF Implementation
namespace LL
{
namespace GLTF
{
constexpr S32 INVALID_INDEX = -1;
class Asset;
class Buffer
{
public:
std::vector<U8> mData;
std::string mName;
std::string mUri;
const Buffer& operator=(const tinygltf::Buffer& src)
{
mData = src.data;
mName = src.name;
mUri = src.uri;
return *this;
}
};
class BufferView
{
public:
S32 mBuffer = INVALID_INDEX;
S32 mByteLength;
S32 mByteOffset;
S32 mByteStride;
S32 mTarget;
S32 mComponentType;
std::string mName;
const BufferView& operator=(const tinygltf::BufferView& src)
{
mBuffer = src.buffer;
mByteLength = src.byteLength;
mByteOffset = src.byteOffset;
mByteStride = src.byteStride;
mTarget = src.target;
mName = src.name;
return *this;
}
};
class Accessor
{
public:
S32 mBufferView = INVALID_INDEX;
S32 mByteOffset;
S32 mComponentType;
S32 mCount;
std::vector<double> mMax;
std::vector<double> mMin;
S32 mType;
bool mNormalized;
std::string mName;
const Accessor& operator=(const tinygltf::Accessor& src)
{
mBufferView = src.bufferView;
mByteOffset = src.byteOffset;
mComponentType = src.componentType;
mCount = src.count;
mType = src.type;
mNormalized = src.normalized;
mName = src.name;
mMax = src.maxValues;
mMin = src.maxValues;
return *this;
}
};
class Material
{
public:
@ -118,17 +51,9 @@ namespace LL
LLPointer<LLFetchedGLTFMaterial> mMaterial;
std::string mName;
const Material& operator=(const tinygltf::Material& src)
{
mName = src.name;
return *this;
}
void allocateGLResources(Asset& asset)
{
// allocate material
mMaterial = new LLFetchedGLTFMaterial();
}
const Material& operator=(const tinygltf::Material& src);
void allocateGLResources(Asset& asset);
};
class Mesh
@ -138,28 +63,9 @@ namespace LL
std::vector<double> mWeights;
std::string mName;
const Mesh& operator=(const tinygltf::Mesh& src)
{
mPrimitives.resize(src.primitives.size());
for (U32 i = 0; i < src.primitives.size(); ++i)
{
mPrimitives[i] = src.primitives[i];
}
mWeights = src.weights;
mName = src.name;
return *this;
}
void allocateGLResources(Asset& asset)
{
for (auto& primitive : mPrimitives)
{
primitive.allocateGLResources(asset);
}
}
const Mesh& operator=(const tinygltf::Mesh& src);
void allocateGLResources(Asset& asset);
};
class Node
@ -170,32 +76,27 @@ namespace LL
LLMatrix4a mAssetMatrix; //transform from local to asset space
LLMatrix4a mAssetMatrixInv; //transform from asset to local space
glh::vec3f mTranslation;
glh::quaternionf mRotation;
glh::vec3f mScale;
// if true, mMatrix is valid and up to date
bool mMatrixValid = false;
// if true, translation/rotation/scale are valid and up to date
bool mTRSValid = false;
bool mNeedsApplyMatrix = false;
std::vector<S32> mChildren;
S32 mParent = INVALID_INDEX;
S32 mMesh = INVALID_INDEX;
S32 mSkin = INVALID_INDEX;
std::string mName;
const Node& operator=(const tinygltf::Node& src)
{
F32* dstMatrix = mMatrix.getF32ptr();
if (src.matrix.size() != 16)
{
mMatrix.setIdentity();
}
else
{
for (U32 i = 0; i < 16; ++i)
{
dstMatrix[i] = (F32)src.matrix[i];
}
}
mChildren = src.children;
mMesh = src.mesh;
mName = src.name;
return *this;
}
const Node& operator=(const tinygltf::Node& src);
// Set mRenderMatrix to a transform that can be used for the current render pass
// modelview -- parent's render matrix
@ -203,7 +104,39 @@ namespace LL
// update mAssetMatrix and mAssetMatrixInv
void updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix);
// ensure mMatrix is valid -- if mMatrixValid is false and mTRSValid is true, will update mMatrix to match Translation/Rotation/Scale
void makeMatrixValid();
// ensure Translation/Rotation/Scale are valid -- if mTRSValid is false and mMatrixValid is true, will update Translation/Rotation/Scale to match mMatrix
void makeTRSValid();
// Set rotation of this node
// SIDE EFFECT: invalidates mMatrix
void setRotation(const glh::quaternionf& rotation);
// Set translation of this node
// SIDE EFFECT: invalidates mMatrix
void setTranslation(const glh::vec3f& translation);
// Set scale of this node
// SIDE EFFECT: invalidates mMatrix
void setScale(const glh::vec3f& scale);
};
class Skin
{
public:
S32 mInverseBindMatrices = INVALID_INDEX;
S32 mSkeleton = INVALID_INDEX;
std::vector<S32> mJoints;
std::string mName;
std::vector<glh::matrix4f> mInverseBindMatricesData;
void allocateGLResources(Asset& asset);
void uploadMatrixPalette(Asset& asset, Node& node);
const Skin& operator=(const tinygltf::Skin& src);
};
class Scene
@ -212,17 +145,10 @@ namespace LL
std::vector<S32> mNodes;
std::string mName;
const Scene& operator=(const tinygltf::Scene& src)
{
mNodes = src.nodes;
mName = src.name;
return *this;
}
const Scene& operator=(const tinygltf::Scene& src);
void updateTransforms(Asset& asset);
void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview);
};
class Texture
@ -232,14 +158,7 @@ namespace LL
S32 mSource = INVALID_INDEX;
std::string mName;
const Texture& operator=(const tinygltf::Texture& src)
{
mSampler = src.sampler;
mSource = src.source;
mName = src.name;
return *this;
}
const Texture& operator=(const tinygltf::Texture& src);
};
class Sampler
@ -251,16 +170,7 @@ namespace LL
S32 mWrapT;
std::string mName;
const Sampler& operator=(const tinygltf::Sampler& src)
{
mMagFilter = src.magFilter;
mMinFilter = src.minFilter;
mWrapS = src.wrapS;
mWrapT = src.wrapT;
mName = src.name;
return *this;
}
const Sampler& operator=(const tinygltf::Sampler& src);
};
class Image
@ -311,25 +221,21 @@ namespace LL
std::vector<Sampler> mSamplers;
std::vector<Image> mImages;
std::vector<Accessor> mAccessors;
std::vector<Animation> mAnimations;
std::vector<Skin> mSkins;
void allocateGLResources(const std::string& filename, const tinygltf::Model& model)
{
for (auto& mesh : mMeshes)
{
mesh.allocateGLResources(*this);
}
// the last time update() was called according to gFrameTimeSeconds
F32 mLastUpdateTime = gFrameTimeSeconds;
for (auto& image : mImages)
{
image.allocateGLResources();
}
for (U32 i = 0; i < mMaterials.size(); ++i)
{
mMaterials[i].allocateGLResources(*this);
LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true);
}
}
// prepare the asset for rendering
void allocateGLResources(const std::string& filename, const tinygltf::Model& model);
// Called periodically (typically once per frame)
// Any ongoing work (such as animations) should be handled here
// NOT guaranteed to be called every frame
// MAY be called more than once per frame
// Upon return, all Node Matrix transforms should be up to date
void update();
// update asset-to-node and node-to-asset transforms
void updateTransforms();
@ -337,34 +243,9 @@ namespace LL
// update node render transforms
void updateRenderTransforms(const LLMatrix4a& modelview);
void renderOpaque()
{
for (auto& node : mNodes)
{
if (node.mMesh != INVALID_INDEX)
{
Mesh& mesh = mMeshes[node.mMesh];
for (auto& primitive : mesh.mPrimitives)
{
gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix);
if (primitive.mMaterial != INVALID_INDEX)
{
Material& material = mMaterials[primitive.mMaterial];
material.mMaterial->bind();
}
primitive.mVertexBuffer->setBuffer();
if (primitive.mVertexBuffer->getNumIndices() > 0)
{
primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0);
}
else
{
primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts());
}
}
}
}
}
void render(bool opaque, bool rigged = false);
void renderOpaque();
void renderTransparent();
// return the index of the node that the line segment intersects with, or -1 if no hit
// input and output values must be in this asset's local coordinate frame
@ -376,70 +257,8 @@ namespace LL
S32* primitive_hitp = nullptr // return the index of the primitive that was hit
);
const Asset& operator=(const tinygltf::Model& src)
{
mScenes.resize(src.scenes.size());
for (U32 i = 0; i < src.scenes.size(); ++i)
{
mScenes[i] = src.scenes[i];
}
mNodes.resize(src.nodes.size());
for (U32 i = 0; i < src.nodes.size(); ++i)
{
mNodes[i] = src.nodes[i];
}
mMeshes.resize(src.meshes.size());
for (U32 i = 0; i < src.meshes.size(); ++i)
{
mMeshes[i] = src.meshes[i];
}
mMaterials.resize(src.materials.size());
for (U32 i = 0; i < src.materials.size(); ++i)
{
mMaterials[i] = src.materials[i];
}
mBuffers.resize(src.buffers.size());
for (U32 i = 0; i < src.buffers.size(); ++i)
{
mBuffers[i] = src.buffers[i];
}
mBufferViews.resize(src.bufferViews.size());
for (U32 i = 0; i < src.bufferViews.size(); ++i)
{
mBufferViews[i] = src.bufferViews[i];
}
mTextures.resize(src.textures.size());
for (U32 i = 0; i < src.textures.size(); ++i)
{
mTextures[i] = src.textures[i];
}
mSamplers.resize(src.samplers.size());
for (U32 i = 0; i < src.samplers.size(); ++i)
{
mSamplers[i] = src.samplers[i];
}
mImages.resize(src.images.size());
for (U32 i = 0; i < src.images.size(); ++i)
{
mImages[i] = src.images[i];
}
mAccessors.resize(src.accessors.size());
for (U32 i = 0; i < src.accessors.size(); ++i)
{
mAccessors[i] = src.accessors[i];
}
return *this;
}
const Asset& operator=(const tinygltf::Model& src);
};
}
}

View File

@ -0,0 +1,402 @@
#pragma once
/**
* @file buffer_util.inl
* @brief LL GLTF Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
// inline template implementations for copying data out of GLTF buffers
// DO NOT include from header files to avoid the need to rebuild the whole project
// whenever we add support for more types
#ifdef _MSC_VER
#define LL_FUNCSIG __FUNCSIG__
#else
#define LL_FUNCSIG __PRETTY_FUNCTION__
#endif
namespace LL
{
namespace GLTF
{
// copy one Scalar from src to dst
template<class S, class T>
static void copyScalar(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec2 from src to dst
template<class S, class T>
static void copyVec2(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec3 from src to dst
template<class S, class T>
static void copyVec3(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec4 from src to dst
template<class S, class T>
static void copyVec4(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec2 from src to dst
template<class S, class T>
static void copyMat2(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec3 from src to dst
template<class S, class T>
static void copyMat3(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec4 from src to dst
template<class S, class T>
static void copyMat4(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
//=========================================================================================================
// concrete implementations for different types of source and destination
//=========================================================================================================
// suppress unused function warning -- clang complains here but these specializations are definitely used
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#endif
template<>
void copyScalar<F32, F32>(F32* src, F32& dst)
{
dst = *src;
}
template<>
void copyScalar<U32, U32>(U32* src, U32& dst)
{
dst = *src;
}
template<>
void copyScalar<U32, U16>(U32* src, U16& dst)
{
dst = *src;
}
template<>
void copyScalar<U16, U16>(U16* src, U16& dst)
{
dst = *src;
}
template<>
void copyScalar<U16, U32>(U16* src, U32& dst)
{
dst = *src;
}
template<>
void copyScalar<U8, U16>(U8* src, U16& dst)
{
dst = *src;
}
template<>
void copyScalar<U8, U32>(U8* src, U32& dst)
{
dst = *src;
}
template<>
void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst)
{
dst.set(src[0], src[1]);
}
template<>
void copyVec3<F32, glh::vec3f>(F32* src, glh::vec3f& dst)
{
dst.set_value(src[0], src[1], src[2]);
}
template<>
void copyVec3<F32, LLVector4a>(F32* src, LLVector4a& dst)
{
dst.load3(src);
}
template<>
void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst)
{
dst.set(src[0], src[1], src[2], 255);
}
template<>
void copyVec4<U8, LLColor4U>(U8* src, LLColor4U& dst)
{
dst.set(src[0], src[1], src[2], src[3]);
}
template<>
void copyVec4<U16, LLColor4U>(U16* src, LLColor4U& dst)
{
dst.set(src[0], src[1], src[2], src[3]);
}
template<>
void copyVec4<F32, LLColor4U>(F32* src, LLColor4U& dst)
{
dst.set(src[0]*255, src[1]*255, src[2]*255, src[3]*255);
}
template<>
void copyVec4<F32, LLVector4a>(F32* src, LLVector4a& dst)
{
dst.loadua(src);
}
template<>
void copyVec4<U16, LLVector4a>(U16* src, LLVector4a& dst)
{
dst.set(src[0], src[1], src[2], src[3]);
}
template<>
void copyVec4<U8, LLVector4a>(U8* src, LLVector4a& dst)
{
dst.set(src[0], src[1], src[2], src[3]);
}
template<>
void copyVec4<F32, glh::quaternionf>(F32* src, glh::quaternionf& dst)
{
dst.set_value(src);
}
template<>
void copyMat4<F32, glh::matrix4f>(F32* src, glh::matrix4f& dst)
{
dst.set_value(src);
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
//=========================================================================================================
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
static void copyScalar(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyScalar(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
static void copyVec2(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyVec2(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
static void copyVec3(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyVec3(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
static void copyVec4(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyVec4(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
static void copyMat2(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyMat2(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
static void copyMat3(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyMat3(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
static void copyMat4(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyMat4(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
template<class S, class T>
static void copy(Asset& asset, Accessor& accessor, const S* src, LLStrider<T>& dst, S32 byteStride)
{
if (accessor.mType == (S32)Accessor::Type::SCALAR)
{
S32 stride = byteStride == 0 ? sizeof(S) * 1 : byteStride;
copyScalar((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == (S32)Accessor::Type::VEC2)
{
S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride;
copyVec2((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == (S32)Accessor::Type::VEC3)
{
S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride;
copyVec3((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == (S32)Accessor::Type::VEC4)
{
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
copyVec4((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == (S32)Accessor::Type::MAT2)
{
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
copyMat2((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == (S32)Accessor::Type::MAT3)
{
S32 stride = byteStride == 0 ? sizeof(S) * 9 : byteStride;
copyMat3((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == (S32)Accessor::Type::MAT4)
{
S32 stride = byteStride == 0 ? sizeof(S) * 16 : byteStride;
copyMat4((S*)src, dst, stride, accessor.mCount);
}
else
{
LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL;
}
}
// copy data from accessor to strider
template<class T>
static void copy(Asset& asset, Accessor& accessor, LLStrider<T>& dst)
{
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT)
{
LL::GLTF::copy(asset, accessor, (const F32*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
{
LL::GLTF::copy(asset, accessor, (const U16*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
{
LL::GLTF::copy(asset, accessor, (const U32*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)
{
LL::GLTF::copy(asset, accessor, (const U8*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT)
{
LL::GLTF::copy(asset, accessor, (const S16*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE)
{
LL::GLTF::copy(asset, accessor, (const S8*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_DOUBLE)
{
LL::GLTF::copy(asset, accessor, (const F64*)src, dst, bufferView.mByteStride);
}
else
{
LL_ERRS("GLTF") << "Unsupported component type" << LL_ENDL;
}
}
// copy data from accessor to vector
template<class T>
static void copy(Asset& asset, Accessor& accessor, std::vector<T>& dst)
{
dst.resize(accessor.mCount);
LLStrider<T> strider = dst.data();
copy(asset, accessor, strider);
}
}
}

View File

@ -27,148 +27,12 @@
#include "../llviewerprecompiledheaders.h"
#include "asset.h"
#include "buffer_util.h"
#include "../lltinygltfhelper.h"
using namespace LL::GLTF;
#ifdef _MSC_VER
#define LL_FUNCSIG __FUNCSIG__
#else
#define LL_FUNCSIG __PRETTY_FUNCTION__
#endif
// copy one vec3 from src to dst
template<class S, class T>
void copyVec2(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec3 from src to dst
template<class S, class T>
void copyVec3(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
// copy one vec4 from src to dst
template<class S, class T>
void copyVec4(S* src, T& dst)
{
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
}
template<>
void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst)
{
dst.set(src[0], src[1]);
}
template<>
void copyVec3<F32, LLVector4a>(F32* src, LLVector4a& dst)
{
dst.load3(src);
}
template<>
void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst)
{
dst.set(src[0], src[1], src[2], 255);
}
template<>
void copyVec4<F32, LLVector4a>(F32* src, LLVector4a& dst)
{
dst.loadua(src);
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
void copyVec2(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyVec2(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
void copyVec3(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyVec3(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
template<class S, class T>
void copyVec4(S* src, LLStrider<T> dst, S32 stride, S32 count)
{
for (S32 i = 0; i < count; ++i)
{
copyVec3(src, *dst);
dst++;
src = (S*)((U8*)src + stride);
}
}
template<class S, class T>
void copyAttributeArray(Asset& asset, const Accessor& accessor, const S* src, LLStrider<T>& dst, S32 byteStride)
{
if (accessor.mType == TINYGLTF_TYPE_VEC2)
{
S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride;
copyVec2((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == TINYGLTF_TYPE_VEC3)
{
S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride;
copyVec3((S*)src, dst, stride, accessor.mCount);
}
else if (accessor.mType == TINYGLTF_TYPE_VEC4)
{
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
copyVec4((S*)src, dst, stride, accessor.mCount);
}
else
{
LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL;
}
}
template <class T>
void Primitive::copyAttribute(Asset& asset, S32 accessorIdx, LLStrider<T>& dst)
{
const Accessor& accessor = asset.mAccessors[accessorIdx];
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT)
{
copyAttributeArray(asset, accessor, (const F32*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
{
copyAttributeArray(asset, accessor, (const U16*)src, dst, bufferView.mByteStride);
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
{
copyAttributeArray(asset, accessor, (const U32*)src, dst, bufferView.mByteStride);
}
else
{
LL_ERRS() << "Unsupported component type" << LL_ENDL;
}
}
void Primitive::allocateGLResources(Asset& asset)
{
// allocate vertex buffer
@ -177,195 +41,174 @@ void Primitive::allocateGLResources(Asset& asset)
// For our engine, though, it's better to rearrange the buffers at load time into a layout that's more consistent.
// The GLTF native approach undoubtedly works well if you can count on VAOs, but VAOs perform much worse with our scenes.
// get the number of vertices
U32 numVertices = 0;
for (auto& it : mAttributes)
{
const Accessor& accessor = asset.mAccessors[it.second];
numVertices = accessor.mCount;
break;
}
// get the number of indices
U32 numIndices = 0;
if (mIndices != INVALID_INDEX)
{
const Accessor& accessor = asset.mAccessors[mIndices];
numIndices = accessor.mCount;
}
// create vertex buffer
mVertexBuffer = new LLVertexBuffer(ATTRIBUTE_MASK);
mVertexBuffer->allocateBuffer(numVertices, numIndices);
bool needs_color = true;
bool needs_texcoord = true;
bool needs_normal = true;
bool needs_tangent = true;
// load vertex data
for (auto& it : mAttributes)
{
const std::string& attribName = it.first;
Accessor& accessor = asset.mAccessors[it.second];
// load vertex data
if (attribName == "POSITION")
{
// load position data
LLStrider<LLVector4a> dst;
mVertexBuffer->getVertexStrider(dst);
copyAttribute(asset, it.second, dst);
copy(asset, accessor, mPositions);
}
else if (attribName == "NORMAL")
{
needs_normal = false;
// load normal data
LLStrider<LLVector4a> dst;
mVertexBuffer->getNormalStrider(dst);
copyAttribute(asset, it.second, dst);
copy(asset, accessor, mNormals);
}
else if (attribName == "TANGENT")
{
needs_tangent = false;
// load tangent data
LLStrider<LLVector4a> dst;
mVertexBuffer->getTangentStrider(dst);
copyAttribute(asset, it.second, dst);
copy(asset, accessor, mTangents);
}
else if (attribName == "COLOR_0")
{
needs_color = false;
// load color data
LLStrider<LLColor4U> dst;
mVertexBuffer->getColorStrider(dst);
copyAttribute(asset, it.second, dst);
copy(asset, accessor, mColors);
}
else if (attribName == "TEXCOORD_0")
{
needs_texcoord = false;
// load texcoord data
LLStrider<LLVector2> dst;
mVertexBuffer->getTexCoord0Strider(dst);
LLStrider<LLVector2> tc = dst;
copyAttribute(asset, it.second, dst);
// convert to OpenGL coordinate space
for (U32 i = 0; i < numVertices; ++i)
{
tc->mV[1] = 1.0f - tc->mV[1];;
tc++;
}
copy(asset, accessor, mTexCoords);
}
else if (attribName == "JOINTS_0")
{
copy(asset, accessor, mJoints);
}
else if (attribName == "WEIGHTS_0")
{
copy(asset, accessor, mWeights);
}
}
// copy index buffer
if (mIndices != INVALID_INDEX)
{
const Accessor& accessor = asset.mAccessors[mIndices];
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
LLStrider<U16> dst;
mVertexBuffer->getIndexStrider(dst);
mIndexArray.resize(numIndices);
if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
{
for (U32 i = 0; i < numIndices; ++i)
{
*(dst++) = (U16) * (U32*)src;
src += sizeof(U32);
}
}
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
{
for (U32 i = 0; i < numIndices; ++i)
{
*(dst++) = *(U16*)src;
src += sizeof(U16);
}
}
else
{
LL_ERRS("GLTF") << "Unsupported component type for indices" << LL_ENDL;
}
U16* idx = (U16*)mVertexBuffer->getMappedIndices();
for (U32 i = 0; i < numIndices; ++i)
{
mIndexArray[i] = idx[i];
}
Accessor& accessor = asset.mAccessors[mIndices];
copy(asset, accessor, mIndexArray);
}
// fill in default values for missing attributes
if (needs_color)
{ // set default color
LLStrider<LLColor4U> dst;
mVertexBuffer->getColorStrider(dst);
for (U32 i = 0; i < numVertices; ++i)
{
*(dst++) = LLColor4U(255, 255, 255, 255);
}
}
if (needs_texcoord)
{ // set default texcoord
LLStrider<LLVector2> dst;
mVertexBuffer->getTexCoord0Strider(dst);
for (U32 i = 0; i < numVertices; ++i)
{
*(dst++) = LLVector2(0.0f, 0.0f);
}
}
if (needs_normal)
{ // set default normal
LLStrider<LLVector4a> dst;
mVertexBuffer->getNormalStrider(dst);
for (U32 i = 0; i < numVertices; ++i)
{
*(dst++) = LLVector4a(0.0f, 0.0f, 1.0f, 0.0f);
}
}
if (needs_tangent)
{ // TODO: generate tangents if needed
LLStrider<LLVector4a> dst;
mVertexBuffer->getTangentStrider(dst);
for (U32 i = 0; i < numVertices; ++i)
{
*(dst++) = LLVector4a(1.0f, 0.0f, 0.0f, 1.0f);
}
}
mPositions.resize(numVertices);
mTexCoords.resize(numVertices);
mNormals.resize(numVertices);
mTangents.resize(numVertices);
LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX));
LLVector2* tc = (LLVector2*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TEXCOORD0));
LLVector4a* norm = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_NORMAL));
LLVector4a* tangent = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TANGENT));
for (U32 i = 0; i < numVertices; ++i)
U32 mask = ATTRIBUTE_MASK;
if (!mWeights.empty())
{
mPositions[i] = pos[i];
mTexCoords[i] = tc[i];
mNormals[i] = norm[i];
mTangents[i] = tangent[i];
mask |= LLVertexBuffer::MAP_WEIGHT4;
}
mVertexBuffer = new LLVertexBuffer(mask);
mVertexBuffer->allocateBuffer(mPositions.size(), mIndexArray.size()*2); // double the size of the index buffer for 32-bit indices
mVertexBuffer->setBuffer();
mVertexBuffer->setPositionData(mPositions.data());
if (!mIndexArray.empty())
{
mVertexBuffer->setIndexData(mIndexArray.data());
}
if (mTexCoords.empty())
{
mTexCoords.resize(mPositions.size());
}
// flip texcoord y, upload, then flip back (keep the off-spec data in vram only)
for (auto& tc : mTexCoords)
{
tc[1] = 1.f - tc[1];
}
mVertexBuffer->setTexCoordData(mTexCoords.data());
for (auto& tc : mTexCoords)
{
tc[1] = 1.f - tc[1];
}
if (mColors.empty())
{
mColors.resize(mPositions.size(), LLColor4U::white);
}
// bake material basecolor into color array
if (mMaterial != INVALID_INDEX)
{
const Material& material = asset.mMaterials[mMaterial];
LLColor4 baseColor = material.mMaterial->mBaseColor;
for (auto& dst : mColors)
{
dst = LLColor4U(baseColor * LLColor4(dst));
}
}
mVertexBuffer->setColorData(mColors.data());
if (mNormals.empty())
{
mNormals.resize(mPositions.size(), LLVector4a(0, 0, 1, 0));
}
mVertexBuffer->setNormalData(mNormals.data());
if (mTangents.empty())
{
// TODO: generate tangents if needed
mTangents.resize(mPositions.size(), LLVector4a(1, 0, 0, 1));
}
mVertexBuffer->setTangentData(mTangents.data());
if (!mWeights.empty())
{
std::vector<LLVector4a> weight_data;
weight_data.resize(mWeights.size());
F32 max_weight = 1.f - FLT_EPSILON*100.f;
LLVector4a maxw(max_weight, max_weight, max_weight, max_weight);
for (U32 i = 0; i < mWeights.size(); ++i)
{
LLVector4a& w = weight_data[i];
w.setMin(mWeights[i], maxw);
w.add(mJoints[i]);
};
mVertexBuffer->setWeight4Data(weight_data.data());
}
createOctree();
mVertexBuffer->unmapBuffer();
mVertexBuffer->unbind();
}
void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2)
{
//store pointers to vertex data
tri->mV[0] = &v0;
tri->mV[1] = &v1;
tri->mV[2] = &v2;
//store indices
tri->mIndex[0] = i0;
tri->mIndex[1] = i1;
tri->mIndex[2] = i2;
//get minimum point
LLVector4a min = v0;
min.setMin(min, v1);
min.setMin(min, v2);
//get maximum point
LLVector4a max = v0;
max.setMax(max, v1);
max.setMax(max, v2);
//compute center
LLVector4a center;
center.setAdd(min, max);
center.mul(0.5f);
tri->mPositionGroup = center;
//compute "radius"
LLVector4a size;
size.setSub(max, min);
tri->mRadius = size.getLength3().getF32() * scaler;
}
void Primitive::createOctree()
@ -373,62 +216,88 @@ void Primitive::createOctree()
// create octree
mOctree = new LLVolumeOctree();
F32 scaler = 0.25f;
if (mMode == TINYGLTF_MODE_TRIANGLES)
{
F32 scaler = 0.25f;
const U32 num_triangles = mVertexBuffer->getNumIndices() / 3;
// Initialize all the triangles we need
mOctreeTriangles.resize(num_triangles);
LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX));
U16* indices = (U16*)mVertexBuffer->getMappedIndices();
for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)
{ //for each triangle
const U32 index = triangle_index * 3;
LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index];
const LLVector4a& v0 = pos[indices[index]];
const LLVector4a& v1 = pos[indices[index + 1]];
const LLVector4a& v2 = pos[indices[index + 2]];
S32 i0 = mIndexArray[index];
S32 i1 = mIndexArray[index + 1];
S32 i2 = mIndexArray[index + 2];
//store pointers to vertex data
tri->mV[0] = &v0;
tri->mV[1] = &v1;
tri->mV[2] = &v2;
const LLVector4a& v0 = mPositions[i0];
const LLVector4a& v1 = mPositions[i1];
const LLVector4a& v2 = mPositions[i2];
initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2);
//insert
mOctree->insert(tri);
}
}
else if (mMode == TINYGLTF_MODE_TRIANGLE_STRIP)
{
const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
// Initialize all the triangles we need
mOctreeTriangles.resize(num_triangles);
//store indices
tri->mIndex[0] = indices[index];
tri->mIndex[1] = indices[index + 1];
tri->mIndex[2] = indices[index + 2];
for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)
{ //for each triangle
const U32 index = triangle_index + 2;
LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index];
S32 i0 = mIndexArray[index];
S32 i1 = mIndexArray[index - 1];
S32 i2 = mIndexArray[index - 2];
//get minimum point
LLVector4a min = v0;
min.setMin(min, v1);
min.setMin(min, v2);
const LLVector4a& v0 = mPositions[i0];
const LLVector4a& v1 = mPositions[i1];
const LLVector4a& v2 = mPositions[i2];
//get maximum point
LLVector4a max = v0;
max.setMax(max, v1);
max.setMax(max, v2);
//compute center
LLVector4a center;
center.setAdd(min, max);
center.mul(0.5f);
tri->mPositionGroup = center;
//compute "radius"
LLVector4a size;
size.setSub(max, min);
tri->mRadius = size.getLength3().getF32() * scaler;
initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2);
//insert
mOctree->insert(tri);
}
}
else if (mMode == TINYGLTF_MODE_TRIANGLE_FAN)
{
const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
// Initialize all the triangles we need
mOctreeTriangles.resize(num_triangles);
for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)
{ //for each triangle
const U32 index = triangle_index + 2;
LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index];
S32 i0 = mIndexArray[0];
S32 i1 = mIndexArray[index - 1];
S32 i2 = mIndexArray[index - 2];
const LLVector4a& v0 = mPositions[i0];
const LLVector4a& v1 = mPositions[i1];
const LLVector4a& v2 = mPositions[i2];
initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2);
//insert
mOctree->insert(tri);
}
}
else if (mMode == TINYGLTF_MODE_POINTS ||
mMode == TINYGLTF_MODE_LINE ||
mMode == TINYGLTF_MODE_LINE_LOOP ||
mMode == TINYGLTF_MODE_LINE_STRIP)
{
// nothing to do, no volume... maybe add some collision geometry around these primitive types?
}
else
{
LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL;
@ -461,7 +330,7 @@ const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start,
face.mTexCoords = mTexCoords.data();
face.mNormals = mNormals.data();
face.mTangents = mTangents.data();
face.mIndices = mIndexArray.data();
face.mIndices = nullptr; // unreferenced
face.mNumIndices = mIndexArray.size();
face.mNumVertices = mPositions.size();
@ -482,3 +351,50 @@ Primitive::~Primitive()
mOctree = nullptr;
}
const Primitive& Primitive::operator=(const tinygltf::Primitive& src)
{
// load material
mMaterial = src.material;
// load mode
mMode = src.mode;
// load indices
mIndices = src.indices;
// load attributes
for (auto& it : src.attributes)
{
mAttributes[it.first] = it.second;
}
switch (mMode)
{
case TINYGLTF_MODE_POINTS:
mGLMode = LLRender::POINTS;
break;
case TINYGLTF_MODE_LINE:
mGLMode = LLRender::LINES;
break;
case TINYGLTF_MODE_LINE_LOOP:
mGLMode = LLRender::LINE_LOOP;
break;
case TINYGLTF_MODE_LINE_STRIP:
mGLMode = LLRender::LINE_STRIP;
break;
case TINYGLTF_MODE_TRIANGLES:
mGLMode = LLRender::TRIANGLES;
break;
case TINYGLTF_MODE_TRIANGLE_STRIP:
mGLMode = LLRender::TRIANGLE_STRIP;
break;
case TINYGLTF_MODE_TRIANGLE_FAN:
mGLMode = LLRender::TRIANGLE_FAN;
break;
default:
mGLMode = GL_TRIANGLES;
}
return *this;
}

View File

@ -56,7 +56,10 @@ namespace LL
std::vector<LLVector4a> mNormals;
std::vector<LLVector4a> mTangents;
std::vector<LLVector4a> mPositions;
std::vector<U16> mIndexArray;
std::vector<LLVector4a> mJoints;
std::vector<LLVector4a> mWeights;
std::vector<LLColor4U> mColors;
std::vector<U32> mIndexArray;
// raycast acceleration structure
LLPointer<LLVolumeOctree> mOctree;
@ -68,11 +71,6 @@ namespace LL
S32 mIndices = -1;
std::unordered_map<std::string, int> mAttributes;
// copy the attribute in the given BufferView to the given destination
// assumes destination has enough storage for the attribute
template<class T>
void copyAttribute(Asset& asset, S32 bufferViewIdx, LLStrider<T>& dst);
// create octree based on vertex buffer
// must be called before buffer is unmapped and after buffer is populated with good data
void createOctree();
@ -87,52 +85,7 @@ namespace LL
LLVector4a* tangent = NULL // return the surface tangent at the intersection point
);
const Primitive& operator=(const tinygltf::Primitive& src)
{
// load material
mMaterial = src.material;
// load mode
mMode = src.mode;
// load indices
mIndices = src.indices;
// load attributes
for (auto& it : src.attributes)
{
mAttributes[it.first] = it.second;
}
switch (mMode)
{
case TINYGLTF_MODE_POINTS:
mGLMode = LLRender::POINTS;
break;
case TINYGLTF_MODE_LINE:
mGLMode = LLRender::LINES;
break;
case TINYGLTF_MODE_LINE_LOOP:
mGLMode = LLRender::LINE_LOOP;
break;
case TINYGLTF_MODE_LINE_STRIP:
mGLMode = LLRender::LINE_STRIP;
break;
case TINYGLTF_MODE_TRIANGLES:
mGLMode = LLRender::TRIANGLES;
break;
case TINYGLTF_MODE_TRIANGLE_STRIP:
mGLMode = LLRender::TRIANGLE_STRIP;
break;
case TINYGLTF_MODE_TRIANGLE_FAN:
mGLMode = LLRender::TRIANGLE_FAN;
break;
default:
mGLMode = GL_TRIANGLES;
}
return *this;
}
const Primitive& operator=(const tinygltf::Primitive& src);
void allocateGLResources(Asset& asset);
};

View File

@ -82,6 +82,7 @@ void GLTFSceneManager::load(const std::string& filename)
LLPointer<Asset> asset = new Asset();
*asset = model;
gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions
asset->allocateGLResources(filename, model);
asset->updateTransforms();
@ -91,7 +92,11 @@ void GLTFSceneManager::load(const std::string& filename)
if (obj)
{ // assign to self avatar
obj->mGLTFAsset = asset;
mObjects.push_back(obj);
if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end())
{
mObjects.push_back(obj);
}
}
}
@ -100,43 +105,35 @@ GLTFSceneManager::~GLTFSceneManager()
mObjects.clear();
}
LLMatrix4a getAssetToAgentTransform(LLViewerObject* obj)
{
LLMatrix4 root;
root.initScale(obj->getScale());
root.rotate(obj->getRenderRotation());
root.translate(obj->getPositionAgent());
LLMatrix4a mat;
mat.loadu((F32*) root.mMatrix);
return mat;
}
LLMatrix4a getAgentToAssetTransform(LLViewerObject* obj)
{
LLMatrix4 root;
LLVector3 scale = obj->getScale();
scale.mV[0] = 1.f / scale.mV[0];
scale.mV[1] = 1.f / scale.mV[1];
scale.mV[2] = 1.f / scale.mV[2];
root.translate(-obj->getPositionAgent());
root.rotate(~obj->getRenderRotation());
LLMatrix4 scale_mat;
scale_mat.initScale(scale);
root *= scale_mat;
LLMatrix4a mat;
mat.loadu((F32*) root.mMatrix);
return mat;
}
void GLTFSceneManager::renderOpaque()
{
render(true);
}
void GLTFSceneManager::renderAlpha()
{
render(false);
}
void GLTFSceneManager::update()
{
for (U32 i = 0; i < mObjects.size(); ++i)
{
if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr)
{
mObjects.erase(mObjects.begin() + i);
--i;
continue;
}
Asset* asset = mObjects[i]->mGLTFAsset;
asset->update();
}
}
void GLTFSceneManager::render(bool opaque, bool rigged)
{
// for debugging, just render the whole scene as opaque
// by traversing the whole scenegraph
@ -158,7 +155,7 @@ void GLTFSceneManager::renderOpaque()
gGL.pushMatrix();
LLMatrix4a mat = getAssetToAgentTransform(mObjects[i]);
LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform();
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
@ -166,7 +163,7 @@ void GLTFSceneManager::renderOpaque()
matMul(mat, modelview, modelview);
asset->updateRenderTransforms(modelview);
asset->renderOpaque();
asset->render(opaque, rigged);
gGL.popMatrix();
}
@ -195,7 +192,7 @@ bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const
LLVector4a local_start;
LLVector4a local_end;
LLMatrix4a asset_to_agent = getAssetToAgentTransform(obj);
LLMatrix4a asset_to_agent = obj->getGLTFAssetToAgentTransform();
LLMatrix4a agent_to_asset = inverse(asset_to_agent);
agent_to_asset.affineTransform(start, local_start);
@ -331,7 +328,7 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset)
gGL.pushMatrix();
// get raycast in asset space
LLMatrix4a agent_to_asset = getAgentToAssetTransform(obj);
LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform();
LLVector4a start;
LLVector4a end;
@ -399,7 +396,8 @@ void GLTFSceneManager::renderDebug()
{
if (!gPipeline.hasRenderDebugMask(
LLPipeline::RENDER_DEBUG_BBOXES |
LLPipeline::RENDER_DEBUG_RAYCAST))
LLPipeline::RENDER_DEBUG_RAYCAST |
LLPipeline::RENDER_DEBUG_NODES))
{
return;
}
@ -412,6 +410,29 @@ void GLTFSceneManager::renderDebug()
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gPipeline.disableLights();
// force update all mRenderMatrix, not just nodes with meshes
for (auto& obj : mObjects)
{
if (obj->isDead() || obj->mGLTFAsset == nullptr)
{
continue;
}
LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
matMul(mat, modelview, modelview);
Asset* asset = obj->mGLTFAsset;
for (auto& node : asset->mNodes)
{
matMul(node.mAssetMatrix, modelview, node.mRenderMatrix);
}
}
for (auto& obj : mObjects)
{
if (obj->isDead() || obj->mGLTFAsset == nullptr)
@ -421,18 +442,91 @@ void GLTFSceneManager::renderDebug()
Asset* asset = obj->mGLTFAsset;
LLMatrix4a mat = getAssetToAgentTransform(obj);
LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
matMul(mat, modelview, modelview);
asset->updateRenderTransforms(modelview);
renderAssetDebug(obj, asset);
}
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NODES))
{ //render node hierarchy
for (U32 i = 0; i < 2; ++i)
{
LLGLDepthTest depth(GL_TRUE, i == 0 ? GL_FALSE : GL_TRUE, i == 0 ? GL_GREATER : GL_LEQUAL);
LLGLState blend(GL_BLEND, i == 0 ? TRUE : FALSE);
gGL.pushMatrix();
for (auto& obj : mObjects)
{
if (obj->isDead() || obj->mGLTFAsset == nullptr)
{
continue;
}
LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
matMul(mat, modelview, modelview);
Asset* asset = obj->mGLTFAsset;
for (auto& node : asset->mNodes)
{
// force update all mRenderMatrix, not just nodes with meshes
matMul(node.mAssetMatrix, modelview, node.mRenderMatrix);
gGL.loadMatrix(node.mRenderMatrix.getF32ptr());
// render x-axis red, y-axis green, z-axis blue
gGL.color4f(1.f, 0.f, 0.f, 0.5f);
gGL.begin(LLRender::LINES);
gGL.vertex3f(0.f, 0.f, 0.f);
gGL.vertex3f(1.f, 0.f, 0.f);
gGL.end();
gGL.flush();
gGL.color4f(0.f, 1.f, 0.f, 0.5f);
gGL.begin(LLRender::LINES);
gGL.vertex3f(0.f, 0.f, 0.f);
gGL.vertex3f(0.f, 1.f, 0.f);
gGL.end();
gGL.flush();
gGL.begin(LLRender::LINES);
gGL.color4f(0.f, 0.f, 1.f, 0.5f);
gGL.vertex3f(0.f, 0.f, 0.f);
gGL.vertex3f(0.f, 0.f, 1.f);
gGL.end();
gGL.flush();
// render path to child nodes cyan
gGL.color4f(0.f, 1.f, 1.f, 0.5f);
gGL.begin(LLRender::LINES);
for (auto& child_idx : node.mChildren)
{
Node& child = asset->mNodes[child_idx];
gGL.vertex3f(0.f, 0.f, 0.f);
gGL.vertex3fv(child.mMatrix.getTranslation().getF32ptr());
}
gGL.end();
gGL.flush();
}
}
gGL.popMatrix();
}
}
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
{
S32 node_hit = -1;

View File

@ -36,9 +36,14 @@ namespace LL
public:
~GLTFSceneManager();
// load GLTF file from disk
void load(); // open filepicker to choose asset
void load(const std::string& filename); // load asset from filename
void update();
void render(bool opaque, bool rigged = false);
void renderOpaque();
void renderAlpha();
LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
BOOL pick_transparent,

View File

@ -280,19 +280,6 @@ S32 LLAgentBenefits::get2KTextureUploadCost(S32 area) const
{
return m_texture_upload_cost;
}
const S32 TEXTURE_SEGMENTS = 1024;
if (m_2k_texture_upload_cost.size() == TEXTURE_SEGMENTS)
{
S32 index = (S32)llceil(sqrt((F32)area));
// 1..1024 pixels uses m_texture_upload_cost
// 1025..2048 uses m_2k_texture_upload_cost
// Translate 1025..2048 to 0..1023 of the
// cost array
const S32 PIXELS_TO_2K_ARRAY_TRANLATE = 1025;
index -= PIXELS_TO_2K_ARRAY_TRANLATE;
index = llclamp(index, 0, TEXTURE_SEGMENTS - 1);
return m_2k_texture_upload_cost[index];
}
return m_2k_texture_upload_cost[0];
}

View File

@ -2814,7 +2814,7 @@ void LLAgentCamera::setFocusGlobal(const LLPickInfo& pick)
{
LLViewerObject* objectp = gObjectList.findObject(pick.mObjectID);
if (objectp)
if (objectp && pick.mGLTFNodeIndex == -1)
{
// focus on object plus designated offset
// which may or may not be same as pick.mPosGlobal

View File

@ -5722,6 +5722,7 @@ void LLAppViewer::idle()
{
LLPerfStats::tunedAvatars=0; // <FS:Beq> reset the number of avatars that have been tweaked.
gObjectList.update(gAgent);
LL::GLTFSceneManager::instance().update();
}
}

View File

@ -49,6 +49,7 @@
#include "llspatialpartition.h"
#include "llglcommonfunc.h"
#include "llvoavatar.h"
#include "gltfscenemanager.h"
#include "llenvironment.h"
@ -261,6 +262,15 @@ void LLDrawPoolAlpha::forwardRender(bool rigged)
mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
if (rigged)
{ // draw GLTF scene to depth buffer before rigged alpha
gPipeline.bindDeferredShader(gDeferredPBRAlphaProgram);
LL::GLTFSceneManager::instance().render(false, false);
gPipeline.bindDeferredShader(*gDeferredPBRAlphaProgram.mRiggedVariant);
LL::GLTFSceneManager::instance().render(false, true);
}
// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
// We don't want the nearly invisible objects to cause of DoF effects
renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged);

View File

@ -704,8 +704,7 @@ void LLBumpImageList::updateImages()
{
for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); )
{
bump_image_map_t::iterator curiter = iter++;
LLViewerTexture* image = curiter->second;
LLViewerTexture* image = iter->second;
if( image )
{
BOOL destroy = TRUE;
@ -724,9 +723,11 @@ void LLBumpImageList::updateImages()
if( destroy )
{
//LL_INFOS() << "*** Destroying bright " << (void*)image << LL_ENDL;
mBrightnessEntries.erase(curiter); // deletes the image thanks to reference counting
iter = mBrightnessEntries.erase(iter); // deletes the image thanks to reference counting
continue;
}
}
++iter;
}
for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); )

View File

@ -61,6 +61,7 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass)
gDeferredPBROpaqueProgram.bind(true);
LL::GLTFSceneManager::instance().render(true, true);
pushRiggedGLTFBatches(mRenderType + 1);
}

View File

@ -34,6 +34,9 @@
#include "llshadermgr.h"
#include "pipeline.h"
//static
LLFetchedGLTFMaterial LLFetchedGLTFMaterial::sDefault;
LLFetchedGLTFMaterial::LLFetchedGLTFMaterial()
: LLGLTFMaterial()
, mExpectedFlusTime(0.f)

View File

@ -66,6 +66,8 @@ public:
std::set<LLTextureEntry*> mTextureEntires;
// default material for when assets don't have one
static LLFetchedGLTFMaterial sDefault;
protected:
// Lifetime management

View File

@ -357,9 +357,16 @@ LLVector3 LLManip::getSavedPivotPoint() const
LLVector3 LLManip::getPivotPoint()
{
// <FS:KC> Pivot point controls
//if (mObjectSelection->getFirstObject() && mObjectSelection->getObjectCount() == 1 && mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
//LLViewerObject* object = mObjectSelection->getFirstObject();
//if (object && mObjectSelection->getObjectCount() == 1 && mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
//{
// LLSelectNode* select_node = mObjectSelection->getFirstNode();
// if (select_node->mSelectedGLTFNode != -1)
// {
// return object->getGLTFNodePositionAgent(select_node->mSelectedGLTFNode);
// }
// return mObjectSelection->getFirstObject()->getPivotPositionAgent();
//}
//return LLSelectMgr::getInstance()->getBBoxOfSelection().getCenterAgent();
@ -377,7 +384,15 @@ LLVector3 LLManip::getPivotPoint()
LLViewerObject* root_object = mObjectSelection->getFirstRootObject(children_ok);
if (root_object && (mObjectSelection->getObjectCount() == 1 || sActualRoot) && mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
{
pos = root_object->getPivotPositionAgent();
LLSelectNode* select_node = mObjectSelection->getFirstNode();
if (select_node->mSelectedGLTFNode != -1)
{
pos = root_object->getGLTFNodePositionAgent(select_node->mSelectedGLTFNode);
}
else
{
pos = root_object->getPivotPositionAgent();
}
scale = root_object->getScale();
rot = root_object->getRotation();
}

View File

@ -556,6 +556,7 @@ void LLManipRotate::drag( S32 x, S32 y )
BOOL damped = mSmoothRotate;
mSmoothRotate = FALSE;
bool gltf_mode = false;
for (LLObjectSelection::iterator iter = mObjectSelection->begin();
iter != mObjectSelection->end(); iter++)
@ -569,154 +570,177 @@ void LLManipRotate::drag( S32 x, S32 y )
((root_object == NULL) || !root_object->isPermanentEnforced()) &&
(object->isRootEdit() || selectNode->mIndividualSelection))
{
if (!object->isRootEdit())
{
// child objects should not update if parent is selected
LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
if (editable_root->isSelected())
{
// we will be moved properly by our parent, so skip
continue;
}
}
LLQuaternion new_rot = selectNode->mSavedRotation * mRotation;
std::vector<LLVector3>& child_positions = object->mUnselectedChildrenPositions ;
std::vector<LLQuaternion> child_rotations;
if (object->isRootEdit() && selectNode->mIndividualSelection)
{
object->saveUnselectedChildrenRotation(child_rotations) ;
object->saveUnselectedChildrenPosition(child_positions) ;
}
if (selectNode->mSelectedGLTFNode != -1)
{
LLQuaternion new_rot = selectNode->mSavedRotation * mRotation;
if (object->getParent() && object->mDrawable.notNull())
{
LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
invParentRotation.transQuat();
object->setGLTFNodeRotationAgent(selectNode->mSelectedGLTFNode, new_rot);
object->setRotation(new_rot * invParentRotation, damped);
rebuild(object);
}
else
{
object->setRotation(new_rot, damped);
LLVOAvatar* avatar = object->asAvatar();
if (avatar && avatar->isSelf()
&& LLSelectMgr::getInstance()->mAllowSelectAvatar
&& !object->getParent())
gltf_mode = true;
}
else if (!gltf_mode)
{
if (!object->isRootEdit())
{
// Normal avatars use object's orienttion, but self uses
// separate LLCoordFrame
// See LVOAvatar::updateOrientation()
if (gAgentCamera.getFocusOnAvatar())
// child objects should not update if parent is selected
LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
if (editable_root->isSelected())
{
//Don't rotate camera with avatar
gAgentCamera.setFocusOnAvatar(false, false, false);
// we will be moved properly by our parent, so skip
continue;
}
LLVector3 at_axis = mAgentSelfAtAxis;
at_axis *= mRotation;
at_axis.mV[VZ] = 0.f;
at_axis.normalize();
gAgent.resetAxes(at_axis);
}
rebuild(object);
}
// for individually selected roots, we need to counterrotate all the children
if (object->isRootEdit() && selectNode->mIndividualSelection)
{
//RN: must do non-damped updates on these objects so relative rotation appears constant
// instead of having two competing slerps making the child objects appear to "wobble"
object->resetChildrenRotationAndPosition(child_rotations, child_positions) ;
}
LLQuaternion new_rot = selectNode->mSavedRotation * mRotation;
std::vector<LLVector3>& child_positions = object->mUnselectedChildrenPositions;
std::vector<LLQuaternion> child_rotations;
if (object->isRootEdit() && selectNode->mIndividualSelection)
{
object->saveUnselectedChildrenRotation(child_rotations);
object->saveUnselectedChildrenPosition(child_positions);
}
if (object->getParent() && object->mDrawable.notNull())
{
LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
invParentRotation.transQuat();
object->setRotation(new_rot * invParentRotation, damped);
rebuild(object);
}
else
{
object->setRotation(new_rot, damped);
LLVOAvatar* avatar = object->asAvatar();
if (avatar && avatar->isSelf()
&& LLSelectMgr::getInstance()->mAllowSelectAvatar
&& !object->getParent())
{
// Normal avatars use object's orienttion, but self uses
// separate LLCoordFrame
// See LVOAvatar::updateOrientation()
if (gAgentCamera.getFocusOnAvatar())
{
//Don't rotate camera with avatar
gAgentCamera.setFocusOnAvatar(false, false, false);
}
LLVector3 at_axis = mAgentSelfAtAxis;
at_axis *= mRotation;
at_axis.mV[VZ] = 0.f;
at_axis.normalize();
gAgent.resetAxes(at_axis);
}
rebuild(object);
}
// for individually selected roots, we need to counterrotate all the children
if (object->isRootEdit() && selectNode->mIndividualSelection)
{
//RN: must do non-damped updates on these objects so relative rotation appears constant
// instead of having two competing slerps making the child objects appear to "wobble"
object->resetChildrenRotationAndPosition(child_rotations, child_positions);
}
}
}
}
// update positions
for (LLObjectSelection::iterator iter = mObjectSelection->begin();
iter != mObjectSelection->end(); iter++)
{
LLSelectNode* selectNode = *iter;
LLViewerObject* object = selectNode->getObject();
LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
if (!gltf_mode)
{
for (LLObjectSelection::iterator iter = mObjectSelection->begin();
iter != mObjectSelection->end(); iter++)
{
LLSelectNode* selectNode = *iter;
LLViewerObject* object = selectNode->getObject();
LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
// to avoid cumulative position changes we calculate the objects new position using its saved position
if (object && object->permMove() && !object->isPermanentEnforced() &&
((root_object == NULL) || !root_object->isPermanentEnforced()))
{
LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
LLVector3 old_position;
LLVector3 new_position;
// to avoid cumulative position changes we calculate the objects new position using its saved position
if (object && object->permMove() && !object->isPermanentEnforced() &&
((root_object == NULL) || !root_object->isPermanentEnforced()))
{
LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter);
if (object->isAttachment() && object->mDrawable.notNull())
{
// need to work in drawable space to handle selected items from multiple attachments
// (which have no shared frame of reference other than their render positions)
LLXform* parent_xform = object->mDrawable->getXform()->getParent();
new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition();
}
else
{
new_position = gAgent.getPosAgentFromGlobal( selectNode->mSavedPositionGlobal );
old_position = object->getPositionAgent();
}
LLVector3 old_position;
LLVector3 new_position;
new_position = (new_position - center) * mRotation; // new relative rotated position
new_position += center;
if (object->isRootEdit() && !object->isAttachment())
{
LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position);
new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global);
new_position = gAgent.getPosAgentFromGlobal(new_pos_global);
}
if (selectNode->mSelectedGLTFNode != -1)
{
// for individually selected child objects
if (!object->isRootEdit() && selectNode->mIndividualSelection)
{
LLViewerObject* parentp = (LLViewerObject*)object->getParent();
if (!parentp->isSelected())
{
if (object->isAttachment() && object->mDrawable.notNull())
{
// find position relative to render position of parent
object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation());
rebuild(object);
}
else
{
object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion());
rebuild(object);
}
}
}
else if (object->isRootEdit())
{
if (object->isAttachment() && object->mDrawable.notNull())
{
LLXform* parent_xform = object->mDrawable->getXform()->getParent();
object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation());
rebuild(object);
}
else
{
object->setPositionAgent(new_position);
rebuild(object);
}
}
}
else
{
if (object->isAttachment() && object->mDrawable.notNull())
{
// need to work in drawable space to handle selected items from multiple attachments
// (which have no shared frame of reference other than their render positions)
LLXform* parent_xform = object->mDrawable->getXform()->getParent();
new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition();
}
else
{
new_position = gAgent.getPosAgentFromGlobal(selectNode->mSavedPositionGlobal);
old_position = object->getPositionAgent();
}
// for individually selected roots, we need to counter-translate all unselected children
if (object->isRootEdit() && selectNode->mIndividualSelection)
{
// only offset by parent's translation as we've already countered parent's rotation
rebuild(object);
object->resetChildrenPosition(old_position - new_position) ;
}
}
}
new_position = (new_position - center) * mRotation; // new relative rotated position
new_position += center;
if (object->isRootEdit() && !object->isAttachment())
{
LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position);
new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global);
new_position = gAgent.getPosAgentFromGlobal(new_pos_global);
}
// for individually selected child objects
if (!object->isRootEdit() && selectNode->mIndividualSelection)
{
LLViewerObject* parentp = (LLViewerObject*)object->getParent();
if (!parentp->isSelected())
{
if (object->isAttachment() && object->mDrawable.notNull())
{
// find position relative to render position of parent
object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation());
rebuild(object);
}
else
{
object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion());
rebuild(object);
}
}
}
else if (object->isRootEdit())
{
if (object->isAttachment() && object->mDrawable.notNull())
{
LLXform* parent_xform = object->mDrawable->getXform()->getParent();
object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation());
rebuild(object);
}
else
{
object->setPositionAgent(new_position);
rebuild(object);
}
}
// for individually selected roots, we need to counter-translate all unselected children
if (object->isRootEdit() && selectNode->mIndividualSelection)
{
// only offset by parent's translation as we've already countered parent's rotation
rebuild(object);
object->resetChildrenPosition(old_position - new_position);
}
}
}
}
}
// store changes to override updates
for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
@ -725,12 +749,13 @@ void LLManipRotate::drag( S32 x, S32 y )
LLSelectNode* selectNode = *iter;
LLViewerObject*cur = selectNode->getObject();
LLViewerObject *root_object = (cur == NULL) ? NULL : cur->getRootEdit();
if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() &&
if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() &&
((root_object == NULL) || !root_object->isPermanentEnforced()) &&
(!cur->isAvatar() || LLSelectMgr::getInstance()->mAllowSelectAvatar))
{
selectNode->mLastRotation = cur->getRotation();
selectNode->mLastPositionLocal = cur->getPosition();
selectNode->mLastRotation = cur->getRotation();
selectNode->mLastPositionLocal = cur->getPosition();
}
}

View File

@ -676,119 +676,131 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask)
LLVector3d clamped_relative_move = axis_magnitude * axis_d; // scalar multiply
LLVector3 clamped_relative_move_f = (F32)axis_magnitude * axis_f; // scalar multiply
for (LLObjectSelection::iterator iter = mObjectSelection->begin();
iter != mObjectSelection->end(); iter++)
{
LLSelectNode* selectNode = *iter;
LLViewerObject* object = selectNode->getObject();
// Only apply motion to root objects and objects selected
// as "individual".
if (!object->isRootEdit() && !selectNode->mIndividualSelection)
{
continue;
}
for (LLObjectSelection::iterator iter = mObjectSelection->begin();
iter != mObjectSelection->end(); iter++)
{
LLSelectNode* selectNode = *iter;
LLViewerObject* object = selectNode->getObject();
if (!object->isRootEdit())
{
// child objects should not update if parent is selected
LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
if (editable_root->isSelected())
{
// we will be moved properly by our parent, so skip
continue;
}
}
if (selectNode->mSelectedGLTFNode != -1)
{
// manipulating a GLTF node
clamped_relative_move_f -= selectNode->mLastMoveLocal;
object->moveGLTFNode(selectNode->mSelectedGLTFNode, clamped_relative_move_f);
selectNode->mLastMoveLocal += clamped_relative_move_f;
}
else
{
// Only apply motion to root objects and objects selected
// as "individual".
if (!object->isRootEdit() && !selectNode->mIndividualSelection)
{
continue;
}
LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
if (object->permMove() && !object->isPermanentEnforced() &&
((root_object == NULL) || !root_object->isPermanentEnforced()))
{
// handle attachments in local space
if (object->isAttachment() && object->mDrawable.notNull())
{
// calculate local version of relative move
LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
objWorldRotation.transQuat();
if (!object->isRootEdit())
{
// child objects should not update if parent is selected
LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
if (editable_root->isSelected())
{
// we will be moved properly by our parent, so skip
continue;
}
}
LLVector3 old_position_local = object->getPosition();
LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation);
LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
if (object->permMove() && !object->isPermanentEnforced() &&
((root_object == NULL) || !root_object->isPermanentEnforced()))
{
// handle attachments in local space
if (object->isAttachment() && object->mDrawable.notNull())
{
// calculate local version of relative move
LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
objWorldRotation.transQuat();
//RN: I forget, but we need to do this because of snapping which doesn't often result
// in position changes even when the mouse moves
object->setPosition(new_position_local);
rebuild(object);
gAgentAvatarp->clampAttachmentPositions();
new_position_local = object->getPosition();
LLVector3 old_position_local = object->getPosition();
LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation);
if (selectNode->mIndividualSelection)
{
// counter-translate child objects if we are moving the root as an individual
object->resetChildrenPosition(old_position_local - new_position_local, TRUE) ;
}
}
else
{
// compute new position to send to simulators, but don't set it yet.
// We need the old position to know which simulator to send the move message to.
LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move;
//RN: I forget, but we need to do this because of snapping which doesn't often result
// in position changes even when the mouse moves
object->setPosition(new_position_local);
rebuild(object);
gAgentAvatarp->clampAttachmentPositions();
new_position_local = object->getPosition();
// Don't let object centers go too far underground
F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal());
if (new_position_global.mdV[VZ] < min_height)
{
new_position_global.mdV[VZ] = min_height;
}
if (selectNode->mIndividualSelection)
{
// counter-translate child objects if we are moving the root as an individual
object->resetChildrenPosition(old_position_local - new_position_local, TRUE);
}
}
else
{
// compute new position to send to simulators, but don't set it yet.
// We need the old position to know which simulator to send the move message to.
LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move;
// For safety, cap heights where objects can be dragged
// Don't let object centers go too far underground
F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal());
if (new_position_global.mdV[VZ] < min_height)
{
new_position_global.mdV[VZ] = min_height;
}
// For safety, cap heights where objects can be dragged
// <AW: opensim-limits>
// if (new_position_global.mdV[VZ] > MAX_OBJECT_Z)
// {
// new_position_global.mdV[VZ] = MAX_OBJECT_Z;
// }
if (new_position_global.mdV[VZ] > LLWorld::getInstance()->getRegionMaxHeight())
{
new_position_global.mdV[VZ] = LLWorld::getInstance()->getRegionMaxHeight();
}
// if (new_position_global.mdV[VZ] > MAX_OBJECT_Z)
// {
// new_position_global.mdV[VZ] = MAX_OBJECT_Z;
// }
if (new_position_global.mdV[VZ] > LLWorld::getInstance()->getRegionMaxHeight())
{
new_position_global.mdV[VZ] = LLWorld::getInstance()->getRegionMaxHeight();
}
// </AW: opensim-limits>
// Grass is always drawn on the ground, so clamp its position to the ground
if (object->getPCode() == LL_PCODE_LEGACY_GRASS)
{
new_position_global.mdV[VZ] = LLWorld::getInstance()->resolveLandHeightGlobal(new_position_global) + 1.f;
}
if (object->isRootEdit())
{
new_position_global = LLWorld::getInstance()->clipToVisibleRegions(object->getPositionGlobal(), new_position_global);
}
// PR: Only update if changed
LLVector3 old_position_agent = object->getPositionAgent();
LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global);
if (object->isRootEdit())
{
// finally, move parent object after children have calculated new offsets
object->setPositionAgent(new_position_agent);
rebuild(object);
}
else
{
LLViewerObject* root_object = object->getRootEdit();
new_position_agent -= root_object->getPositionAgent();
new_position_agent = new_position_agent * ~root_object->getRotation();
object->setPositionParent(new_position_agent, FALSE);
rebuild(object);
}
// Grass is always drawn on the ground, so clamp its position to the ground
if (object->getPCode() == LL_PCODE_LEGACY_GRASS)
{
new_position_global.mdV[VZ] = LLWorld::getInstance()->resolveLandHeightGlobal(new_position_global) + 1.f;
}
if (object->isRootEdit())
{
new_position_global = LLWorld::getInstance()->clipToVisibleRegions(object->getPositionGlobal(), new_position_global);
}
// PR: Only update if changed
LLVector3 old_position_agent = object->getPositionAgent();
LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global);
if (object->isRootEdit())
{
// finally, move parent object after children have calculated new offsets
object->setPositionAgent(new_position_agent);
rebuild(object);
}
else
{
LLViewerObject* root_object = object->getRootEdit();
new_position_agent -= root_object->getPositionAgent();
new_position_agent = new_position_agent * ~root_object->getRotation();
object->setPositionParent(new_position_agent, FALSE);
rebuild(object);
}
if (selectNode->mIndividualSelection)
{
// counter-translate child objects if we are moving the root as an individual
object->resetChildrenPosition(old_position_agent - new_position_agent, TRUE);
}
}
selectNode->mLastPositionLocal = object->getPosition();
}
}
}
if (selectNode->mIndividualSelection)
{
// counter-translate child objects if we are moving the root as an individual
object->resetChildrenPosition(old_position_agent - new_position_agent, TRUE) ;
}
}
selectNode->mLastPositionLocal = object->getPosition();
}
}
LLSelectMgr::getInstance()->updateSelectionCenter();
gAgentCamera.clearFocusObject();

View File

@ -41,14 +41,17 @@
#include "llviewermenufile.h"
#include "llnotificationsutil.h"
// load an OpenEXR image from a file
#define IMATH_HALF_NO_LOOKUP_TABLE 1
#include <ImfInputFile.h>
#include <ImfArray.h>
#include <ImfHeader.h>
#include <ImfFrameBuffer.h>
#include <iostream>
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4702) // compiler complains unreachable code
#endif
#define TINYEXR_USE_MINIZ 0
#include "zlib.h"
#define TINYEXR_IMPLEMENTATION
#include "tinyexr/tinyexr.h"
#if LL_WINDOWS
#pragma warning (pop)
#endif
LLPointer<LLImageGL> gEXRImage;
@ -58,55 +61,14 @@ void load_exr(const std::string& filename)
gPipeline.mReflectionMapManager.reset();
gPipeline.mReflectionMapManager.initReflectionMaps();
try {
Imf::InputFile file(filename.c_str());
Imath::Box2i dw = file.header().dataWindow();
int width = dw.max.x - dw.min.x + 1;
int height = dw.max.y - dw.min.y + 1;
Imf::Array2D<Imath::half> rPixels;
Imf::Array2D<Imath::half> gPixels;
Imf::Array2D<Imath::half> bPixels;
rPixels.resizeErase(height, width);
gPixels.resizeErase(height, width);
bPixels.resizeErase(height, width);
Imf::FrameBuffer frameBuffer;
frameBuffer.insert("R", // name
Imf::Slice(Imf::HALF, // type
(char*)(&rPixels[0][0] - // base
dw.min.x -
dw.min.y * width),
sizeof(rPixels[0][0]) * 1, // xStride
sizeof(rPixels[0][0]) * width, // yStride
1, 1, // x/y sampling
0.0)); // fillValue
frameBuffer.insert("G", // name
Imf::Slice(Imf::HALF, // type
(char*)(&gPixels[0][0] - // base
dw.min.x -
dw.min.y * width),
sizeof(gPixels[0][0]) * 1, // xStride
sizeof(gPixels[0][0]) * width, // yStride
1, 1, // x/y sampling
0.0)); // fillValue
frameBuffer.insert("B", // name
Imf::Slice(Imf::HALF, // type
(char*)(&bPixels[0][0] - // base
dw.min.x -
dw.min.y * width),
sizeof(bPixels[0][0]) * 1, // xStride
sizeof(bPixels[0][0]) * width, // yStride
1, 1, // x/y sampling
FLT_MAX)); // fillValue
file.setFrameBuffer(frameBuffer);
file.readPixels(dw.min.y, dw.max.y);
float* out; // width * height * RGBA
int width;
int height;
const char* err = NULL; // or nullptr in C++11
int ret = LoadEXRWithLayer(&out, &width, &height, filename.c_str(), /* layername */ nullptr, &err);
if (ret == TINYEXR_SUCCESS)
{
U32 texName = 0;
LLImageGL::generateTextures(1, &texName);
@ -117,27 +79,25 @@ void load_exr(const std::string& filename)
gGL.getTexUnit(0)->bind(gEXRImage);
std::vector<F32> data(width * height * 3);
for (int i = 0; i < width * height; ++i)
{
data[i * 3 + 0] = rPixels[i / width][i % width];
data[i * 3 + 1] = gPixels[i / width][i % width];
data[i * 3 + 2] = bPixels[i / width][i % width];
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGBA, GL_FLOAT, out);
free(out); // release memory of image data
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data.data());
glGenerateMipmap(GL_TEXTURE_2D);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
catch (const std::exception& e) {
else
{
LLSD notif_args;
notif_args["WHAT"] = filename;
notif_args["REASON"] = e.what();
notif_args["REASON"] = "Unknown";
if (err)
{
notif_args["REASON"] = std::string(err);
FreeEXRErrorMessage(err); // release memory of error message.
}
LLNotificationsUtil::add("CannotLoad", notif_args);
return;
}
}

View File

@ -479,7 +479,7 @@ void LLSelectMgr::overrideAvatarUpdates()
//-----------------------------------------------------------------------------
// Select just the object, not any other group members.
//-----------------------------------------------------------------------------
LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face)
LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face, S32 gltf_node, S32 gltf_primitive)
{
llassert( object );
@ -504,7 +504,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S3
// Place it in the list and tag it.
// This will refresh dialogs.
addAsIndividual(object, face);
addAsIndividual(object, face, TRUE, gltf_node, gltf_primitive);
// Stop the object from moving (this anticipates changes on the
// simulator in LLTask::userSelect)
@ -1104,7 +1104,7 @@ void LLSelectMgr::addAsFamily(std::vector<LLViewerObject*>& objects, BOOL add_to
//-----------------------------------------------------------------------------
// addAsIndividual() - a single object, face, etc
//-----------------------------------------------------------------------------
void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoable)
void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoable, S32 gltf_node, S32 gltf_primitive)
{
// check to see if object is already in list
LLSelectNode *nodep = mSelectedObjects->findNode(objectp);
@ -1151,6 +1151,13 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoab
return;
}
// Handle glTF node selection
if (gltf_node >= 0)
{
nodep->selectGLTFNode(gltf_node, gltf_primitive, TRUE);
}
saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
updateSelectionCenter();
dialog_refresh_all();
@ -5452,46 +5459,57 @@ void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type)
{
return true; // skip
}
selectNode->mSavedPositionLocal = object->getPosition();
if (object->isAttachment())
{
if (object->isRootEdit())
{
LLXform* parent_xform = object->mDrawable->getXform()->getParent();
if (parent_xform)
{
selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition());
}
else
{
selectNode->mSavedPositionGlobal = object->getPositionGlobal();
}
}
else
{
LLViewerObject* attachment_root = (LLViewerObject*)object->getParent();
LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL;
if (parent_xform)
{
LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation());
selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos);
}
else
{
selectNode->mSavedPositionGlobal = object->getPositionGlobal();
}
}
selectNode->mSavedRotation = object->getRenderRotation();
}
else
{
selectNode->mSavedPositionGlobal = object->getPositionGlobal();
selectNode->mSavedRotation = object->getRotationRegion();
}
selectNode->mSavedScale = object->getScale();
selectNode->saveTextureScaleRatios(mManager->mTextureChannel);
if (selectNode->mSelectedGLTFNode != -1)
{
// save GLTF node state
object->getGLTFNodeTransformAgent(selectNode->mSelectedGLTFNode, &selectNode->mSavedPositionLocal, &selectNode->mSavedRotation, &selectNode->mSavedScale);
selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent(selectNode->mSavedPositionLocal);
selectNode->mLastMoveLocal.setZero();
}
else
{
selectNode->mSavedPositionLocal = object->getPosition();
if (object->isAttachment())
{
if (object->isRootEdit())
{
LLXform* parent_xform = object->mDrawable->getXform()->getParent();
if (parent_xform)
{
selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition());
}
else
{
selectNode->mSavedPositionGlobal = object->getPositionGlobal();
}
}
else
{
LLViewerObject* attachment_root = (LLViewerObject*)object->getParent();
LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL;
if (parent_xform)
{
LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation());
selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos);
}
else
{
selectNode->mSavedPositionGlobal = object->getPositionGlobal();
}
}
selectNode->mSavedRotation = object->getRenderRotation();
}
else
{
selectNode->mSavedPositionGlobal = object->getPositionGlobal();
selectNode->mSavedRotation = object->getRotationRegion();
}
selectNode->mSavedScale = object->getScale();
selectNode->saveTextureScaleRatios(mManager->mTextureChannel);
}
return true;
}
} func(action_type, this);
@ -6952,8 +6970,7 @@ LLSelectNode::~LLSelectNode()
}
}
delete mPermissions;
delete mPermissions;
mPermissions = NULL;
}
@ -6981,6 +6998,17 @@ void LLSelectNode::selectTE(S32 te_index, BOOL selected)
mLastTESelected = te_index;
}
void LLSelectNode::selectGLTFNode(S32 node_index, S32 primitive_index, bool selected)
{
if (node_index < 0)
{
return;
}
mSelectedGLTFNode = node_index;
mSelectedGLTFPrimitive = primitive_index;
}
BOOL LLSelectNode::isTESelected(S32 te_index) const
{
if (te_index < 0 || te_index >= mObject->getNumTEs())

View File

@ -193,6 +193,7 @@ public:
void selectAllTEs(BOOL b);
void selectTE(S32 te_index, BOOL selected);
void selectGLTFNode(S32 node_index, S32 primitive_index, bool selected);
BOOL isTESelected(S32 te_index) const;
bool hasSelectedTE() const { return TE_SELECT_MASK_ALL & mTESelectMask; }
S32 getLastSelectedTE() const;
@ -235,6 +236,7 @@ public:
S16 mInventorySerial;
LLVector3 mSavedPositionLocal; // for interactively modifying object position
LLVector3 mLastPositionLocal;
LLVector3 mLastMoveLocal;
LLVector3d mSavedPositionGlobal; // for interactively modifying object position
LLVector3 mSavedScale; // for interactively modifying object scale
LLVector3 mLastScale;
@ -258,6 +260,8 @@ public:
std::vector<LLVector3> mSilhouetteVertices; // array of vertices to render silhouette of object
std::vector<LLVector3> mSilhouetteNormals; // array of normals to render silhouette of object
BOOL mSilhouetteExists; // need to generate silhouette?
S32 mSelectedGLTFNode = -1;
S32 mSelectedGLTFPrimitive = -1;
protected:
LLPointer<LLViewerObject> mObject;
@ -601,7 +605,7 @@ public:
LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, BOOL add_to_end = FALSE, BOOL ignore_select_owned = FALSE);
// For when you want just a child object.
LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES);
LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES, S32 gltf_node = -1, S32 gltf_primitive = -1);
// Same as above, but takes a list of objects. Used by rectangle select.
LLObjectSelectionHandle selectObjectAndFamily(const std::vector<LLViewerObject*>& object_list, BOOL send_to_sim = TRUE);
@ -906,7 +910,7 @@ public:
void remove(std::vector<LLViewerObject*>& objects);
void remove(LLViewerObject* object, S32 te = SELECT_ALL_TES, BOOL undoable = TRUE);
void removeAll();
void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, BOOL undoable = TRUE);
void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, BOOL undoable = TRUE, S32 gltf_node = -1, S32 gltf_primitive = -1);
void promoteSelectionToRoot();
void demoteSelectionToIndividuals();

View File

@ -87,20 +87,30 @@ void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material,
{
strip_alpha_channel(mr_img);
if (occlusion_img && material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index)
if (occlusion_img)
{
// occlusion is a distinct texture from pbrMetallicRoughness
// pack into mr red channel
int occlusion_idx = material.occlusionTexture.index;
int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index;
if (occlusion_idx != mr_idx)
if (material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index)
{
//scale occlusion image to match resolution of mr image
occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight());
// occlusion is a distinct texture from pbrMetallicRoughness
// pack into mr red channel
int occlusion_idx = material.occlusionTexture.index;
int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index;
if (occlusion_idx != mr_idx)
{
//scale occlusion image to match resolution of mr image
occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight());
copy_red_channel(occlusion_img, mr_img);
copy_red_channel(occlusion_img, mr_img);
}
}
}
else
{
// no occlusion, make a white occlusion image
occlusion_img = new LLImageRaw(mr_img->getWidth(), mr_img->getHeight(), 3);
occlusion_img->clear(255, 255, 255);
copy_red_channel(occlusion_img, mr_img);
}
}
else if (occlusion_img)
{

View File

@ -224,7 +224,7 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi
if ( ignore_group )
{
LLSelectMgr::getInstance()->selectObjectOnly(object, SELECT_ALL_TES);
LLSelectMgr::getInstance()->selectObjectOnly(object, SELECT_ALL_TES, pick.mGLTFNodeIndex, pick.mGLTFPrimitiveIndex);
}
else
{

View File

@ -905,10 +905,30 @@ U32 render_type_from_string(std::string render_type)
{
return LLPipeline::RENDER_TYPE_SIMPLE;
}
if ("materials" == render_type)
{
return LLPipeline::RENDER_TYPE_MATERIALS;
}
else if ("alpha" == render_type)
{
return LLPipeline::RENDER_TYPE_ALPHA;
}
else if ("alpha_mask" == render_type)
{
return LLPipeline::RENDER_TYPE_ALPHA_MASK;
}
else if ("fullbright_alpha_mask" == render_type)
{
return LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK;
}
else if ("fullbright" == render_type)
{
return LLPipeline::RENDER_TYPE_FULLBRIGHT;
}
else if ("glow" == render_type)
{
return LLPipeline::RENDER_TYPE_GLOW;
}
else if ("tree" == render_type)
{
return LLPipeline::RENDER_TYPE_TREE;
@ -1165,6 +1185,10 @@ U64 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_OCTREE;
}
else if ("nodes" == info_display)
{
return LLPipeline::RENDER_DEBUG_NODES;
}
else if ("shadow frusta" == info_display)
{
return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA;

View File

@ -4537,6 +4537,168 @@ const LLVector3 &LLViewerObject::getPositionAgent() const
return mPositionAgent;
}
LLMatrix4a LLViewerObject::getGLTFAssetToAgentTransform() const
{
LLMatrix4 root;
root.initScale(getScale());
root.rotate(getRenderRotation());
root.translate(getPositionAgent());
LLMatrix4a mat;
mat.loadu((F32*)root.mMatrix);
return mat;
}
LLVector3 LLViewerObject::getGLTFNodePositionAgent(S32 node_index) const
{
LLVector3 ret;
getGLTFNodeTransformAgent(node_index, &ret, nullptr, nullptr);
return ret;
}
LLMatrix4a LLViewerObject::getAgentToGLTFAssetTransform() const
{
LLMatrix4 root;
LLVector3 scale = getScale();
scale.mV[0] = 1.f / scale.mV[0];
scale.mV[1] = 1.f / scale.mV[1];
scale.mV[2] = 1.f / scale.mV[2];
root.translate(-getPositionAgent());
root.rotate(~getRenderRotation());
LLMatrix4 scale_mat;
scale_mat.initScale(scale);
root *= scale_mat;
LLMatrix4a mat;
mat.loadu((F32*)root.mMatrix);
return mat;
}
LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const
{
LLMatrix4a mat;
if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
{
auto& node = mGLTFAsset->mNodes[node_index];
LLMatrix4a asset_to_agent = getGLTFAssetToAgentTransform();
LLMatrix4a node_to_agent;
matMul(node.mAssetMatrix, asset_to_agent, node_to_agent);
mat = node_to_agent;
}
else
{
mat.setIdentity();
}
return mat;
}
void LLViewerObject::getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const
{
LLMatrix4a node_to_agent = getGLTFNodeTransformAgent(node_index);
if (position)
{
LLVector4a p = node_to_agent.getTranslation();
position->set(p.getF32ptr());
}
if (rotation)
{
rotation->set(node_to_agent.asMatrix4());
}
if (scale)
{
scale->mV[0] = node_to_agent.mMatrix[0].getLength3().getF32();
scale->mV[1] = node_to_agent.mMatrix[1].getLength3().getF32();
scale->mV[2] = node_to_agent.mMatrix[2].getLength3().getF32();
}
}
void decomposeMatrix(const LLMatrix4a& mat, LLVector3& position, LLQuaternion& rotation, LLVector3& scale)
{
LLVector4a p = mat.getTranslation();
position.set(p.getF32ptr());
rotation.set(mat.asMatrix4());
scale.mV[0] = mat.mMatrix[0].getLength3().getF32();
scale.mV[1] = mat.mMatrix[1].getLength3().getF32();
scale.mV[2] = mat.mMatrix[2].getLength3().getF32();
}
void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion& rotation)
{
if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
{
auto& node = mGLTFAsset->mNodes[node_index];
LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform();
LLMatrix4a agent_to_node = agent_to_asset;
if (node.mParent != -1)
{
auto& parent = mGLTFAsset->mNodes[node.mParent];
matMul(agent_to_asset, parent.mAssetMatrixInv, agent_to_node);
}
LLQuaternion agent_to_node_rot(agent_to_node.asMatrix4());
LLQuaternion new_rot;
new_rot = rotation * agent_to_node_rot;
new_rot.normalize();
LLVector3 pos;
LLQuaternion rot;
LLVector3 scale;
decomposeMatrix(node.mMatrix, pos, rot, scale);
node.mMatrix.asMatrix4().initAll(scale, new_rot, pos);
mGLTFAsset->updateTransforms();
}
}
void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset)
{
if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
{
auto& node = mGLTFAsset->mNodes[node_index];
LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform();
LLMatrix4a agent_to_node;
matMul(agent_to_asset, node.mAssetMatrixInv, agent_to_node);
LLVector4a origin = LLVector4a::getZero();
LLVector4a offset_v;
offset_v.load3(offset.mV);
agent_to_node.affineTransform(offset_v, offset_v);
agent_to_node.affineTransform(origin, origin);
offset_v.sub(origin);
offset_v.getF32ptr()[3] = 1.f;
LLMatrix4a trans;
trans.setIdentity();
trans.mMatrix[3] = offset_v;
matMul(trans, node.mMatrix, node.mMatrix);
// TODO -- only update transforms for this node and its children (or use a dirty flag)
mGLTFAsset->updateTransforms();
}
}
const LLVector3 &LLViewerObject::getPositionRegion() const
{
if (!isRoot())

View File

@ -321,6 +321,18 @@ public:
virtual const LLVector3 &getPositionAgent() const;
virtual const LLVector3 getRenderPosition() const;
LLMatrix4a getAgentToGLTFAssetTransform() const;
LLMatrix4a getGLTFAssetToAgentTransform() const;
LLVector3 getGLTFNodePositionAgent(S32 node_index) const;
LLMatrix4a getGLTFNodeTransformAgent(S32 node_index) const;
void getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const;
// move the node at the given index by the given offset in agent space
void moveGLTFNode(S32 node_index, const LLVector3& offset);
// set the rotation in agent space of the given node
void setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion& rotation);
virtual const LLVector3 getPivotPositionAgent() const; // Usually = to getPositionAgent, unless like flex objects it's not
LLViewerObject* getRootEdit() const;

View File

@ -724,7 +724,6 @@ std::string LLViewerShaderMgr::loadBasicShaders()
index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsFuncs.glsl", mShaderLevel[SHADER_WINDLIGHT] ) );
index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) );
index_channels.push_back(-1); shaders.push_back( make_pair( "environment/waterFogF.glsl", mShaderLevel[SHADER_WATER] ) );
index_channels.push_back(-1); shaders.push_back( make_pair( "environment/encodeNormF.glsl", mShaderLevel[SHADER_ENVIRONMENT] ) );
index_channels.push_back(-1); shaders.push_back( make_pair( "environment/srgbF.glsl", mShaderLevel[SHADER_ENVIRONMENT] ) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/deferredUtil.glsl", 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/globalF.glsl", 1));
@ -1060,7 +1059,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (success)
{
gDeferredDiffuseProgram.mName = "Deferred Diffuse Shader";
gDeferredDiffuseProgram.mFeatures.encodesNormal = true;
gDeferredDiffuseProgram.mFeatures.hasSrgb = true;
gDeferredDiffuseProgram.mShaderFiles.clear();
gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER));
@ -1074,7 +1072,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (success)
{
gDeferredDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Alpha Mask Shader";
gDeferredDiffuseAlphaMaskProgram.mFeatures.encodesNormal = true;
gDeferredDiffuseAlphaMaskProgram.mShaderFiles.clear();
gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER));
gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskIndexedF.glsl", GL_FRAGMENT_SHADER));
@ -1087,7 +1084,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (success)
{
gDeferredNonIndexedDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask Shader";
gDeferredNonIndexedDiffuseAlphaMaskProgram.mFeatures.encodesNormal = true;
gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.clear();
gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER));
gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskF.glsl", GL_FRAGMENT_SHADER));
@ -1099,7 +1095,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (success)
{
gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask No Color Shader";
gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mFeatures.encodesNormal = true;
gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.clear();
gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseNoColorV.glsl", GL_VERTEX_SHADER));
gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskNoColorF.glsl", GL_FRAGMENT_SHADER));
@ -1111,7 +1106,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (success)
{
gDeferredBumpProgram.mName = "Deferred Bump Shader";
gDeferredBumpProgram.mFeatures.encodesNormal = true;
gDeferredBumpProgram.mShaderFiles.clear();
gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER));
gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER));
@ -1183,7 +1177,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredMaterialProgram[i].mFeatures.hasSrgb = true;
gDeferredMaterialProgram[i].mFeatures.encodesNormal = true;
gDeferredMaterialProgram[i].mFeatures.calculatesAtmospherics = true;
gDeferredMaterialProgram[i].mFeatures.hasAtmospherics = true;
gDeferredMaterialProgram[i].mFeatures.hasGamma = true;
@ -1217,7 +1210,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (success)
{
gDeferredPBROpaqueProgram.mName = "Deferred PBR Opaque Shader";
gDeferredPBROpaqueProgram.mFeatures.encodesNormal = true;
gDeferredPBROpaqueProgram.mFeatures.hasSrgb = true;
gDeferredPBROpaqueProgram.mShaderFiles.clear();
@ -1278,7 +1270,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
shader->mFeatures.hasLighting = false;
shader->mFeatures.isAlphaLighting = true;
shader->mFeatures.hasSrgb = true;
shader->mFeatures.encodesNormal = true;
shader->mFeatures.calculatesAtmospherics = true;
shader->mFeatures.hasAtmospherics = true;
shader->mFeatures.hasGamma = true;
@ -1349,7 +1340,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredPBRTerrainProgram.mName = llformat("Deferred PBR Terrain Shader %d %s",
detail,
(mapping == 1 ? "flat" : "triplanar"));
gDeferredPBRTerrainProgram.mFeatures.encodesNormal = true;
gDeferredPBRTerrainProgram.mFeatures.hasSrgb = true;
gDeferredPBRTerrainProgram.mFeatures.isAlphaLighting = true;
gDeferredPBRTerrainProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
@ -1373,7 +1363,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
{
gDeferredTreeProgram.mName = "Deferred Tree Shader";
gDeferredTreeProgram.mShaderFiles.clear();
gDeferredTreeProgram.mFeatures.encodesNormal = true;
gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeV.glsl", GL_VERTEX_SHADER));
gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeF.glsl", GL_FRAGMENT_SHADER));
gDeferredTreeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
@ -1408,8 +1397,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
{
gDeferredImpostorProgram.mName = "Deferred Impostor Shader";
gDeferredImpostorProgram.mFeatures.hasSrgb = true;
gDeferredImpostorProgram.mFeatures.encodesNormal = true;
//gDeferredImpostorProgram.mFeatures.isDeferred = true;
gDeferredImpostorProgram.mShaderFiles.clear();
gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorV.glsl", GL_VERTEX_SHADER));
gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorF.glsl", GL_FRAGMENT_SHADER));
@ -1571,7 +1558,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
shader->mFeatures.isAlphaLighting = true;
shader->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
shader->mFeatures.hasSrgb = true;
shader->mFeatures.encodesNormal = true;
shader->mFeatures.calculatesAtmospherics = true;
shader->mFeatures.hasAtmospherics = true;
shader->mFeatures.hasGamma = true;
@ -1633,7 +1619,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
shader->mFeatures.hasSrgb = true;
shader->mFeatures.isAlphaLighting = true;
shader->mFeatures.encodesNormal = true;
shader->mFeatures.hasShadows = use_sun_shadow;
shader->mFeatures.hasReflectionProbes = true;
shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
@ -1681,7 +1666,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredAvatarEyesProgram.mFeatures.hasAtmospherics = true;
gDeferredAvatarEyesProgram.mFeatures.disableTextureIndex = true;
gDeferredAvatarEyesProgram.mFeatures.hasSrgb = true;
gDeferredAvatarEyesProgram.mFeatures.encodesNormal = true;
gDeferredAvatarEyesProgram.mFeatures.hasShadows = true;
gDeferredAvatarEyesProgram.mShaderFiles.clear();
@ -2079,7 +2063,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
if (success)
{
gDeferredTerrainProgram.mName = "Deferred Terrain Shader";
gDeferredTerrainProgram.mFeatures.encodesNormal = true;
gDeferredTerrainProgram.mFeatures.hasSrgb = true;
gDeferredTerrainProgram.mFeatures.isAlphaLighting = true;
gDeferredTerrainProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
@ -2099,7 +2082,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
{
gDeferredAvatarProgram.mName = "Deferred Avatar Shader";
gDeferredAvatarProgram.mFeatures.hasSkinning = true;
gDeferredAvatarProgram.mFeatures.encodesNormal = true;
gDeferredAvatarProgram.mShaderFiles.clear();
gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarV.glsl", GL_VERTEX_SHADER));
gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarF.glsl", GL_FRAGMENT_SHADER));
@ -2118,7 +2100,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredAvatarAlphaProgram.mFeatures.isAlphaLighting = true;
gDeferredAvatarAlphaProgram.mFeatures.disableTextureIndex = true;
gDeferredAvatarAlphaProgram.mFeatures.hasSrgb = true;
gDeferredAvatarAlphaProgram.mFeatures.encodesNormal = true;
gDeferredAvatarAlphaProgram.mFeatures.calculatesAtmospherics = true;
gDeferredAvatarAlphaProgram.mFeatures.hasAtmospherics = true;
gDeferredAvatarAlphaProgram.mFeatures.hasGamma = true;
@ -2466,7 +2447,6 @@ BOOL LLViewerShaderMgr::loadShadersObject()
if (success)
{
gObjectBumpProgram.mName = "Bump Shader";
gObjectBumpProgram.mFeatures.encodesNormal = true;
gObjectBumpProgram.mShaderFiles.clear();
gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpV.glsl", GL_VERTEX_SHADER));
gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpF.glsl", GL_FRAGMENT_SHADER));

View File

@ -276,6 +276,8 @@ LLVector2 gDebugRaycastTexCoord;
LLVector4a gDebugRaycastNormal;
LLVector4a gDebugRaycastTangent;
S32 gDebugRaycastFaceHit;
S32 gDebugRaycastGLTFNodeHit;
S32 gDebugRaycastGLTFPrimitiveHit;
LLVector4a gDebugRaycastStart;
LLVector4a gDebugRaycastEnd;
@ -3836,9 +3838,11 @@ void LLViewerWindow::updateUI()
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
{
gDebugRaycastFaceHit = -1;
gDebugRaycastFaceHit = gDebugRaycastGLTFNodeHit = gDebugRaycastGLTFPrimitiveHit = -1;
gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, FALSE,
&gDebugRaycastFaceHit,
&gDebugRaycastGLTFNodeHit,
&gDebugRaycastGLTFPrimitiveHit,
&gDebugRaycastIntersection,
&gDebugRaycastTexCoord,
&gDebugRaycastNormal,
@ -5453,6 +5457,8 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
BOOL pick_unselectable,
BOOL pick_reflection_probe,
S32* face_hit,
S32* gltf_node_hit,
S32* gltf_primitive_hit,
LLVector4a *intersection,
LLVector2 *uv,
LLVector4a *normal,
@ -5553,7 +5559,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
if (!found) // if not found in HUD, look in world:
{
found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe,
face_hit, intersection, uv, normal, tangent);
face_hit, gltf_node_hit, gltf_primitive_hit, intersection, uv, normal, tangent);
if (found && !pick_transparent)
{
gDebugRaycastIntersection = *intersection;
@ -7472,8 +7478,8 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
void LLPickInfo::fetchResults()
{
S32 face_hit = -1;
LLVector4a intersection, normal;
LLVector4a tangent;
@ -7495,8 +7501,8 @@ void LLPickInfo::fetchResults()
icon_dist = delta.getLength3().getF32();
}
LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f,
NULL, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit,
&intersection, &uv, &normal, &tangent, &start, &end);
nullptr, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit, &mGLTFNodeIndex, &mGLTFPrimitiveIndex,
&intersection, &uv, &normal, &tangent, &start, &end);
mPickPt = mMousePt;
@ -7658,6 +7664,8 @@ void LLPickInfo::getSurfaceInfo()
if (gViewerWindow->cursorIntersect(ll_round((F32)mMousePt.mX), ll_round((F32)mMousePt.mY), 1024.f,
objectp, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe,
&mObjectFace,
&mGLTFNodeIndex,
&mGLTFPrimitiveIndex,
&intersection,
&mSTCoords,
&normal,

View File

@ -120,6 +120,8 @@ public:
LLUUID mParticleOwnerID;
LLUUID mParticleSourceID;
S32 mObjectFace;
S32 mGLTFNodeIndex = -1;
S32 mGLTFPrimitiveIndex = -1;
LLHUDIcon* mHUDIcon;
LLVector3 mIntersection;
LLVector2 mUVCoords;
@ -424,6 +426,8 @@ public:
BOOL pick_unselectable = TRUE,
BOOL pick_reflection_probe = TRUE,
S32* face_hit = NULL,
S32* gltf_node_hit = nullptr,
S32* gltf_primitive_hit = nullptr,
LLVector4a *intersection = NULL,
LLVector2 *uv = NULL,
LLVector4a *normal = NULL,

View File

@ -353,8 +353,8 @@ bool addDeferredAttachments(LLRenderTarget& target, bool for_impostor = false)
{
bool valid = true
&& target.addColorAttachment(GL_RGBA) // frag-data[1] specular OR PBR ORM
&& target.addColorAttachment(GL_RGBA16F) // frag_data[2] normal+z+fogmask, See: class1\deferred\materialF.glsl & softenlight
&& target.addColorAttachment(GL_RGB16F); // frag_data[3] PBR emissive
&& target.addColorAttachment(GL_RGBA16F) // frag_data[2] normal+fogmask, See: class1\deferred\materialF.glsl & softenlight
&& target.addColorAttachment(GL_RGB16F); // frag_data[3] PBR emissive OR material env intensity
return valid;
}
@ -6450,6 +6450,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start,
bool pick_unselectable,
bool pick_reflection_probe,
S32* face_hit,
S32* gltf_node_hit,
S32* gltf_primitive_hit,
LLVector4a* intersection, // return the intersection point
LLVector2* tex_coord, // return the texture coordinates of the intersection point
LLVector4a* normal, // return the surface normal at the intersection point
@ -6493,15 +6495,6 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start,
}
}
S32 node_hit = -1;
S32 primitive_hit = -1;
LLDrawable* hit = LL::GLTFSceneManager::instance().lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, &node_hit, &primitive_hit, &position, tex_coord, normal, tangent);
if (hit)
{
drawable = hit;
local_end = position;
}
if (!sPickAvatar)
{
//save hit info in case we need to restore
@ -6602,6 +6595,25 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start,
}
}
S32 node_hit = -1;
S32 primitive_hit = -1;
LLDrawable* hit = LL::GLTFSceneManager::instance().lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, &node_hit, &primitive_hit, &position, tex_coord, normal, tangent);
if (hit)
{
drawable = hit;
local_end = position;
}
if (gltf_node_hit)
{
*gltf_node_hit = node_hit;
}
if (gltf_primitive_hit)
{
*gltf_primitive_hit = primitive_hit;
}
if (intersection)
{
*intersection = position;
@ -6722,6 +6734,10 @@ void LLPipeline::renderGLTFObjects(U32 type, bool texture, bool rigged)
{
LL::GLTFSceneManager::instance().renderOpaque();
}
else
{
LL::GLTFSceneManager::instance().render(true, true);
}
}
// Currently only used for shadows -Cosmic,2023-04-19
@ -7465,7 +7481,7 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst)
LLVector4a result;
result.clear();
gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, TRUE, NULL, &result);
gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, TRUE, nullptr, nullptr, nullptr, &result);
focus_point.set(result.getF32ptr());
}

View File

@ -210,6 +210,8 @@ public:
bool pick_unselectable,
bool pick_reflection_probe,
S32* face_hit, // return the face hit
S32* gltf_node_hit = nullptr, // return the gltf node hit
S32* gltf_primitive_hit = nullptr, // return the gltf primitive hit
LLVector4a* intersection = NULL, // return the intersection point
LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
LLVector4a* normal = NULL, // return the surface normal at the intersection point
@ -620,7 +622,7 @@ public:
RENDER_DEBUG_PHYSICS_SHAPES = 0x02000000,
RENDER_DEBUG_NORMALS = 0x04000000,
RENDER_DEBUG_LOD_INFO = 0x08000000,
RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used
RENDER_DEBUG_NODES = 0x20000000,
RENDER_DEBUG_TEXEL_DENSITY = 0x40000000,
RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000,
RENDER_DEBUG_IMPOSTORS = 0x100000000,

View File

@ -342,6 +342,11 @@
</menu>
<menu label="Darstellungstypen" name="Rendering Types">
<menu_item_check label="Einfach" name="Rendering Type Simple"/>
<menu_item_check label="Materialien" name="Rendering Type Materials"/>
<menu_item_check label="Alpha-Masken" name="Rendering Type Alpha Mask"/>
<menu_item_check label="Ganz hell Alpha-Masken" name="Rendering Type Fullbright Alpha Mask"/>
<menu_item_check label="Leuchten" name="Rendering Type Glow"/>
<menu_item_check label="Ganz hell" name="Rendering Type Fullbright"/>
<menu_item_check label="Alpha" name="Rendering Type Alpha"/>
<menu_item_check label="Baum" name="Rendering Type Tree"/>
<menu_item_check label="Avatare" name="Rendering Type Character"/>

View File

@ -3151,7 +3151,57 @@
function="Advanced.ToggleRenderType"
parameter="simple" />
</menu_item_check>
<menu_item_check
<menu_item_check
label="Materials"
name="Rendering Type Materials">
<menu_item_check.on_check
function="Advanced.CheckRenderType"
parameter="materials" />
<menu_item_check.on_click
function="Advanced.ToggleRenderType"
parameter="materials" />
</menu_item_check>
<menu_item_check
label="Alpha Mask"
name="Rendering Type Alpha Mask">
<menu_item_check.on_check
function="Advanced.CheckRenderType"
parameter="alpha_mask" />
<menu_item_check.on_click
function="Advanced.ToggleRenderType"
parameter="alpha_mask" />
</menu_item_check>
<menu_item_check
label="Fullbright Alpha Mask"
name="Rendering Type Fullbright Alpha Mask">
<menu_item_check.on_check
function="Advanced.CheckRenderType"
parameter="fullbright_alpha_mask" />
<menu_item_check.on_click
function="Advanced.ToggleRenderType"
parameter="fullbright_alpha_mask" />
</menu_item_check>
<menu_item_check
label="Glow"
name="Rendering Type Glow">
<menu_item_check.on_check
function="Advanced.CheckRenderType"
parameter="glow" />
<menu_item_check.on_click
function="Advanced.ToggleRenderType"
parameter="glow" />
</menu_item_check>
<menu_item_check
label="Fullbright"
name="Rendering Type Fullbright">
<menu_item_check.on_check
function="Advanced.CheckRenderType"
parameter="fullbright" />
<menu_item_check.on_click
function="Advanced.ToggleRenderType"
parameter="fullbright" />
</menu_item_check>
<menu_item_check
label="Alpha"
name="Rendering Type Alpha"
shortcut="control|alt|shift|2">
@ -4178,6 +4228,16 @@
function="Advanced.ToggleInfoDisplay"
parameter="octree" />
</menu_item_check>
<menu_item_check
label="GLTF Nodes"
name="GLTF Nodes">
<menu_item_check.on_check
function="Advanced.CheckInfoDisplay"
parameter="nodes" />
<menu_item_check.on_click
function="Advanced.ToggleInfoDisplay"
parameter="nodes" />
</menu_item_check>
<menu_item_check
label="Shadow Frusta"
name="Shadow Frusta">

View File

@ -705,14 +705,6 @@ class Windows_x86_64_Manifest(ViewerManifest):
self.path("libcrypto-1_1-x64.dll")
self.path("libssl-1_1-x64.dll")
# OpenEXR
self.path("Iex-3_2.dll")
self.path("IlmThread-3_2.dll")
self.path("Imath-3_1.dll")
self.path("OpenEXR-3_2.dll")
self.path("OpenEXRCore-3_2.dll")
self.path("OpenEXRUtil-3_2.dll")
# HTTP/2
self.path("nghttp2.dll")