secondlife/viewer#1883: Local-only PBR terrain paintmap with developer tools
parent
ae2ff22542
commit
6aa9110b2a
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -578,6 +578,7 @@ set(viewer_SOURCE_FILES
|
|||
llsyswellwindow.cpp
|
||||
llteleporthistory.cpp
|
||||
llteleporthistorystorage.cpp
|
||||
llterrainpaintmap.cpp
|
||||
lltexturecache.cpp
|
||||
lltexturectrl.cpp
|
||||
lltexturefetch.cpp
|
||||
|
|
@ -1235,6 +1236,7 @@ set(viewer_HEADER_FILES
|
|||
lltable.h
|
||||
llteleporthistory.h
|
||||
llteleporthistorystorage.h
|
||||
llterrainpaintmap.h
|
||||
lltexturecache.h
|
||||
lltexturectrl.h
|
||||
lltexturefetch.h
|
||||
|
|
|
|||
|
|
@ -14965,6 +14965,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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -1387,6 +1390,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)
|
||||
|
|
@ -2242,20 +2304,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 //
|
||||
///////////////////
|
||||
|
|
@ -9851,7 +9899,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");
|
||||
|
|
@ -9868,6 +9915,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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "llstl.h"
|
||||
#include "message.h"
|
||||
#include "lltimer.h"
|
||||
#include "v4coloru.h"
|
||||
|
||||
// viewer includes
|
||||
#include "llimagegl.h"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(U16 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(U16 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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue