SL-17281 environment map prototype (stupid slow and hacky, but provides a way to get a "real" environment map for shader development)

master
Dave Parks 2022-04-28 15:51:31 +00:00
parent a3ffa9f006
commit deffbca3ee
9 changed files with 231 additions and 195 deletions

View File

@ -166,6 +166,39 @@ void LLCubeMap::init(const std::vector<LLPointer<LLImageRaw> >& rawimages)
}
}
void LLCubeMap::initEnvironmentMap(const std::vector<LLPointer<LLImageRaw> >& rawimages)
{
llassert(rawimages.size() == 6);
U32 texname = 0;
LLImageGL::generateTextures(1, &texname);
U32 resolution = rawimages[0]->getWidth();
U32 components = rawimages[0]->getComponents();
for (int i = 0; i < 6; i++)
{
llassert(rawimages[i]->getWidth() == resolution);
llassert(rawimages[i]->getHeight() == resolution);
llassert(rawimages[i]->getComponents() == components);
mImages[i] = new LLImageGL(resolution, resolution, components, FALSE);
mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP);
mRawImages[i] = rawimages[i];
mImages[i]->createGLTexture(0, mRawImages[i], texname);
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname);
mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
stop_glerror();
mImages[i]->setSubImage(mRawImages[i], 0, 0, resolution, resolution);
}
gGL.getTexUnit(0)->disable();
disable();
}
GLuint LLCubeMap::getGLName()
{
return mImages[0]->getTexName();
@ -256,191 +289,6 @@ void LLCubeMap::restoreMatrix()
}*/
}
void LLCubeMap::setReflection (void)
{
gGL.getTexUnit(mTextureStage)->bindManual(LLTexUnit::TT_CUBE_MAP, getGLName());
mImages[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
mImages[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
}
LLVector3 LLCubeMap::map(U8 side, U16 v_val, U16 h_val) const
{
LLVector3 dir;
const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
const S8 side_dir = (((side & 1) << 1) - 1); // even = -1, odd = 1
const U8 i_coef = (curr_coef + 1) % 3;
const U8 j_coef = (i_coef + 1) % 3;
dir.mV[curr_coef] = side_dir;
switch (side)
{
case 0: // negative X
dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
break;
case 1: // positive X
dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
dir.mV[j_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
break;
case 2: // negative Y
dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
break;
case 3: // positive Y
dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
break;
case 4: // negative Z
dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
dir.mV[j_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
break;
case 5: // positive Z
dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
dir.mV[j_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
break;
default:
dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
}
dir.normVec();
return dir;
}
BOOL LLCubeMap::project(F32& v_val, F32& h_val, BOOL& outside,
U8 side, const LLVector3& dir) const
{
const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
const S8 side_dir = (((side & 1) << 1) - 1); // even = -1, odd = 1
const U8 i_coef = (curr_coef + 1) % 3;
const U8 j_coef = (i_coef + 1) % 3;
outside = TRUE;
if (side_dir * dir.mV[curr_coef] < 0)
return FALSE;
LLVector3 ray;
F32 norm_val = fabs(dir.mV[curr_coef]);
if (norm_val < epsilon)
norm_val = 1e-5f;
ray.mV[curr_coef] = side_dir;
ray.mV[i_coef] = dir.mV[i_coef] / norm_val;
ray.mV[j_coef] = dir.mV[j_coef] / norm_val;
const F32 i_val = (ray.mV[i_coef] + 1) * 0.5f * RESOLUTION;
const F32 j_val = (ray.mV[j_coef] + 1) * 0.5f * RESOLUTION;
switch (side)
{
case 0: // negative X
v_val = RESOLUTION - i_val;
h_val = j_val;
break;
case 1: // positive X
v_val = RESOLUTION - i_val;
h_val = RESOLUTION - j_val;
break;
case 2: // negative Y
v_val = RESOLUTION - i_val;
h_val = j_val;
break;
case 3: // positive Y
v_val = i_val;
h_val = j_val;
break;
case 4: // negative Z
v_val = RESOLUTION - j_val;
h_val = RESOLUTION - i_val;
break;
case 5: // positive Z
v_val = RESOLUTION - j_val;
h_val = i_val;
break;
default:
v_val = i_val;
h_val = j_val;
}
outside = ((v_val < 0) || (v_val > RESOLUTION) ||
(h_val < 0) || (h_val > RESOLUTION));
return TRUE;
}
BOOL LLCubeMap::project(F32& v_min, F32& v_max, F32& h_min, F32& h_max,
U8 side, LLVector3 dir[4]) const
{
v_min = h_min = RESOLUTION;
v_max = h_max = 0;
BOOL fully_outside = TRUE;
for (U8 vtx = 0; vtx < 4; ++vtx)
{
F32 v_val, h_val;
BOOL outside;
BOOL consider = project(v_val, h_val, outside, side, dir[vtx]);
if (!outside)
fully_outside = FALSE;
if (consider)
{
if (v_val < v_min) v_min = v_val;
if (v_val > v_max) v_max = v_val;
if (h_val < h_min) h_min = h_val;
if (h_val > h_max) h_max = h_val;
}
}
v_min = llmax(0.0f, v_min);
v_max = llmin(RESOLUTION - epsilon, v_max);
h_min = llmax(0.0f, h_min);
h_max = llmin(RESOLUTION - epsilon, h_max);
return !fully_outside;
}
void LLCubeMap::paintIn(LLVector3 dir[4], const LLColor4U& col)
{
LL_PROFILE_ZONE_SCOPED;
F32 v_min, v_max, h_min, h_max;
LLVector3 center = dir[0] + dir[1] + dir[2] + dir[3];
center.normVec();
for (U8 side = 0; side < 6; ++side)
{
if (!project(v_min, v_max, h_min, h_max, side, dir))
continue;
U8 *td = mRawImages[side]->getData();
U16 v_minu = (U16) v_min;
U16 v_maxu = (U16) (ceil(v_max) + 0.5);
U16 h_minu = (U16) h_min;
U16 h_maxu = (U16) (ceil(h_max) + 0.5);
for (U16 v = v_minu; v < v_maxu; ++v)
for (U16 h = h_minu; h < h_maxu; ++h)
//for (U16 v = 0; v < RESOLUTION; ++v)
// for (U16 h = 0; h < RESOLUTION; ++h)
{
const LLVector3 ray = map(side, v, h);
if (ray * center > 0.999)
{
const U32 offset = (RESOLUTION * v + h) * 4;
for (U8 cc = 0; cc < 3; ++cc)
td[offset + cc] = U8((td[offset + cc] + col.mV[cc]) * 0.5);
}
}
mImages[side]->setSubImage(mRawImages[side], 0, 0, RESOLUTION, RESOLUTION);
}
}
void LLCubeMap::destroyGL()
{

View File

@ -40,6 +40,13 @@ class LLCubeMap : public LLRefCount
public:
LLCubeMap(bool init_as_srgb);
void init(const std::vector<LLPointer<LLImageRaw> >& rawimages);
// init from environment map images
// Similar to init, but takes ownership of rawimages and makes this cubemap
// respect the resolution of rawimages
// Raw images must point to array of six square images that are all the same resolution
// For example usage, see LLEnvironmentMap
void initEnvironmentMap(const std::vector<LLPointer<LLImageRaw> >& rawimages);
void initGL();
void initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages);
void initGLData();
@ -54,18 +61,9 @@ public:
void disableTexture(void);
void setMatrix(S32 stage);
void restoreMatrix();
void setReflection (void);
void finishPaint();
GLuint getGLName();
LLVector3 map(U8 side, U16 v_val, U16 h_val) const;
BOOL project(F32& v_val, F32& h_val, BOOL& outside,
U8 side, const LLVector3& dir) const;
BOOL project(F32& v_min, F32& v_max, F32& h_min, F32& h_max,
U8 side, LLVector3 dir[4]) const;
void paintIn(LLVector3 dir[4], const LLColor4U& col);
void destroyGL();
public:

View File

@ -196,6 +196,7 @@ set(viewer_SOURCE_FILES
lldynamictexture.cpp
llemote.cpp
llenvironment.cpp
llenvironmentmap.cpp
llestateinfomodel.cpp
lleventnotifier.cpp
lleventpoll.cpp
@ -832,6 +833,7 @@ set(viewer_HEADER_FILES
lldynamictexture.h
llemote.h
llenvironment.h
llenvironmentmap.h
llestateinfomodel.h
lleventnotifier.h
lleventpoll.h

View File

@ -0,0 +1,116 @@
/**
* @file llenvironmentmap.cpp
* @brief LLEnvironmentMap class implementation
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, 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 "llenvironmentmap.h"
#include "pipeline.h"
#include "llviewerwindow.h"
LLEnvironmentMap::LLEnvironmentMap()
{
mOrigin.setVec(0, 0, 0);
}
void LLEnvironmentMap::update(const LLVector3& origin, U32 resolution)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
mOrigin = origin;
// allocate images
std::vector<LLPointer<LLImageRaw> > rawimages;
rawimages.reserve(6);
for (int i = 0; i < 6; ++i)
{
rawimages.push_back(new LLImageRaw(resolution, resolution, 3));
}
// ============== modified copy/paste of LLFloater360Capture::capture360Images() follows ==============
// these are the 6 directions we will point the camera, see LLCubeMap::mTargets
LLVector3 look_dirs[6] = {
LLVector3(-1, 0, 0),
LLVector3(1, 0, 0),
LLVector3(0, -1, 0),
LLVector3(0, 1, 0),
LLVector3(0, 0, -1),
LLVector3(0, 0, 1)
};
LLVector3 look_upvecs[6] = {
LLVector3(0, -1, 0),
LLVector3(0, -1, 0),
LLVector3(0, 0, -1),
LLVector3(0, 0, 1),
LLVector3(0, 1, 0),
LLVector3(0, -1, 0)
};
// save current view/camera settings so we can restore them afterwards
S32 old_occlusion = LLPipeline::sUseOcclusion;
// set new parameters specific to the 360 requirements
LLPipeline::sUseOcclusion = 0;
LLViewerCamera* camera = LLViewerCamera::getInstance();
LLVector3 old_origin = camera->getOrigin();
F32 old_fov = camera->getView();
F32 old_aspect = camera->getAspect();
F32 old_yaw = camera->getYaw();
// camera constants for the square, cube map capture image
camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV
camera->setView(F_PI_BY_TWO);
camera->yaw(0.0);
camera->setOrigin(mOrigin);
// for each of the 6 directions we shoot...
for (int i = 0; i < 6; i++)
{
// set up camera to look in each direction
camera->lookDir(look_dirs[i], look_upvecs[i]);
// call the (very) simplified snapshot code that simply deals
// with a single image, no sub-images etc. but is very fast
gViewerWindow->simpleSnapshot(rawimages[i],
resolution, resolution, 1);
}
// restore original view/camera/avatar settings settings
camera->setAspect(old_aspect);
camera->setView(old_fov);
camera->yaw(old_yaw);
camera->setOrigin(old_origin);
LLPipeline::sUseOcclusion = old_occlusion;
// ====================================================
mCubeMap = new LLCubeMap(false);
mCubeMap->initEnvironmentMap(rawimages);
}

View File

@ -0,0 +1,48 @@
/**
* @file llenvironmentmap.h
* @brief LLEnvironmentMap class declaration
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, 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$
*/
#pragma once
#include "llcubemap.h"
class LLEnvironmentMap
{
public:
// allocate an environment map of the given resolution
LLEnvironmentMap();
// update this environment map
// origin - position in agent space to generate environment map from in agent space
// resolution - size of cube map to generate
void update(const LLVector3& origin, U32 resolution);
// cube map used to sample this environment map
LLPointer<LLCubeMap> mCubeMap;
// point at which environment map was generated from (in agent space)
LLVector3 mOrigin;
};

View File

@ -8304,6 +8304,12 @@ void handle_cache_clear_immediately()
LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately);
}
void handle_override_environment_map()
{
gPipeline.overrideEnvironmentMap();
}
void handle_web_content_test(const LLSD& param)
{
std::string url = param.asString();
@ -9402,6 +9408,8 @@ void initialize_menus()
view_listener_t::addMenu(new LLDevelopTextureFetchDebugger(), "Develop.SetTexFetchDebugger");
//Develop (clear cache immediately)
commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) );
//Develop (override environment map)
commit.add("Develop.OverrideEnvironmentMap", boost::bind(&handle_override_environment_map));
// Admin >Object
view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy");

View File

@ -8191,7 +8191,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
if (channel > -1)
{
LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
LLCubeMap* cube_map = mEnvironmentMap.mCubeMap.notNull() ? mEnvironmentMap.mCubeMap : gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
if (cube_map)
{
cube_map->enable(channel);
@ -11467,3 +11467,8 @@ void LLPipeline::restoreHiddenObject( const LLUUID& id )
}
}
void LLPipeline::overrideEnvironmentMap()
{
mEnvironmentMap.update(LLViewerCamera::instance().getOrigin(), 1024);
}

View File

@ -38,6 +38,7 @@
#include "llgl.h"
#include "lldrawable.h"
#include "llrendertarget.h"
#include "llenvironmentmap.h"
#include <stack>
@ -426,6 +427,9 @@ public:
void hideObject( const LLUUID& id );
void restoreHiddenObject( const LLUUID& id );
LLEnvironmentMap mEnvironmentMap;
void overrideEnvironmentMap();
private:
void unloadShaders();
void addToQuickLookup( LLDrawPool* new_poolp );

View File

@ -3250,6 +3250,13 @@ function="World.EnvPreset"
function="ToggleControl"
parameter="RenderHoverGlowEnable" />
</menu_item_check>
<menu_item_call
enabled="true"
label="Override Environment Map"
name="Override Environment Map">
<menu_item_call.on_click
function="Develop.OverrideEnvironmentMap" />
</menu_item_call>
<menu_item_separator />
<menu_item_call