523 lines
16 KiB
GLSL
523 lines
16 KiB
GLSL
/**
|
|
* @file class1\deferred\pbrterrainUtilF.glsl
|
|
*
|
|
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2023, 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]*/
|
|
|
|
/**
|
|
* Triplanar mapping implementation adapted from Inigo Quilez' example shader,
|
|
* MIT license.
|
|
* https://www.shadertoy.com/view/MtsGWH
|
|
* Copyright © 2015 Inigo Quilez
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions: The above copyright
|
|
* notice and this permission notice shall be included in all copies or
|
|
* substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS",
|
|
* WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#define TERRAIN_PBR_DETAIL_EMISSIVE 0
|
|
#define TERRAIN_PBR_DETAIL_OCCLUSION -1
|
|
#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);
|
|
|
|
// A relatively agressive threshold for terrain material mixing sampling
|
|
// cutoff. This ensures that only one or two materials are used in most places,
|
|
// making PBR terrain blending more performant. Should be greater than 0 to work.
|
|
#define TERRAIN_RAMP_MIX_THRESHOLD 0.1
|
|
// A small threshold for triplanar mapping sampling cutoff. This and
|
|
// TERRAIN_TRIPLANAR_BLEND_FACTOR together ensures that only one or two samples
|
|
// per texture are used in most places, making triplanar mapping more
|
|
// performant. Should be greater than 0 to work.
|
|
// There's also an artistic design choice in the use of these factors, and the
|
|
// use of triplanar generally. Don't take these triplanar constants for granted.
|
|
#define TERRAIN_TRIPLANAR_MIX_THRESHOLD 0.01
|
|
|
|
#define SAMPLE_X 1 << 0
|
|
#define SAMPLE_Y 1 << 1
|
|
#define SAMPLE_Z 1 << 2
|
|
#define MIX_X 1 << 3
|
|
#define MIX_Y 1 << 4
|
|
#define MIX_Z 1 << 5
|
|
#define MIX_W 1 << 6
|
|
|
|
struct PBRMix
|
|
{
|
|
vec4 col; // RGB color with alpha, linear space
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
|
vec3 orm; // Occlusion, roughness, metallic
|
|
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
vec2 rm; // Roughness, metallic
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
vec3 vNt; // Unpacked normal texture sample, vector
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
vec3 emissive; // RGB emissive color, linear space
|
|
#endif
|
|
};
|
|
|
|
PBRMix init_pbr_mix()
|
|
{
|
|
PBRMix mix;
|
|
mix.col = vec4(0);
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
|
mix.orm = vec3(0);
|
|
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
mix.rm = vec2(0);
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
mix.vNt = vec3(0);
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
mix.emissive = vec3(0);
|
|
#endif
|
|
return mix;
|
|
}
|
|
|
|
// Usage example, for two weights:
|
|
// vec2 weights = ... // Weights must add up to 1
|
|
// PBRMix mix = init_pbr_mix();
|
|
// PBRMix mix1 = ...
|
|
// mix = mix_pbr(mix, mix1, weights.x);
|
|
// PBRMix mix2 = ...
|
|
// mix = mix_pbr(mix, mix2, weights.y);
|
|
PBRMix mix_pbr(PBRMix mix1, PBRMix mix2, float mix2_weight)
|
|
{
|
|
PBRMix mix;
|
|
mix.col = mix1.col + (mix2.col * mix2_weight);
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
|
mix.orm = mix1.orm + (mix2.orm * mix2_weight);
|
|
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
mix.rm = mix1.rm + (mix2.rm * mix2_weight);
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
mix.vNt = mix1.vNt + (mix2.vNt * mix2_weight);
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
mix.emissive = mix1.emissive + (mix2.emissive * mix2_weight);
|
|
#endif
|
|
return mix;
|
|
}
|
|
|
|
PBRMix sample_pbr(
|
|
vec2 uv
|
|
, sampler2D tex_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, sampler2D tex_orm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
, sampler2D tex_vNt
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, sampler2D tex_emissive
|
|
#endif
|
|
)
|
|
{
|
|
PBRMix mix;
|
|
mix.col = texture(tex_col, uv);
|
|
mix.col.rgb = srgb_to_linear(mix.col.rgb);
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
|
mix.orm = texture(tex_orm, uv).xyz;
|
|
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
mix.rm = texture(tex_orm, uv).yz;
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
mix.vNt = texture(tex_vNt, uv).xyz*2.0-1.0;
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
mix.emissive = srgb_to_linear(texture(tex_emissive, uv).xyz);
|
|
#endif
|
|
return mix;
|
|
}
|
|
|
|
struct TerrainTriplanar
|
|
{
|
|
vec3 weight;
|
|
int type;
|
|
};
|
|
|
|
struct TerrainMix
|
|
{
|
|
vec4 weight;
|
|
int type;
|
|
};
|
|
|
|
#define TerrainMixSample vec4[4]
|
|
#define TerrainMixSample3 vec3[4]
|
|
|
|
TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal)
|
|
{
|
|
TerrainMix tm;
|
|
vec4 sample_x = vec4(1,0,0,0);
|
|
vec4 sample_y = vec4(0,1,0,0);
|
|
vec4 sample_z = vec4(0,0,1,0);
|
|
vec4 sample_w = vec4(0,0,0,1);
|
|
|
|
tm.weight = mix( mix(sample_w, sample_z, alpha2), mix(sample_y, sample_x, alpha1), alphaFinal );
|
|
tm.weight -= TERRAIN_RAMP_MIX_THRESHOLD;
|
|
ivec4 usage = max(ivec4(0), ivec4(ceil(tm.weight)));
|
|
// Prevent negative weights and keep weights balanced
|
|
tm.weight = tm.weight*vec4(usage);
|
|
tm.weight /= (tm.weight.x + tm.weight.y + tm.weight.z + tm.weight.w);
|
|
|
|
tm.type = (usage.x * MIX_X) |
|
|
(usage.y * MIX_Y) |
|
|
(usage.z * MIX_Z) |
|
|
(usage.w * MIX_W);
|
|
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;
|
|
float threshold = TERRAIN_TRIPLANAR_MIX_THRESHOLD;
|
|
vec3 weight_signed = pow(abs(vary_vertex_normal), vec3(sharpness));
|
|
weight_signed /= (weight_signed.x + weight_signed.y + weight_signed.z);
|
|
weight_signed -= vec3(threshold);
|
|
TerrainTriplanar tw;
|
|
// *NOTE: Make sure the threshold doesn't affect the materials
|
|
tw.weight = max(vec3(0), weight_signed);
|
|
tw.weight /= (tw.weight.x + tw.weight.y + tw.weight.z);
|
|
ivec3 usage = ivec3(round(max(vec3(0), sign(weight_signed))));
|
|
tw.type = ((usage.x) * SAMPLE_X) |
|
|
((usage.y) * SAMPLE_Y) |
|
|
((usage.z) * SAMPLE_Z);
|
|
return tw;
|
|
}
|
|
#endif
|
|
|
|
|
|
// Assume weights add to 1
|
|
float terrain_mix(TerrainMix tm, vec4 tms4)
|
|
{
|
|
return (tm.weight.x * tms4[0]) +
|
|
(tm.weight.y * tms4[1]) +
|
|
(tm.weight.z * tms4[2]) +
|
|
(tm.weight.w * tms4[3]);
|
|
}
|
|
|
|
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
|
// Triplanar mapping
|
|
|
|
// Pre-transformed texture coordinates for each axial uv slice (Packing: xy, yz, (-x)z, unused)
|
|
#define TerrainCoord vec4[3]
|
|
|
|
// If sign_or_zero is positive, use uv_unflippped, otherwise use uv_flipped
|
|
vec2 _t_uv(vec2 uv_unflipped, vec2 uv_flipped, float sign_or_zero)
|
|
{
|
|
return mix(uv_flipped, uv_unflipped, max(0.0, sign_or_zero));
|
|
}
|
|
|
|
vec3 _t_normal_post_1(vec3 vNt0, float sign_or_zero)
|
|
{
|
|
// Assume normal is unpacked
|
|
vec3 vNt1 = vNt0;
|
|
// Get sign
|
|
float sign = sign_or_zero;
|
|
// Handle case where sign is 0
|
|
sign = (2.0*sign) + 1.0;
|
|
sign /= abs(sign);
|
|
// If the sign is negative, rotate normal by 180 degrees
|
|
vNt1.xy = (min(0, sign) * vNt1.xy) + (min(0, -sign) * -vNt1.xy);
|
|
return vNt1;
|
|
}
|
|
|
|
// Triplanar-specific normal texture fixes
|
|
vec3 _t_normal_post_x(vec3 vNt0, float tangent_sign)
|
|
{
|
|
vec3 vNt_x = _t_normal_post_1(vNt0, sign(vary_vertex_normal.x));
|
|
// *HACK: Transform normals according to orientation of the UVs
|
|
vNt_x.xy = vec2(-vNt_x.y, vNt_x.x);
|
|
vNt_x.xy *= tangent_sign;
|
|
return vNt_x;
|
|
}
|
|
vec3 _t_normal_post_y(vec3 vNt0)
|
|
{
|
|
vec3 vNt_y = _t_normal_post_1(vNt0, sign(vary_vertex_normal.y));
|
|
// *HACK: Transform normals according to orientation of the UVs
|
|
vNt_y.xy = -vNt_y.xy;
|
|
return vNt_y;
|
|
}
|
|
vec3 _t_normal_post_z(vec3 vNt0)
|
|
{
|
|
vec3 vNt_z = _t_normal_post_1(vNt0, sign(vary_vertex_normal.z));
|
|
return vNt_z;
|
|
}
|
|
|
|
PBRMix terrain_sample_pbr(
|
|
TerrainCoord terrain_coord
|
|
, TerrainTriplanar tw
|
|
, sampler2D tex_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, sampler2D tex_orm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
, sampler2D tex_vNt
|
|
, float tangent_sign
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, sampler2D tex_emissive
|
|
#endif
|
|
)
|
|
{
|
|
PBRMix mix = init_pbr_mix();
|
|
|
|
#define get_uv_x() _t_uv(terrain_coord[0].zw, terrain_coord[1].zw, sign(vary_vertex_normal.x))
|
|
#define get_uv_y() _t_uv(terrain_coord[1].xy, terrain_coord[2].xy, sign(vary_vertex_normal.y))
|
|
#define get_uv_z() _t_uv(terrain_coord[0].xy, vec2(0), sign(vary_vertex_normal.z))
|
|
switch (tw.type & SAMPLE_X)
|
|
{
|
|
case SAMPLE_X:
|
|
PBRMix mix_x = sample_pbr(
|
|
get_uv_x()
|
|
, tex_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, tex_orm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
, tex_vNt
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, tex_emissive
|
|
#endif
|
|
);
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
// Triplanar-specific normal texture fix
|
|
mix_x.vNt = _t_normal_post_x(mix_x.vNt, tangent_sign);
|
|
#endif
|
|
mix = mix_pbr(mix, mix_x, tw.weight.x);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (tw.type & SAMPLE_Y)
|
|
{
|
|
case SAMPLE_Y:
|
|
PBRMix mix_y = sample_pbr(
|
|
get_uv_y()
|
|
, tex_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, tex_orm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
, tex_vNt
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, tex_emissive
|
|
#endif
|
|
);
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
// Triplanar-specific normal texture fix
|
|
mix_y.vNt = _t_normal_post_y(mix_y.vNt);
|
|
#endif
|
|
mix = mix_pbr(mix, mix_y, tw.weight.y);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (tw.type & SAMPLE_Z)
|
|
{
|
|
case SAMPLE_Z:
|
|
PBRMix mix_z = sample_pbr(
|
|
get_uv_z()
|
|
, tex_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, tex_orm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
, tex_vNt
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, tex_emissive
|
|
#endif
|
|
);
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
// Triplanar-specific normal texture fix
|
|
// *NOTE: Bottom face has not been tested
|
|
mix_z.vNt = _t_normal_post_z(mix_z.vNt);
|
|
#endif
|
|
mix = mix_pbr(mix, mix_z, tw.weight.z);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return mix;
|
|
}
|
|
|
|
#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1
|
|
|
|
#define TerrainCoord vec2
|
|
|
|
#define terrain_sample_pbr sample_pbr
|
|
|
|
#endif
|
|
|
|
PBRMix multiply_factors_pbr(
|
|
PBRMix mix_in
|
|
, vec4 factor_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
|
, vec3 factor_orm
|
|
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, vec2 factor_rm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, vec3 factor_emissive
|
|
#endif
|
|
)
|
|
{
|
|
PBRMix mix = mix_in;
|
|
mix.col *= factor_col;
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
|
mix.orm *= factor_orm;
|
|
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
mix.rm *= factor_rm;
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
mix.emissive *= factor_emissive;
|
|
#endif
|
|
return mix;
|
|
}
|
|
|
|
PBRMix terrain_sample_and_multiply_pbr(
|
|
TerrainCoord terrain_coord
|
|
, sampler2D tex_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, sampler2D tex_orm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
, sampler2D tex_vNt
|
|
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
|
, float tangent_sign
|
|
#endif
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, sampler2D tex_emissive
|
|
#endif
|
|
, vec4 factor_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
|
, vec3 factor_orm
|
|
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, vec2 factor_rm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, vec3 factor_emissive
|
|
#endif
|
|
)
|
|
{
|
|
PBRMix mix = terrain_sample_pbr(
|
|
terrain_coord
|
|
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
|
, _t_triplanar()
|
|
#endif
|
|
, tex_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, tex_orm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
|
, tex_vNt
|
|
#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3
|
|
, tangent_sign
|
|
#endif
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, tex_emissive
|
|
#endif
|
|
);
|
|
|
|
mix = multiply_factors_pbr(mix
|
|
, factor_col
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
|
, factor_orm
|
|
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
|
, factor_rm
|
|
#endif
|
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
|
, factor_emissive
|
|
#endif
|
|
);
|
|
|
|
return mix;
|
|
}
|