Merge pull request #2210 from secondlife/v-1883

secondlife/viewer#1883: Local-only PBR terrain paintmap with developer tools
master
cosmic-linden 2024-08-13 10:34:35 -07:00 committed by GitHub
commit d696010cea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 906 additions and 144 deletions

View File

@ -0,0 +1,48 @@
# PBR Terrain Paintmap
## Introduction/Disclaimer
As of 2024-08-06, PBR terrain painting is **WIP**. Currently, there is only a client-side terrain paintmap, with no way to directly edit it. This document will explain how to informally explore this feature and compare it to the existing heightmap with noise. In the future, a testing document will be added for PBR terrain painting.
## Background
Historically, PBR terrain in a region has several parameters for controlling its composition. These are:
- The four materials
- The elevation of the terrain, which roughly controls the material, with some noise added on top ("heightmap with noise")
- Material Elevation Ranges, which control where the materials start and end
This allows for some coarse control over terrain composition. For example, you can have one corner of the terrain be a sandy beach and the rest of the coastline be rocky. Or you can have the peaks of your mountains be covered with snow. However, artistic control is limited due to the gradient imposed by the material elevation ranges, and the unpredictability of the noise.
A terrain painting option would allow for more control over the terrain composition. The first step to getting that working is the paintmap.
## How to activate the local paintmap
The local paintmap is a good way to assess the quality of the PBR terrain paintmap. By default, the newly created local paintmap inherits its composition (i.e. where the grass and dirt goes) from the existing terrain. This allows for a direct comparison with the terrain heightmap-with-noise shader.
Activating the local paintmap is similar to [applying local PBR terrain via the debug settings](https://wiki.secondlife.com/wiki/PBR_Terrain#How_to_apply_PBR_Terrain), but with a couple extra steps.
You will need:
- Four fullperm PBR material items to copy UUIDs from
- A region with a good variation of elevations which showcase the four composition layers (no special permissions needed)
Open the Debug Settings menu (Advanced > Show Debug Settings) and search for "terrain". The following relevant options are available:
- LocalTerrainAsset1
- LocalTerrainAsset1
- LocalTerrainAsset3
- LocalTerrainAsset4
- LocalTerrainPaintEnabled
- TerrainPaintBitDepth
- TerrainPaintResolution
By setting LocalTerrainAsset1, etc to valid material IDs, you will override the terrain to use those materials.
The next step is to "bake" the terrain into a paintmap (Develop > Terrain > Create Local Paintmap). This will *automatically* set LocalTerrainPaintEnabled to true. **WARNING:** LocalTerrainPaintEnabled will *not* do anything until one of LocalTerrainAsset1, etc is set.
You are now looking at the same terrain, but rendered as a paintmap.
To compare the quality of the paintmap version and the heightmap-with-noise version, toggle LocalTerrainPaintEnabled in Debug Settings.
To change the bit depth and/or resolution of the paintmap, change TerrainPaintBitDepth and TerrainPaintResolution as desired, then "re-bake" the paintmap (Develop > Terrain > Create Local Paintmap).

View File

@ -1409,6 +1409,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("detail_3");
mReservedUniforms.push_back("alpha_ramp");
mReservedUniforms.push_back("paint_map");
mReservedUniforms.push_back("detail_0_base_color");
mReservedUniforms.push_back("detail_1_base_color");
@ -1433,6 +1434,8 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("emissiveColors");
mReservedUniforms.push_back("minimum_alphas");
mReservedUniforms.push_back("region_scale");
mReservedUniforms.push_back("origin");
mReservedUniforms.push_back("display_gamma");

View File

@ -267,6 +267,7 @@ public:
TERRAIN_DETAIL3, // "detail_3"
TERRAIN_ALPHARAMP, // "alpha_ramp"
TERRAIN_PAINTMAP, // "paint_map"
TERRAIN_DETAIL0_BASE_COLOR, // "detail_0_base_color" (GLTF)
TERRAIN_DETAIL1_BASE_COLOR, // "detail_1_base_color" (GLTF)
@ -291,6 +292,8 @@ public:
TERRAIN_EMISSIVE_COLORS, // "emissiveColors" (GLTF)
TERRAIN_MINIMUM_ALPHAS, // "minimum_alphas" (GLTF)
REGION_SCALE, // "region_scale" (GLTF)
SHINY_ORIGIN, // "origin"
DISPLAY_GAMMA, // "display_gamma"

View File

@ -579,6 +579,7 @@ set(viewer_SOURCE_FILES
llsyswellwindow.cpp
llteleporthistory.cpp
llteleporthistorystorage.cpp
llterrainpaintmap.cpp
lltexturecache.cpp
lltexturectrl.cpp
lltexturefetch.cpp
@ -1237,6 +1238,7 @@ set(viewer_HEADER_FILES
lltable.h
llteleporthistory.h
llteleporthistorystorage.h
llterrainpaintmap.h
lltexturecache.h
lltexturectrl.h
lltexturefetch.h

View File

@ -14987,6 +14987,39 @@
<string>F32</string>
<key>Value</key>
<real>0.0</real>
</map>
<key>LocalTerrainPaintEnabled</key>
<map>
<key>Comment</key>
<string>Enables local paintmap if LocalTerrainAsset1, etc are set</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>TerrainPaintBitDepth</key>
<map>
<key>Comment</key>
<string>Bit depth for future terrain paint map operations. Min: 1. Max: 8. Takes effect when the paint map is created or modified. Modifications to an existing paintmap of different bit depth will have lower precision.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>5</integer>
</map>
<key>TerrainPaintResolution</key>
<map>
<key>Comment</key>
<string>Resolution of the terrain paint map in pixels. Rounded to a power of two. Min: 16. Max: RenderMaxTextureResolution. Takes effect when the paint map is created.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>2048</integer>
</map>
<key>PathfindingRetrieveNeighboringRegion</key>
<map>

View File

@ -30,6 +30,9 @@
#define TERRAIN_PBR_DETAIL_NORMAL -2
#define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3
#define TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 0
#define TERRAIN_PAINT_TYPE_PBR_PAINTMAP 1
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
#define TerrainCoord vec4[3]
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
@ -48,6 +51,7 @@ struct TerrainMix
};
TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal);
TerrainMix get_terrain_usage_from_weight3(vec3 weight3);
struct PBRMix
{
@ -97,7 +101,11 @@ PBRMix mix_pbr(PBRMix mix1, PBRMix mix2, float mix2_weight);
out vec4 frag_data[4];
#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE
uniform sampler2D alpha_ramp;
#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP
uniform sampler2D paint_map;
#endif
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#additional-textures
uniform sampler2D detail_0_base_color;
@ -133,19 +141,25 @@ uniform vec3[4] emissiveColors;
#endif
uniform vec4 minimum_alphas; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff()
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
in vec4[10] vary_coords;
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
in vec4[2] vary_coords;
#endif
in vec3 vary_position;
in vec3 vary_normal;
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
in vec3 vary_tangents[4];
flat in float vary_signs[4];
#endif
// vary_texcoord* are used for terrain composition, vary_coords are used for terrain UVs
#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE
in vec4 vary_texcoord0;
in vec4 vary_texcoord1;
#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP
in vec2 vary_texcoord;
#endif
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
in vec4[10] vary_coords;
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
in vec4[2] vary_coords;
#endif
void mirrorClip(vec3 position);
@ -171,11 +185,16 @@ void main()
// Make sure we clip the terrain if we're in a mirror.
mirrorClip(vary_position);
TerrainMix tm;
#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE
float alpha1 = texture(alpha_ramp, vary_texcoord0.zw).a;
float alpha2 = texture(alpha_ramp,vary_texcoord1.xy).a;
float alphaFinal = texture(alpha_ramp, vary_texcoord1.zw).a;
TerrainMix tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal);
tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal);
#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP
tm = get_terrain_usage_from_weight3(texture(paint_map, vary_texcoord).xyz);
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
// RGB = Occlusion, Roughness, Metal

View File

@ -51,7 +51,12 @@
#define TERRAIN_PBR_DETAIL_NORMAL -2
#define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3
#define TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 0
#define TERRAIN_PAINT_TYPE_PBR_PAINTMAP 1
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
in vec3 vary_vertex_normal;
#endif
vec3 srgb_to_linear(vec3 c);
@ -202,6 +207,45 @@ TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal)
return tm;
}
// A paintmap weight applier for 4 swatches. The input saves a channel by not
// storing swatch 1, and assuming the weights of the 4 swatches add to 1.
// The components of weight3 should be between 0 and 1
// The sum of the components of weight3 should be between 0 and 1
TerrainMix get_terrain_usage_from_weight3(vec3 weight3)
{
// These steps ensure the output weights add to between 0 and 1
weight3.xyz = max(vec3(0.0), weight3.xyz);
weight3.xyz /= max(1.0, weight3.x + weight3.y + weight3.z);
TerrainMix tm;
// Extract the first weight from the other weights
tm.weight.x = 1.0 - (weight3.x + weight3.y + weight3.z);
tm.weight.yzw = weight3.xyz;
ivec4 usage = max(ivec4(0), ivec4(ceil(tm.weight)));
tm.type = (usage.x * MIX_X) |
(usage.y * MIX_Y) |
(usage.z * MIX_Z) |
(usage.w * MIX_W);
return tm;
}
// Inverse of get_terrain_usage_from_weight3, excluding usage flags
// The components of weight should be between 0 and 1
// The sum of the components of weight should be 1
vec3 get_weight3_from_terrain_weight(vec4 weight)
{
// These steps ensure the input weights add to 1
weight = max(vec4(0.0), weight);
weight.x += 1.0 - sign(weight.x + weight.y + weight.z + weight.w);
weight /= weight.x + weight.y + weight.z + weight.w;
// Then return the input weights with the first weight truncated
return weight.yzw;
}
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
TerrainTriplanar _t_triplanar()
{
float sharpness = TERRAIN_TRIPLANAR_BLEND_FACTOR;
@ -219,6 +263,8 @@ TerrainTriplanar _t_triplanar()
((usage.z) * SAMPLE_Z);
return tw;
}
#endif
// Assume weights add to 1
float terrain_mix(TerrainMix tm, vec4 tms4)

View File

@ -28,31 +28,47 @@
#define TERRAIN_PBR_DETAIL_NORMAL -2
#define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3
#define TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 0
#define TERRAIN_PAINT_TYPE_PBR_PAINTMAP 1
uniform mat3 normal_matrix;
uniform mat4 texture_matrix0;
uniform mat4 modelview_matrix;
uniform mat4 modelview_projection_matrix;
#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP
uniform float region_scale;
#endif
in vec3 position;
in vec3 normal;
in vec4 tangent;
in vec4 diffuse_color;
#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE
in vec2 texcoord1;
#endif
out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl
out vec3 vary_position;
out vec3 vary_normal;
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl
#endif
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
out vec3 vary_tangents[4];
flat out float vary_signs[4];
#endif
// vary_texcoord* are used for terrain composition, vary_coords are used for terrain UVs
#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE
out vec4 vary_texcoord0;
out vec4 vary_texcoord1;
#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP
out vec2 vary_texcoord;
#endif
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
out vec4[10] vary_coords;
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
out vec4[2] vary_coords;
#endif
out vec3 vary_position;
// *HACK: Each material uses only one texture transform, but the KHR texture
// transform spec allows handling texture transforms separately for each
@ -69,7 +85,9 @@ void main()
vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
vec3 n = normal_matrix * normal;
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
vary_vertex_normal = normal;
#endif
vec3 t = normal_matrix * tangent.xyz;
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
@ -110,9 +128,9 @@ void main()
// Transform and pass tex coords
{
vec4[2] ttt;
#define transform_xy() terrain_texture_transform(position.xy, ttt)
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
// Don't care about upside-down (transform_xy_flipped())
#define transform_xy() terrain_texture_transform(position.xy, ttt)
#define transform_yz() terrain_texture_transform(position.yz, ttt)
#define transform_negx_z() terrain_texture_transform(position.xz * vec2(-1, 1), ttt)
#define transform_yz_flipped() terrain_texture_transform(position.yz * vec2(-1, 1), ttt)
@ -157,26 +175,30 @@ void main()
ttt[0].xyz = terrain_texture_transforms[0].xyz;
ttt[1].x = terrain_texture_transforms[0].w;
ttt[1].y = terrain_texture_transforms[1].x;
vary_coords[0].xy = terrain_texture_transform(position.xy, ttt);
vary_coords[0].xy = transform_xy();
// material 2
ttt[0].xyz = terrain_texture_transforms[1].yzw;
ttt[1].xy = terrain_texture_transforms[2].xy;
vary_coords[0].zw = terrain_texture_transform(position.xy, ttt);
vary_coords[0].zw = transform_xy();
// material 3
ttt[0].xy = terrain_texture_transforms[2].zw;
ttt[0].z = terrain_texture_transforms[3].x;
ttt[1].xy = terrain_texture_transforms[3].yz;
vary_coords[1].xy = terrain_texture_transform(position.xy, ttt);
vary_coords[1].xy = transform_xy();
// material 4
ttt[0].x = terrain_texture_transforms[3].w;
ttt[0].yz = terrain_texture_transforms[4].xy;
ttt[1].xy = terrain_texture_transforms[4].zw;
vary_coords[1].zw = terrain_texture_transform(position.xy, ttt);
vary_coords[1].zw = transform_xy();
#endif
}
vec4 tc = vec4(texcoord1,0,1);
#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE
vec2 tc = texcoord1.xy;
vary_texcoord0.zw = tc.xy;
vary_texcoord1.xy = tc.xy-vec2(2.0, 0.0);
vary_texcoord1.zw = tc.xy-vec2(1.0, 0.0);
#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP
vary_texcoord = position.xy / region_scale;
#endif
}

View File

@ -0,0 +1,62 @@
/**
* @file terrainBakeF.glsl
*
* $LicenseInfo:firstyear=2007&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$
*/
/*[EXTRA_CODE_HERE]*/
out vec4 frag_color;
struct TerrainMix
{
vec4 weight;
int type;
};
TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal);
uniform sampler2D alpha_ramp;
// vary_texcoord* are used for terrain composition
in vec4 vary_texcoord0;
in vec4 vary_texcoord1;
void main()
{
TerrainMix tm;
float alpha1 = texture(alpha_ramp, vary_texcoord0.zw).a;
float alpha2 = texture(alpha_ramp,vary_texcoord1.xy).a;
float alphaFinal = texture(alpha_ramp, vary_texcoord1.zw).a;
tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal);
// tm.weight.x can be ignored. The paintmap saves a channel by not storing
// swatch 1, and assuming the weights of the 4 swatches add to 1.
// TERRAIN_PAINT_PRECISION emulates loss of precision at lower bit depth
// when a corresponding low-bit image format is not available. Because
// integral values at one depth cannot be precisely represented at another
// bit depth, rounding is required. To maximize numerical stability for
// future conversions, bit depth conversions should round to the nearest
// integer, not floor or ceil.
frag_color = max(vec4(round(tm.weight.yzw * TERRAIN_PAINT_PRECISION) / TERRAIN_PAINT_PRECISION, 1.0), vec4(0));
}

View File

@ -0,0 +1,42 @@
/**
* @file pbrTerrainBakeV.glsl
*
* $LicenseInfo:firstyear=2007&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$
*/
uniform mat4 modelview_projection_matrix;
in vec3 position;
in vec2 texcoord1;
out vec4 vary_texcoord0;
out vec4 vary_texcoord1;
void main()
{
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
vec2 tc = texcoord1.xy;
vary_texcoord0.zw = tc.xy;
vary_texcoord1.xy = tc.xy-vec2(2.0, 0.0);
vary_texcoord1.zw = tc.xy-vec2(1.0, 0.0);
}

View File

@ -219,7 +219,9 @@ void LLDrawPoolTerrain::renderFullShader()
else
{
// Use materials
sShader = &gDeferredPBRTerrainProgram;
U32 paint_type = use_local_materials ? gLocalTerrainMaterials.getPaintType() : compp->getPaintType();
paint_type = llclamp(paint_type, 0, TERRAIN_PAINT_TYPE_COUNT);
sShader = &gDeferredPBRTerrainProgram[paint_type];
sShader->bind();
renderFullShaderPBR(use_local_materials);
}
@ -326,7 +328,7 @@ void LLDrawPoolTerrain::renderFullShaderTextures()
}
// *TODO: Investigate use of bindFast for PBR terrain textures
void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)
void LLDrawPoolTerrain::renderFullShaderPBR(bool use_local_materials)
{
// Hack! Get the region that this draw pool is rendering from!
LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion();
@ -339,7 +341,7 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)
llassert(shader_material_count == terrain_material_count);
#endif
if (local_materials)
if (use_local_materials)
{
// Override region terrain with the global local override terrain
fetched_materials = &gLocalTerrainMaterials.mDetailRenderMaterials;
@ -351,6 +353,9 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)
if (!materials[i]) { materials[i] = &LLGLTFMaterial::sDefault; }
}
U32 paint_type = use_local_materials ? gLocalTerrainMaterials.getPaintType() : compp->getPaintType();
paint_type = llclamp(paint_type, 0, TERRAIN_PAINT_TYPE_COUNT);
S32 detail_basecolor[terrain_material_count];
S32 detail_normal[terrain_material_count];
S32 detail_metalrough[terrain_material_count];
@ -481,11 +486,31 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)
LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
//
// Alpha Ramp
// Alpha Ramp or paint map
//
S32 alpha_ramp = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
gGL.getTexUnit(alpha_ramp)->bind(m2DAlphaRampImagep);
gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
S32 alpha_ramp = -1;
S32 paint_map = -1;
if (paint_type == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE)
{
alpha_ramp = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
gGL.getTexUnit(alpha_ramp)->bind(m2DAlphaRampImagep);
gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
}
else if (paint_type == TERRAIN_PAINT_TYPE_PBR_PAINTMAP)
{
paint_map = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_PAINTMAP);
LLViewerTexture* tex_paint_map = use_local_materials ? gLocalTerrainMaterials.getPaintMap() : compp->getPaintMap();
// If no paintmap is available, fall back to rendering just material slot 1 (by binding the appropriate image)
if (!tex_paint_map) { tex_paint_map = LLViewerTexture::sBlackImagep.get(); }
// This is a paint map for four materials, but we save a channel by
// storing the paintmap as the "difference" between slot 1 and the
// other 3 slots.
llassert(tex_paint_map->getComponents() == 3);
gGL.getTexUnit(paint_map)->bind(tex_paint_map);
gGL.getTexUnit(paint_map)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
shader->uniform1f(LLShaderMgr::REGION_SCALE, regionp->getWidth());
}
//
// GLTF uniforms
@ -534,11 +559,22 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)
// Disable multitexture
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
if (paint_type == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE)
{
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
gGL.getTexUnit(alpha_ramp)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(alpha_ramp)->disable();
gGL.getTexUnit(alpha_ramp)->activate();
gGL.getTexUnit(alpha_ramp)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(alpha_ramp)->disable();
gGL.getTexUnit(alpha_ramp)->activate();
}
else if (paint_type == TERRAIN_PAINT_TYPE_PBR_PAINTMAP)
{
sShader->disableTexture(LLViewerShaderMgr::TERRAIN_PAINTMAP);
gGL.getTexUnit(paint_map)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(paint_map)->disable();
gGL.getTexUnit(paint_map)->activate();
}
for (U32 i = 0; i < terrain_material_count; ++i)
{

View File

@ -38,7 +38,6 @@ public:
VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX |
LLVertexBuffer::MAP_NORMAL |
LLVertexBuffer::MAP_TANGENT | // Only PBR terrain uses this currently
LLVertexBuffer::MAP_TEXCOORD0 |
LLVertexBuffer::MAP_TEXCOORD1
};
@ -80,7 +79,7 @@ protected:
void renderFull4TU();
void renderFullShader();
void renderFullShaderTextures();
void renderFullShaderPBR(bool local_materials = false);
void renderFullShaderPBR(bool use_local_materials = false);
void drawLoop();
private:

View File

@ -110,6 +110,7 @@ public:
LLSurfacePatch *resolvePatchRegion(const F32 x, const F32 y) const;
LLSurfacePatch *resolvePatchRegion(const LLVector3 &position_region) const;
LLSurfacePatch *resolvePatchGlobal(const LLVector3d &position_global) const;
LLSurfacePatch *getPatch(const S32 x, const S32 y) const;
// Update methods (called during idle, normally)
template<bool PBR>
@ -176,8 +177,6 @@ protected:
void createPatchData(); // Allocates memory for patches.
void destroyPatchData(); // Deallocates memory for patches.
LLSurfacePatch *getPatch(const S32 x, const S32 y) const;
protected:
LLVector3d mOriginGlobal; // In absolute frame
LLSurfacePatch *mPatchList; // Array of all patches

View File

@ -201,13 +201,13 @@ LLVector2 LLSurfacePatch::getTexCoords(const U32 x, const U32 y) const
void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 *vertex, LLVector3 *normal,
LLVector2 *tex0, LLVector2 *tex1)
LLVector2 *tex1) const
{
if (!mSurfacep || !mSurfacep->getRegion() || !mSurfacep->getGridsPerEdge() || !mVObjp)
{
return; // failsafe
}
llassert_always(vertex && normal && tex0 && tex1);
llassert_always(vertex && normal && tex1);
U32 surface_stride = mSurfacep->getGridsPerEdge();
U32 point_offset = x + y*surface_stride;
@ -220,12 +220,6 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3
pos_agent.mV[VZ] = *(mDataZ + point_offset);
*vertex = pos_agent-mVObjp->getRegion()->getOriginAgent();
LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent();
// *NOTE: Only PBR terrain uses the UVs right now. Texture terrain just ignores it.
// *NOTE: In the future, UVs and horizontal position will no longer have a 1:1 relationship for PBR terrain
LLVector3 tex_pos = rel_pos;
tex0->mV[0] = tex_pos.mV[0];
tex0->mV[1] = tex_pos.mV[1];
tex1->mV[0] = mSurfacep->getRegion()->getCompositionXY(llfloor(mOriginRegion.mV[0])+x, llfloor(mOriginRegion.mV[1])+y);
const F32 xyScale = 4.9215f*7.f; //0.93284f;

View File

@ -116,7 +116,7 @@ public:
void calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index /* 0 or 1 */);
void eval(const U32 x, const U32 y, const U32 stride,
LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex0, LLVector2 *tex1);
LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex1) const;
@ -146,6 +146,8 @@ public:
void dirty(); // Mark this surface patch as dirty...
void clearDirty() { mDirty = false; }
bool isHeightsGenerated() const { return mHeightsGenerated; }
void clearVObj();
public:

View File

@ -0,0 +1,285 @@
/**
* @file llterrainpaintmap.cpp
* @brief Utilities for managing terrain paint maps
*
* $LicenseInfo:firstyear=2001&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 "llterrainpaintmap.h"
#include "llviewerprecompiledheaders.h"
// library includes
#include "llglslshader.h"
#include "llrendertarget.h"
#include "llvertexbuffer.h"
// newview includes
#include "llrender.h"
#include "llsurface.h"
#include "llsurfacepatch.h"
#include "llviewercamera.h"
#include "llviewerregion.h"
#include "llviewershadermgr.h"
#include "llviewertexture.h"
// static
bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex)
{
llassert(tex.getComponents() == 3);
llassert(tex.getWidth() > 0 && tex.getHeight() > 0);
llassert(tex.getWidth() == tex.getHeight());
llassert(tex.getPrimaryFormat() == GL_RGB);
llassert(tex.getGLTexture());
const LLSurface& surface = region.getLand();
const U32 patch_count = surface.getPatchesPerEdge();
// *TODO: mHeightsGenerated isn't guaranteed to be true. Assume terrain is
// loaded for now. Would be nice to fix the loading issue or find a better
// heuristic to determine that the terrain is sufficiently loaded.
#if 0
// Don't proceed if the region heightmap isn't loaded
for (U32 rj = 0; rj < patch_count; ++rj)
{
for (U32 ri = 0; ri < patch_count; ++ri)
{
const LLSurfacePatch* patch = surface.getPatch(ri, rj);
if (!patch->isHeightsGenerated())
{
LL_WARNS() << "Region heightmap not fully loaded" << LL_ENDL;
return false;
}
}
}
#endif
// Bind the debug shader and render terrain to tex
// Use a scratch render target because its dimensions may exceed the standard bake target, and this is a one-off bake
LLRenderTarget scratch_target;
const S32 dim = llmin(tex.getWidth(), tex.getHeight());
scratch_target.allocate(dim, dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE,
LLTexUnit::eTextureMipGeneration::TMG_NONE);
if (!scratch_target.isComplete())
{
llassert(false);
LL_WARNS() << "Failed to allocate render target" << LL_ENDL;
return false;
}
gGL.getTexUnit(0)->disable();
stop_glerror();
scratch_target.bindTarget();
glClearColor(0, 0, 0, 0);
scratch_target.clear();
// Render terrain heightmap to paint map via shader
// Set up viewport, camera, and orthographic projection matrix. Position
// the camera such that the camera points straight down, and the region
// completely covers the "screen". Since orthographic projection does not
// distort, we arbitrarily choose the near plane and far plane to cover the
// full span of region heights, plus a small amount of padding to account
// for rounding errors.
const F32 region_width = region.getWidth();
const F32 region_half_width = region_width / 2.0f;
const F32 region_camera_height = surface.getMaxZ() + DEFAULT_NEAR_PLANE;
LLViewerCamera camera;
const LLVector3 region_center = LLVector3(region_half_width, region_half_width, 0.0) + region.getOriginAgent();
const LLVector3 camera_origin = LLVector3(0.0f, 0.0f, region_camera_height) + region_center;
camera.lookAt(camera_origin, region_center, LLVector3::y_axis);
camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth()));
const LLRect texture_rect(0, scratch_target.getHeight(), scratch_target.getWidth(), 0);
glViewport(texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight());
// Manually get modelview matrix from camera orientation.
glh::matrix4f modelview((GLfloat *) OGL_TO_CFR_ROTATION);
GLfloat ogl_matrix[16];
camera.getOpenGLTransform(ogl_matrix);
modelview *= glh::matrix4f(ogl_matrix);
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.loadMatrix(modelview.m);
// Override the projection matrix from the camera
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.pushMatrix();
gGL.loadIdentity();
llassert(camera_origin.mV[VZ] >= surface.getMaxZ());
const F32 region_high_near = camera_origin.mV[VZ] - surface.getMaxZ();
constexpr F32 far_plane_delta = 0.25f;
const F32 region_low_far = camera_origin.mV[VZ] - surface.getMinZ() + far_plane_delta;
gGL.ortho(-region_half_width, region_half_width, -region_half_width, region_half_width, region_high_near, region_low_far);
// No need to call camera.setPerspective because we don't need the clip planes. It would be inaccurate due to the perspective rendering anyway.
// Need to get the full resolution vertices in order to get an accurate
// paintmap. It's not sufficient to iterate over the surface patches, as
// they may be at lower LODs.
// The functionality here is a subset of
// LLVOSurfacePatch::getTerrainGeometry. Unlike said function, we don't
// care about stride length since we're always rendering at full
// resolution. We also don't care about normals/tangents because those
// don't contribute to the paintmap.
// *NOTE: The actual getTerrainGeometry fits the terrain vertices snugly
// under the 16-bit indices limit. For the sake of simplicity, that has not
// been replicated here.
std::vector<LLPointer<LLDrawInfo>> infos;
// Vertex and index counts adapted from LLVOSurfacePatch::getGeomSizesMain,
// with additional vertices added as we are including the north and east
// edges here.
const U32 patch_size = (U32)surface.getGridsPerPatchEdge();
constexpr U32 stride = 1;
const U32 vert_size = (patch_size / stride) + 1;
const U32 n = vert_size * vert_size;
const U32 ni = 6 * (vert_size - 1) * (vert_size - 1);
const U32 region_vertices = n * patch_count * patch_count;
const U32 region_indices = ni * patch_count * patch_count;
if (LLGLSLShader::sCurBoundShaderPtr == nullptr)
{ // make sure a shader is bound to satisfy mVertexBuffer->setBuffer
gDebugProgram.bind();
}
LLPointer<LLVertexBuffer> buf = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD1);
{
buf->allocateBuffer(region_vertices, region_indices*2); // hack double index count... TODO: find a better way to indicate 32-bit indices will be used
buf->setBuffer();
U32 vertex_total = 0;
std::vector<U32> index_array(region_indices);
std::vector<LLVector4a> positions(region_vertices);
std::vector<LLVector2> texcoords1(region_vertices);
auto idx = index_array.begin();
auto pos = positions.begin();
auto tex1 = texcoords1.begin();
for (U32 rj = 0; rj < patch_count; ++rj)
{
for (U32 ri = 0; ri < patch_count; ++ri)
{
const U32 index_offset = vertex_total;
for (U32 j = 0; j < (vert_size - 1); ++j)
{
for (U32 i = 0; i < (vert_size - 1); ++i)
{
// y
// 2....3
// ^ . .
// | 0....1
// |
// -------> x
//
// triangle 1: 0,1,2
// triangle 2: 1,3,2
// 0: vert0
// 1: vert0 + 1
// 2: vert0 + vert_size
// 3: vert0 + vert_size + 1
const U32 vert0 = index_offset + i + (j*vert_size);
*idx++ = vert0;
*idx++ = vert0 + 1;
*idx++ = vert0 + vert_size;
*idx++ = vert0 + 1;
*idx++ = vert0 + vert_size + 1;
*idx++ = vert0 + vert_size;
}
}
const LLSurfacePatch* patch = surface.getPatch(ri, rj);
for (U32 j = 0; j < vert_size; ++j)
{
for (U32 i = 0; i < vert_size; ++i)
{
LLVector3 scratch3;
LLVector3 pos3;
LLVector2 tex1_temp;
patch->eval(i, j, stride, &pos3, &scratch3, &tex1_temp);
(*pos++).set(pos3.mV[VX], pos3.mV[VY], pos3.mV[VZ]);
*tex1++ = tex1_temp;
vertex_total++;
}
}
}
}
buf->setIndexData(index_array.data(), 0, (U32)index_array.size());
buf->setPositionData(positions.data(), 0, (U32)positions.size());
buf->setTexCoord1Data(texcoords1.data(), 0, (U32)texcoords1.size());
buf->unmapBuffer();
buf->unbind();
}
// Draw the region in agent space at full resolution
{
LLGLSLShader::unbind();
// *NOTE: A theoretical non-PBR terrain bake program would be
// *slightly* different, due the texture terrain shader not having an
// alpha ramp threshold (TERRAIN_RAMP_MIX_THRESHOLD)
LLGLSLShader& shader = gPBRTerrainBakeProgram;
shader.bind();
LLGLDisable stencil(GL_STENCIL_TEST);
LLGLDisable scissor(GL_SCISSOR_TEST);
LLGLEnable cull_face(GL_CULL_FACE);
LLGLDepthTest depth_test(GL_FALSE, GL_FALSE, GL_ALWAYS);
S32 alpha_ramp = shader.enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
LLPointer<LLViewerTexture> alpha_ramp_texture = LLViewerTextureManager::getFetchedTexture(IMG_ALPHA_GRAD_2D);
gGL.getTexUnit(alpha_ramp)->bind(alpha_ramp_texture);
gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
buf->setBuffer();
for (U32 rj = 0; rj < patch_count; ++rj)
{
for (U32 ri = 0; ri < patch_count; ++ri)
{
const U32 patch_index = ri + (rj * patch_count);
const U32 index_offset = ni * patch_index;
const U32 vertex_offset = n * patch_index;
llassert(index_offset + ni <= region_indices);
llassert(vertex_offset + n <= region_vertices);
buf->drawRange(LLRender::TRIANGLES, vertex_offset, vertex_offset + n - 1, ni, index_offset);
}
}
shader.disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
gGL.getTexUnit(alpha_ramp)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(alpha_ramp)->disable();
gGL.getTexUnit(alpha_ramp)->activate();
shader.unbind();
}
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.popMatrix();
gGL.flush();
LLVertexBuffer::unbind();
// Final step: Copy the output to the terrain paintmap
const bool success = tex.getGLTexture()->setSubImageFromFrameBuffer(0, 0, 0, 0, dim, dim);
if (!success)
{
LL_WARNS() << "Failed to copy framebuffer to paintmap" << LL_ENDL;
}
glGenerateMipmap(GL_TEXTURE_2D);
stop_glerror();
scratch_target.flush();
LLGLSLShader::unbind();
return success;
}

View File

@ -0,0 +1,42 @@
/**
* @file llterrainpaintmap.h
* @brief Utilities for managing terrain paint maps
*
* $LicenseInfo:firstyear=2001&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$
*/
#pragma once
class LLViewerRegion;
class LLViewerTexture;
class LLTerrainPaintMap
{
public:
// Convert a region's heightmap and composition into a paint map texture which
// approximates how the terrain would be rendered with the heightmap.
// In effect, this allows converting terrain of type TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE
// to type TERRAIN_PAINT_TYPE_PBR_PAINTMAP.
// Returns true if successful
static bool bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex);
};

View File

@ -719,6 +719,8 @@ void handleLocalTerrainChanged(const LLSD& newValue)
{
gLocalTerrainMaterials.setMaterialOverride(i, mat_override);
}
const bool paint_enabled = gSavedSettings.getBOOL("LocalTerrainPaintEnabled");
gLocalTerrainMaterials.setPaintType(paint_enabled ? TERRAIN_PAINT_TYPE_PBR_PAINTMAP : TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE);
}
}
////////////////////////////////////////////////////////////////////////////
@ -909,6 +911,7 @@ void settings_setup_listeners()
setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorByDistEnabled", handleUserImpostorByDistEnabledChanged);
setting_setup_signal_listener(gSavedSettings, "TuningFPSStrategy", handleFPSTuningStrategyChanged);
{
setting_setup_signal_listener(gSavedSettings, "LocalTerrainPaintEnabled", handleLocalTerrainChanged);
const char* transform_suffixes[] = {
"ScaleU",
"ScaleV",
@ -927,6 +930,7 @@ void settings_setup_listeners()
}
}
}
setting_setup_signal_listener(gSavedSettings, "TerrainPaintBitDepth", handleSetShaderChanged);
setting_setup_signal_listener(gSavedPerAccountSettings, "AvatarHoverOffsetZ", handleAvatarHoverOffsetChanged);
}

View File

@ -42,6 +42,7 @@
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llviewereventrecorder.h"
#include "v4coloru.h"
// newview includes
#include "llagent.h"
@ -105,6 +106,7 @@
#include "llsidepanelappearance.h"
#include "llspellcheckmenuhandler.h"
#include "llstatusbar.h"
#include "llterrainpaintmap.h"
#include "lltextureview.h"
#include "lltoolbarview.h"
#include "lltoolcomp.h"
@ -122,6 +124,7 @@
#include "llviewerparcelmgr.h"
#include "llviewerstats.h"
#include "llviewerstatsrecorder.h"
#include "llvlcomposition.h"
#include "llvoavatarself.h"
#include "llvoicevivox.h"
#include "llworld.h"
@ -1385,6 +1388,65 @@ class LLAdvancedResetInterestLists : public view_listener_t
};
/////////////
// TERRAIN //
/////////////
class LLAdvancedRebuildTerrain : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
gPipeline.rebuildTerrain();
return true;
}
};
class LLAdvancedTerrainCreateLocalPaintMap : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
LLViewerRegion* region = gAgent.getRegion();
if (!region)
{
LL_WARNS() << "Agent not in a region" << LL_ENDL;
return false;
}
U16 dim = (U16)gSavedSettings.getU32("TerrainPaintResolution");
// Ensure a reasonable image size of power two
const U32 max_resolution = gSavedSettings.getU32("RenderMaxTextureResolution");
dim = llclamp(dim, 16, max_resolution);
dim = 1 << U32(std::ceil(std::log2(dim)));
LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
LLPointer<LLViewerTexture> tex = LLViewerTextureManager::getLocalTexture(image_raw.get(), true);
const bool success = LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(*region, *tex);
// This calls gLocalTerrainMaterials.setPaintType
gSavedSettings.setBOOL("LocalTerrainPaintEnabled", true);
// If baking the paintmap failed, set the paintmap to nullptr. This
// causes LLDrawPoolTerrain to use a blank paintmap instead.
if (!success) { tex = nullptr; }
gLocalTerrainMaterials.setPaintMap(tex);
return true;
}
};
class LLAdvancedTerrainDeleteLocalPaintMap : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
// This calls gLocalTerrainMaterials.setPaintType
gSavedSettings.setBOOL("LocalTerrainPaintEnabled", false);
gLocalTerrainMaterials.setPaintMap(nullptr);
return true;
}
};
/////////////
class LLAdvancedBuyCurrencyTest : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
@ -2240,20 +2302,6 @@ class LLAdvancedPurgeShaderCache : public view_listener_t
}
};
/////////////////////
// REBUILD TERRAIN //
/////////////////////
class LLAdvancedRebuildTerrain : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
gPipeline.rebuildTerrain();
return true;
}
};
////////////////////
// EVENT Recorder //
///////////////////
@ -9849,7 +9897,6 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedClickGLTFEdit(), "Advanced.ClickGLTFEdit");
view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow");
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");
@ -9866,6 +9913,11 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedCheckInterestList360Mode(), "Advanced.CheckInterestList360Mode");
view_listener_t::addMenu(new LLAdvancedResetInterestLists(), "Advanced.ResetInterestLists");
// Develop > Terrain
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
view_listener_t::addMenu(new LLAdvancedTerrainCreateLocalPaintMap(), "Advanced.TerrainCreateLocalPaintMap");
view_listener_t::addMenu(new LLAdvancedTerrainDeleteLocalPaintMap(), "Advanced.TerrainDeleteLocalPaintMap");
// Advanced > UI
commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser
commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater

View File

@ -100,6 +100,7 @@ LLGLSLShader gBenchmarkProgram;
LLGLSLShader gReflectionProbeDisplayProgram;
LLGLSLShader gCopyProgram;
LLGLSLShader gCopyDepthProgram;
LLGLSLShader gPBRTerrainBakeProgram;
//object shaders
LLGLSLShader gObjectPreviewProgram;
@ -226,7 +227,7 @@ LLGLSLShader gDeferredSkinnedPBROpaqueProgram;
LLGLSLShader gHUDPBRAlphaProgram;
LLGLSLShader gDeferredPBRAlphaProgram;
LLGLSLShader gDeferredSkinnedPBRAlphaProgram;
LLGLSLShader gDeferredPBRTerrainProgram;
LLGLSLShader gDeferredPBRTerrainProgram[TERRAIN_PAINT_TYPE_COUNT];
LLGLSLShader gGLTFPBRMetallicRoughnessProgram;
@ -432,7 +433,10 @@ void LLViewerShaderMgr::finalizeShaderList()
mShaderList.push_back(&gGLTFPBRMetallicRoughnessProgram);
mShaderList.push_back(&gDeferredAvatarProgram);
mShaderList.push_back(&gDeferredTerrainProgram);
mShaderList.push_back(&gDeferredPBRTerrainProgram);
for (U32 paint_type = 0; paint_type < TERRAIN_PAINT_TYPE_COUNT; ++paint_type)
{
mShaderList.push_back(&gDeferredPBRTerrainProgram[paint_type]);
}
mShaderList.push_back(&gDeferredDiffuseAlphaMaskProgram);
mShaderList.push_back(&gDeferredNonIndexedDiffuseAlphaMaskProgram);
mShaderList.push_back(&gDeferredTreeProgram);
@ -1129,7 +1133,10 @@ bool LLViewerShaderMgr::loadShadersDeferred()
gDeferredSkinnedPBROpaqueProgram.unload();
gDeferredPBRAlphaProgram.unload();
gDeferredSkinnedPBRAlphaProgram.unload();
gDeferredPBRTerrainProgram.unload();
for (U32 paint_type = 0; paint_type < TERRAIN_PAINT_TYPE_COUNT; ++paint_type)
{
gDeferredPBRTerrainProgram[paint_type].unload();
}
return true;
}
@ -1443,25 +1450,31 @@ bool LLViewerShaderMgr::loadShadersDeferred()
S32 detail = gSavedSettings.getS32("RenderTerrainPBRDetail");
detail = llclamp(detail, TERRAIN_PBR_DETAIL_MIN, TERRAIN_PBR_DETAIL_MAX);
const S32 mapping = clamp_terrain_mapping(gSavedSettings.getS32("RenderTerrainPBRPlanarSampleCount"));
gDeferredPBRTerrainProgram.mName = llformat("Deferred PBR Terrain Shader %d %s",
detail,
(mapping == 1 ? "flat" : "triplanar"));
gDeferredPBRTerrainProgram.mFeatures.hasSrgb = true;
gDeferredPBRTerrainProgram.mFeatures.isAlphaLighting = true;
gDeferredPBRTerrainProgram.mFeatures.calculatesAtmospherics = true;
gDeferredPBRTerrainProgram.mFeatures.hasAtmospherics = true;
gDeferredPBRTerrainProgram.mFeatures.hasGamma = true;
gDeferredPBRTerrainProgram.mFeatures.hasTransport = true;
gDeferredPBRTerrainProgram.mFeatures.isPBRTerrain = true;
for (U32 paint_type = 0; paint_type < TERRAIN_PAINT_TYPE_COUNT; ++paint_type)
{
LLGLSLShader* shader = &gDeferredPBRTerrainProgram[paint_type];
shader->mName = llformat("Deferred PBR Terrain Shader %d %s %s",
detail,
(paint_type == TERRAIN_PAINT_TYPE_PBR_PAINTMAP ? "paintmap" : "heightmap-with-noise"),
(mapping == 1 ? "flat" : "triplanar"));
shader->mFeatures.hasSrgb = true;
shader->mFeatures.isAlphaLighting = true;
shader->mFeatures.calculatesAtmospherics = true;
shader->mFeatures.hasAtmospherics = true;
shader->mFeatures.hasGamma = true;
shader->mFeatures.hasTransport = true;
shader->mFeatures.isPBRTerrain = true;
gDeferredPBRTerrainProgram.mShaderFiles.clear();
gDeferredPBRTerrainProgram.mShaderFiles.push_back(make_pair("deferred/pbrterrainV.glsl", GL_VERTEX_SHADER));
gDeferredPBRTerrainProgram.mShaderFiles.push_back(make_pair("deferred/pbrterrainF.glsl", GL_FRAGMENT_SHADER));
gDeferredPBRTerrainProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
gDeferredPBRTerrainProgram.addPermutation("TERRAIN_PBR_DETAIL", llformat("%d", detail));
gDeferredPBRTerrainProgram.addPermutation("TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT", llformat("%d", mapping));
success = gDeferredPBRTerrainProgram.createShader();
llassert(success);
shader->mShaderFiles.clear();
shader->mShaderFiles.push_back(make_pair("deferred/pbrterrainV.glsl", GL_VERTEX_SHADER));
shader->mShaderFiles.push_back(make_pair("deferred/pbrterrainF.glsl", GL_FRAGMENT_SHADER));
shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
shader->addPermutation("TERRAIN_PBR_DETAIL", llformat("%d", detail));
shader->addPermutation("TERRAIN_PAINT_TYPE", llformat("%d", paint_type));
shader->addPermutation("TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT", llformat("%d", mapping));
success = success && shader->createShader();
llassert(success);
}
}
if (success)
@ -2957,6 +2970,25 @@ bool LLViewerShaderMgr::loadShadersInterface()
success = gCopyDepthProgram.createShader();
}
if (success)
{
LLGLSLShader* shader = &gPBRTerrainBakeProgram;
U32 bit_depth = gSavedSettings.getU32("TerrainPaintBitDepth");
// LLTerrainPaintMap currently uses an RGB8 texture internally
bit_depth = llclamp(bit_depth, 1, 8);
shader->mName = llformat("Terrain Bake Shader RGB%o", bit_depth);
shader->mFeatures.isPBRTerrain = true;
shader->mShaderFiles.clear();
shader->mShaderFiles.push_back(make_pair("interface/pbrTerrainBakeV.glsl", GL_VERTEX_SHADER));
shader->mShaderFiles.push_back(make_pair("interface/pbrTerrainBakeF.glsl", GL_FRAGMENT_SHADER));
shader->mShaderLevel = mShaderLevel[SHADER_INTERFACE];
const U32 value_range = (1 << bit_depth) - 1;
shader->addPermutation("TERRAIN_PAINT_PRECISION", llformat("%d", value_range));
success = success && shader->createShader();
llassert(success);
}
if (success)
{
gAlphaMaskProgram.mName = "Alpha Mask Shader";

View File

@ -174,6 +174,7 @@ extern LLGLSLShader gBenchmarkProgram;
extern LLGLSLShader gReflectionProbeDisplayProgram;
extern LLGLSLShader gCopyProgram;
extern LLGLSLShader gCopyDepthProgram;
extern LLGLSLShader gPBRTerrainBakeProgram;
//output tex0[tc0] - tex1[tc1]
extern LLGLSLShader gTwoTextureCompareProgram;
@ -304,5 +305,13 @@ enum TerrainPBRDetail : S32
TERRAIN_PBR_DETAIL_BASE_COLOR = -4,
TERRAIN_PBR_DETAIL_MIN = -4,
};
extern LLGLSLShader gDeferredPBRTerrainProgram;
enum TerrainPaintType : U32
{
// Use LLVLComposition::mDatap (heightmap) generated by generateHeights, plus noise from TERRAIN_ALPHARAMP
TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE = 0,
// Use paint map if PBR terrain, otherwise fall back to TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE
TERRAIN_PAINT_TYPE_PBR_PAINTMAP = 1,
TERRAIN_PAINT_TYPE_COUNT = 2,
};
extern LLGLSLShader gDeferredPBRTerrainProgram[TERRAIN_PAINT_TYPE_COUNT];
#endif

View File

@ -42,6 +42,7 @@
#include "llstl.h"
#include "message.h"
#include "lltimer.h"
#include "v4coloru.h"
// viewer includes
#include "llimagegl.h"

View File

@ -4185,15 +4185,17 @@ void LLViewerWindow::renderSelections( bool for_gl_pick, bool pick_parcel_walls,
}
}
}
if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount())
{
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.popMatrix();
}
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.popMatrix();
stop_glerror();
}
// un-setup HUD render
if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount())
{
gGL.matrixMode(LLRender::MM_PROJECTION);
gGL.popMatrix();
gGL.matrixMode(LLRender::MM_MODELVIEW);
gGL.popMatrix();
stop_glerror();
}
}
}

View File

@ -312,6 +312,17 @@ bool LLTerrainMaterials::makeMaterialsReady(bool boost, bool strict)
return one_ready;
}
LLViewerTexture* LLTerrainMaterials::getPaintMap()
{
return mPaintMap.get();
}
void LLTerrainMaterials::setPaintMap(LLViewerTexture* paint_map)
{
llassert(!paint_map || mPaintType == TERRAIN_PAINT_TYPE_PBR_PAINTMAP);
mPaintMap = paint_map;
}
// Boost the texture loading priority
// Return true when ready to use (i.e. texture is sufficiently loaded)
// static

View File

@ -28,6 +28,8 @@
#define LL_LLVLCOMPOSITION_H
#include "llviewerlayer.h"
#include "llviewershadermgr.h"
#include "llviewertexture.h"
#include "llpointer.h"
#include "llimage.h"
@ -44,6 +46,7 @@ public:
virtual const LLGLTFMaterial* getMaterialOverride(S32 asset) const = 0;
};
// The subset of the composition used by local terrain debug materials (gLocalTerrainMaterials)
class LLTerrainMaterials : public LLModifyRegion
{
public:
@ -79,6 +82,12 @@ public:
// strict = false -> at least one material must be loaded
bool makeMaterialsReady(bool boost, bool strict);
// See TerrainPaintType
U32 getPaintType() const { return mPaintType; }
void setPaintType(U32 paint_type) { mPaintType = paint_type; }
LLViewerTexture* getPaintMap();
void setPaintMap(LLViewerTexture* paint_map);
protected:
void unboost();
static bool makeTextureReady(LLPointer<LLViewerFetchedTexture>& tex, bool boost);
@ -93,6 +102,9 @@ protected:
LLPointer<LLGLTFMaterial> mDetailMaterialOverrides[ASSET_COUNT];
LLPointer<LLFetchedGLTFMaterial> mDetailRenderMaterials[ASSET_COUNT];
bool mMaterialTexturesSet[ASSET_COUNT];
U32 mPaintType = TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE;
LLPointer<LLViewerTexture> mPaintMap;
};
// Local materials to override all regions

View File

@ -245,7 +245,6 @@ bool LLVOSurfacePatch::updateLOD()
void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,
LLStrider<LLVector3> &normalsp,
LLStrider<LLVector2> &texCoords0p,
LLStrider<LLVector2> &texCoords1p,
LLStrider<U16> &indicesp)
{
@ -260,21 +259,18 @@ void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,
updateMainGeometry(facep,
verticesp,
normalsp,
texCoords0p,
texCoords1p,
indicesp,
index_offset);
updateNorthGeometry(facep,
verticesp,
normalsp,
texCoords0p,
texCoords1p,
indicesp,
index_offset);
updateEastGeometry(facep,
verticesp,
normalsp,
texCoords0p,
texCoords1p,
indicesp,
index_offset);
@ -283,7 +279,6 @@ void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,
void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
LLStrider<LLVector3> &verticesp,
LLStrider<LLVector3> &normalsp,
LLStrider<LLVector2> &texCoords0p,
LLStrider<LLVector2> &texCoords1p,
LLStrider<U16> &indicesp,
U32 &index_offset)
@ -322,10 +317,9 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
{
x = i * render_stride;
y = j * render_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
}
@ -387,7 +381,6 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
LLStrider<LLVector3> &verticesp,
LLStrider<LLVector3> &normalsp,
LLStrider<LLVector2> &texCoords0p,
LLStrider<LLVector2> &texCoords1p,
LLStrider<U16> &indicesp,
U32 &index_offset)
@ -421,10 +414,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
x = i * render_stride;
y = 16 - render_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -433,10 +425,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
{
x = i * render_stride;
y = 16;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -469,10 +460,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
x = i * render_stride;
y = 16 - render_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -482,10 +472,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
x = i * render_stride;
y = 16;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -525,10 +514,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
x = i * north_stride;
y = 16 - render_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -538,10 +526,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
x = i * north_stride;
y = 16;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -577,7 +564,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,
void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
LLStrider<LLVector3> &verticesp,
LLStrider<LLVector3> &normalsp,
LLStrider<LLVector2> &texCoords0p,
LLStrider<LLVector2> &texCoords1p,
LLStrider<U16> &indicesp,
U32 &index_offset)
@ -606,10 +592,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
x = 16 - render_stride;
y = i * render_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -618,10 +603,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
{
x = 16;
y = i * render_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -654,10 +638,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
x = 16 - render_stride;
y = i * render_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
// Iterate through the east patch's points
@ -666,10 +649,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
x = 16;
y = i * render_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -708,10 +690,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
x = 16 - render_stride;
y = i * east_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
// Iterate through the east patch's points
@ -720,10 +701,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,
x = 16;
y = i * east_stride;
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());
mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());
verticesp++;
normalsp++;
texCoords0p++;
texCoords1p++;
}
@ -992,8 +972,8 @@ void gen_terrain_tangents(U32 strider_vertex_count,
LLStrider<LLVector3> &verticesp,
LLStrider<LLVector3> &normalsp,
LLStrider<LLVector4a> &tangentsp,
LLStrider<LLVector2> &texCoords0p,
LLStrider<U16> &indicesp)
LLStrider<U16> &indicesp,
F32 region_width)
{
LL_PROFILE_ZONE_SCOPED;
@ -1010,7 +990,10 @@ void gen_terrain_tangents(U32 strider_vertex_count,
F32 *n = normalsp[v].mV;
normals[v] = LLVector4a(n[0], n[1], n[2], 1.f);
tangents[v] = tangentsp[v];
texcoords[v] = texCoords0p[v];
// Calculate texcoords on-the-fly using the terrain positions
texcoords[v].mV[VX] = verticesp[v].mV[VX] / region_width;
texcoords[v].mV[VY] = verticesp[v].mV[VY] / region_width;
}
for (U32 i = 0; i < strider_index_count; ++i)
{
@ -1039,14 +1022,12 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
LLStrider<LLVector3> vertices_start;
LLStrider<LLVector3> normals_start;
LLStrider<LLVector4a> tangents_start;
LLStrider<LLVector2> texcoords_start;
LLStrider<LLVector2> texcoords2_start;
LLStrider<U16> indices_start;
llassert_always(buffer->getVertexStrider(vertices_start));
llassert_always(buffer->getNormalStrider(normals_start));
llassert_always(buffer->getTangentStrider(tangents_start));
llassert_always(buffer->getTexCoord0Strider(texcoords_start));
llassert_always(buffer->getTexCoord1Strider(texcoords2_start));
llassert_always(buffer->getIndexStrider(indices_start));
@ -1056,7 +1037,6 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
{
LLStrider<LLVector3> vertices = vertices_start;
LLStrider<LLVector3> normals = normals_start;
LLStrider<LLVector2> texcoords = texcoords_start;
LLStrider<LLVector2> texcoords2 = texcoords2_start;
LLStrider<U16> indices = indices_start;
@ -1069,7 +1049,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
facep->setVertexBuffer(buffer);
LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject();
patchp->getTerrainGeometry(vertices, normals, texcoords, texcoords2, indices);
patchp->getTerrainGeometry(vertices, normals, texcoords2, indices);
indices_index += facep->getIndicesCount();
index_offset += facep->getGeomCount();
@ -1082,10 +1062,20 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
LLStrider<LLVector3> vertices = vertices_start;
LLStrider<LLVector3> normals = normals_start;
LLStrider<LLVector4a> tangents = tangents_start;
LLStrider<LLVector2> texcoords = texcoords_start;
LLStrider<U16> indices = indices_start;
gen_terrain_tangents(index_offset, indices_index, vertices, normals, tangents, texcoords, indices);
F32 region_width = 256.0f;
if (mFaceList.empty())
{
llassert(false);
}
else
{
const LLViewerRegion* regionp = mFaceList[0]->getViewerObject()->getRegion();
llassert(regionp == mFaceList.back()->getViewerObject()->getRegion()); // Assume this spatial group is confined to one region
region_width = regionp->getWidth();
}
gen_terrain_tangents(index_offset, indices_index, vertices, normals, tangents, indices, region_width);
}
buffer->unmapBuffer();

View File

@ -41,14 +41,6 @@ class LLVOSurfacePatch : public LLStaticViewerObject
public:
static F32 sLODFactor;
enum
{
VERTEX_DATA_MASK = (1 << LLVertexBuffer::TYPE_VERTEX) |
(1 << LLVertexBuffer::TYPE_NORMAL) |
(1 << LLVertexBuffer::TYPE_TEXCOORD0) |
(1 << LLVertexBuffer::TYPE_TEXCOORD1)
};
LLVOSurfacePatch(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
/*virtual*/ void markDead();
@ -65,7 +57,6 @@ public:
/*virtual*/ void updateFaceSize(S32 idx);
void getTerrainGeometry(LLStrider<LLVector3> &verticesp,
LLStrider<LLVector3> &normalsp,
LLStrider<LLVector2> &texCoords0p,
LLStrider<LLVector2> &texCoords1p,
LLStrider<U16> &indicesp);
@ -118,21 +109,18 @@ protected:
void updateMainGeometry(LLFace *facep,
LLStrider<LLVector3> &verticesp,
LLStrider<LLVector3> &normalsp,
LLStrider<LLVector2> &texCoords0p,
LLStrider<LLVector2> &texCoords1p,
LLStrider<U16> &indicesp,
U32 &index_offset);
void updateNorthGeometry(LLFace *facep,
LLStrider<LLVector3> &verticesp,
LLStrider<LLVector3> &normalsp,
LLStrider<LLVector2> &texCoords0p,
LLStrider<LLVector2> &texCoords1p,
LLStrider<U16> &indicesp,
U32 &index_offset);
void updateEastGeometry(LLFace *facep,
LLStrider<LLVector3> &verticesp,
LLStrider<LLVector3> &normalsp,
LLStrider<LLVector2> &texCoords0p,
LLStrider<LLVector2> &texCoords1p,
LLStrider<U16> &indicesp,
U32 &index_offset);

View File

@ -3435,13 +3435,6 @@ function="World.EnvPreset"
<menu_item_call.on_click
function="Advanced.ClearShaderCache" />
</menu_item_call>
<menu_item_call
enabled="true"
label="Rebuild Terrain"
name="Rebuild Terrain">
<menu_item_call.on_click
function="Advanced.RebuildTerrain" />
</menu_item_call>
<menu_item_separator />
<menu_item_call
enabled="true"
@ -3662,6 +3655,37 @@ function="World.EnvPreset"
function="Advanced.ResetInterestLists" />
</menu_item_call>
</menu>
<!-- terrain -->
<menu
create_jump_keys="true"
label="Terrain"
name="DevelopTerrain"
tear_off="true">
<menu_item_call
enabled="true"
label="Rebuild Terrain"
name="Rebuild Terrain">
<menu_item_call.on_click
function="Advanced.RebuildTerrain" />
</menu_item_call>
<menu_item_separator/>
<menu_item_call
enabled="true"
label="Create Local Paintmap"
name="Create Local Paintmap">
<menu_item_call.on_click
function="Advanced.TerrainCreateLocalPaintMap" />
</menu_item_call>
<menu_item_call
enabled="true"
label="Delete Local Paintmap"
name="Delete Local Paintmap">
<menu_item_call.on_click
function="Advanced.TerrainDeleteLocalPaintMap" />
</menu_item_call>
</menu>
<menu
create_jump_keys="true"
label="UI"