Implement AO packed normal decode

This commit is contained in:
Xtarsia 2025-11-18 20:31:20 +00:00 committed by Cory Petkovsek
parent adb379b418
commit de3de15dd4
9 changed files with 71 additions and 24 deletions

View File

@ -45,6 +45,7 @@ uniform int _region_map[1024];
uniform vec2 _region_locations[1024];
uniform float _texture_normal_depth_array[32];
uniform float _texture_ao_strength_array[32];
uniform float _texture_ao_affect_array[32];
uniform float _texture_roughness_mod_array[32];
uniform float _texture_uv_scale_array[32];
uniform vec4 _texture_color_array[32];
@ -272,14 +273,15 @@ void fragment() {
vec4 normal_rough = vec4(0., 1., 0., 0.7);
vec4 albedo_height = vec4(1.);
float normal_map_depth = 1.;
float ao_strength = 0.;
float ao = 1.0;
float ao_affect = 0.;
if (enable_textures) {
// set to zero before accumulation
albedo_height = vec4(0.);
normal_rough = vec4(0.);
normal_map_depth = 0.;
ao_strength = 0.;
ao = 0.;
float total_weight = 0.;
float sharpness = fma(56., blend_sharpness, 8.);
@ -358,12 +360,15 @@ void fragment() {
nrm.a = clamp(nrm.a + _texture_roughness_mod_array[id], 0., 1.);
// Unpack normal map for blending.
nrm.xyz = fma(nrm.xzy, vec3(2.0), vec3(-1.0));
float id_ao = length(nrm.xyz) * 2.0 - 1.0;
id_ao = mix(id_ao * id_ao * _texture_ao_strength_array[id] + 1.0 - _texture_ao_strength_array[id], 1.0, alb.a * alb.a);
// height weight modifier.
float id_weight = exp2(sharpness * log2(id_w + alb.a * world_normal));
albedo_height += alb * id_weight;
normal_rough += nrm * id_weight;
normal_map_depth += _texture_normal_depth_array[id] * id_weight;
ao_strength += _texture_ao_strength_array[id] * id_weight;
ao_affect += _texture_ao_affect_array[id] * id_weight;
ao += id_ao * id_weight;
total_weight += id_weight;
}
}
@ -373,7 +378,8 @@ void fragment() {
albedo_height *= weight_inv;
normal_rough *= weight_inv;
normal_map_depth *= weight_inv;
ao_strength *= weight_inv;
ao_affect *= weight_inv;
ao *= weight_inv;
}
// Macro variation. 2 lookups
@ -397,9 +403,7 @@ void fragment() {
NORMAL_MAP = fma(normalize(normal_rough.xzy), vec3(0.5), vec3(0.5));
NORMAL_MAP_DEPTH = normal_map_depth;
// Higher and/or facing up, less occluded.
float ao = (1. - (albedo_height.a * log(2.1 - ao_strength))) * (1. - normal_rough.y);
AO = clamp(1. - ao * ao_strength, albedo_height.a, 1.0);
AO_LIGHT_AFFECT = (1.0 - albedo_height.a) * clamp(normal_rough.y, 0., 1.);
AO = clamp(ao, 0., 1.);
AO_LIGHT_AFFECT = ao_affect;
}

View File

@ -28,8 +28,12 @@ uniform float _region_texel_size = 0.0009765625; // = 1/1024
uniform int _region_map_size = 32;
uniform int _region_map[1024];
//uniform vec2 _region_locations[1024];
//uniform float _texture_normal_depth_array[32];
//uniform float _texture_ao_strength_array[32];
//uniform float _texture_ao_affect_array[32];
//uniform float _texture_roughness_mod_array[32];
//uniform float _texture_uv_scale_array[32];
//uniform float _texture_detile_array[32];
//uniform vec2 _texture_detile_array[32];
//uniform vec4 _texture_color_array[32];
uniform highp sampler2DArray _height_maps : repeat_disable;
uniform highp sampler2DArray _control_maps : repeat_disable;

View File

@ -16,6 +16,7 @@ group_uniforms;
float far_factor = clamp(smoothstep(dual_scale_near, dual_scale_far, length(v_vertex - _camera_pos)), 0.0, 1.0);
vec4 far_alb = vec4(0.);
vec4 far_nrm = vec4(0.);
float far_ao = 1.0;
if (far_factor > 0. && any(equal(texture_id, ivec2(dual_scale_texture)))) {
bool projected = TEXTURE_ID_PROJECTED(dual_scale_texture);
float far_scale = _texture_uv_scale_array[dual_scale_texture] * dual_scale_reduction;
@ -44,6 +45,9 @@ group_uniforms;
far_nrm.a = clamp(far_nrm.a + _texture_roughness_mod_array[dual_scale_texture], 0., 1.);
// Unpack and rotate normal map.
far_nrm.xyz = fma(far_nrm.xzy, vec3(2.0), vec3(-1.0));
far_ao = length(far_nrm.xyz) * 2.0 - 1.0;
far_ao = mix(far_ao * far_ao * _texture_ao_strength_array[dual_scale_texture] + 1.0 - _texture_ao_strength_array[dual_scale_texture], 1.0, far_alb.a * far_alb.a);
far_nrm.xyz = normalize(far_nrm.xyz);
far_nrm.xz = rotate_vec2(far_nrm.xz, far_cs_angle);
far_nrm.xz = fma((far_nrm.xz * p_align), vec2(float(projected)), far_nrm.xz * vec2(float(!projected)));
@ -55,7 +59,8 @@ group_uniforms;
mat.albedo_height = fma(far_alb, vec4(id_weight), mat.albedo_height);
mat.normal_rough = fma(far_nrm, vec4(id_weight), mat.normal_rough);
mat.normal_map_depth = fma(_texture_normal_depth_array[dual_scale_texture], id_weight, mat.normal_map_depth);
mat.ao_strength = fma(_texture_ao_strength_array[dual_scale_texture], id_weight, mat.ao_strength);
mat.ao = fma(far_ao, id_weight, mat.ao);
mat.ao_affect = fma(_texture_ao_affect_array[dual_scale_texture], id_weight, mat.ao_affect);
mat.total_weight += id_weight;
}
}
@ -69,6 +74,7 @@ group_uniforms;
if (id == dual_scale_texture && far_factor > 0.) {
alb = mix(alb, far_alb, far_factor);
nrm = mix(nrm, far_nrm, far_factor);
ao = mix(ao, far_ao, far_factor);
}
//INSERT: TRI_SCALING
// tri scaling

View File

@ -60,6 +60,7 @@ uniform int _region_map[1024];
uniform vec2 _region_locations[1024];
uniform float _texture_normal_depth_array[32];
uniform float _texture_ao_strength_array[32];
uniform float _texture_ao_affect_array[32];
uniform float _texture_roughness_mod_array[32];
uniform float _texture_uv_scale_array[32];
uniform uint _texture_vertical_projections;
@ -108,7 +109,8 @@ struct material {
vec4 albedo_height;
vec4 normal_rough;
float normal_map_depth;
float ao_strength;
float ao;
float ao_affect;
float total_weight;
};
@ -314,6 +316,9 @@ void accumulate_material(vec3 base_ddx, vec3 base_ddy, const float weight, const
nrm.a = clamp(nrm.a + _texture_roughness_mod_array[id], 0., 1.);
// Unpack and rotate normal map.
nrm.xyz = fma(nrm.xzy, vec3(2.0), vec3(-1.0));
float ao = length(nrm.xyz) * 2.0 - 1.0;
ao = mix(ao * ao * _texture_ao_strength_array[id] + 1.0 - _texture_ao_strength_array[id], 1.0, alb.a * alb.a);
nrm.xyz = normalize(nrm.xyz);
nrm.xz = rotate_vec2(nrm.xz, id_cs_angle);
nrm.xz = fma((nrm.xz * p_align), vec2(float(projected)), nrm.xz * vec2(float(!projected)));
@ -324,7 +329,8 @@ void accumulate_material(vec3 base_ddx, vec3 base_ddy, const float weight, const
mat.albedo_height = fma(alb, vec4(id_weight), mat.albedo_height);
mat.normal_rough = fma(nrm, vec4(id_weight), mat.normal_rough);
mat.normal_map_depth = fma(_texture_normal_depth_array[id], id_weight, mat.normal_map_depth);
mat.ao_strength = fma(_texture_ao_strength_array[id], id_weight, mat.ao_strength);
mat.ao = fma(ao, id_weight, mat.ao);
mat.ao_affect = fma(_texture_ao_affect_array[id], id_weight, mat.ao_affect);
mat.total_weight += id_weight;
}
@ -361,6 +367,9 @@ void accumulate_material(vec3 base_ddx, vec3 base_ddy, const float weight, const
nrm.a = clamp(nrm.a + _texture_roughness_mod_array[id], 0., 1.);
// Unpack and rotate normal map.
nrm.xyz = fma(nrm.xzy, vec3(2.0), vec3(-1.0));
float ao = length(nrm.xyz) * 2.0 - 1.0;
ao = mix(ao * ao * _texture_ao_strength_array[id] + 1.0 - _texture_ao_strength_array[id], 1.0, alb.a * alb.a);
nrm.xyz = normalize(nrm.xyz);
nrm.xz = rotate_vec2(nrm.xz, id_cs_angle);
nrm.xz = fma((nrm.xz * p_align), vec2(float(projected)), nrm.xz * vec2(float(!projected)));
@ -369,7 +378,8 @@ void accumulate_material(vec3 base_ddx, vec3 base_ddy, const float weight, const
mat.albedo_height = fma(alb, vec4(id_weight), mat.albedo_height);
mat.normal_rough = fma(nrm, vec4(id_weight), mat.normal_rough);
mat.normal_map_depth = fma(_texture_normal_depth_array[id], id_weight, mat.normal_map_depth);
mat.ao_strength = fma(_texture_ao_strength_array[id], id_weight, mat.ao_strength);
mat.ao = fma(ao, id_weight, mat.ao);
mat.ao_affect = fma(_texture_ao_affect_array[id], id_weight, mat.ao_affect);
mat.total_weight += id_weight;
}
}
@ -539,7 +549,7 @@ void fragment() {
#endif
// Struct to accumulate all texture data.
material mat = material(vec4(0.0), vec4(0.0), 0., 0., 0.);
material mat = material(vec4(0.0), vec4(0.0), 0., 0., 0., 0.);
// 2 - 4 lookups, 2 - 6 if dual scale texture
accumulate_material(base_ddx, base_ddy, weights[3], index[3], control[3], t_weights[3],
@ -560,7 +570,8 @@ void fragment() {
mat.albedo_height *= weight_inv;
mat.normal_rough *= weight_inv;
mat.normal_map_depth *= weight_inv;
mat.ao_strength *= weight_inv;
mat.ao *= weight_inv;
mat.ao_affect *= weight_inv;
// Macro variation. 2 lookups
vec3 macrov = vec3(1.);
@ -582,11 +593,8 @@ void fragment() {
// Repack final normal map value.
NORMAL_MAP = fma(normalize(mat.normal_rough.xzy), vec3(0.5), vec3(0.5));
NORMAL_MAP_DEPTH = mat.normal_map_depth;
// Higher and/or facing up, less occluded.
float ao = (1. - (mat.albedo_height.a * log(2.1 - mat.ao_strength))) * (1. - mat.normal_rough.y);
AO = clamp(1. - ao * mat.ao_strength, mat.albedo_height.a, 1.0);
AO_LIGHT_AFFECT = (1.0 - mat.albedo_height.a) * clamp(mat.normal_rough.y, 0., 1.);
AO = clamp(mat.ao, 0., 1.);
AO_LIGHT_AFFECT = mat.ao_affect;
}

View File

@ -346,10 +346,11 @@ void Terrain3DAssets::_update_texture_files() {
void Terrain3DAssets::_update_texture_settings() {
LOG(DEBUG, "Received setting_changed signal");
if (!_texture_list.is_empty()) {
LOG(INFO, "Updating terrain color and scale arrays");
LOG(INFO, "Updating texture asset settings arrays");
_texture_colors.clear();
_texture_normal_depths.clear();
_texture_ao_strengths.clear();
_texture_ao_light_affects.clear();
_texture_roughness_mods.clear();
_texture_uv_scales.clear();
_texture_vertical_projections = 0u;
@ -366,6 +367,7 @@ void Terrain3DAssets::_update_texture_settings() {
}
_texture_normal_depths.push_back(ta->get_normal_depth());
_texture_ao_strengths.push_back(ta->get_ao_strength());
_texture_ao_light_affects.push_back(ta->get_ao_light_affect());
_texture_roughness_mods.push_back(ta->get_roughness());
_texture_uv_scales.push_back(ta->get_uv_scale());
_texture_vertical_projections |= (ta->get_vertical_projection() ? (uint32_t(1u) << uint32_t(ta->get_id())) : uint32_t(0u));
@ -459,6 +461,7 @@ void Terrain3DAssets::destroy() {
_texture_colors.clear();
_texture_normal_depths.clear();
_texture_ao_strengths.clear();
_texture_ao_light_affects.clear();
_texture_roughness_mods.clear();
_texture_uv_scales.clear();
_texture_detiles.clear();
@ -729,6 +732,7 @@ void Terrain3DAssets::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture_colors"), &Terrain3DAssets::get_texture_colors);
ClassDB::bind_method(D_METHOD("get_texture_normal_depths"), &Terrain3DAssets::get_texture_normal_depths);
ClassDB::bind_method(D_METHOD("get_texture_ao_strengths"), &Terrain3DAssets::get_texture_ao_strengths);
ClassDB::bind_method(D_METHOD("get_texture_ao_light_affects"), &Terrain3DAssets::get_texture_ao_light_affects);
ClassDB::bind_method(D_METHOD("get_texture_roughness_mods"), &Terrain3DAssets::get_texture_roughness_mods);
ClassDB::bind_method(D_METHOD("get_texture_uv_scales"), &Terrain3DAssets::get_texture_uv_scales);
ClassDB::bind_method(D_METHOD("get_texture_vertical_projections"), &Terrain3DAssets::get_texture_vertical_projections);

View File

@ -36,6 +36,7 @@ private:
PackedColorArray _texture_colors;
PackedFloat32Array _texture_normal_depths;
PackedFloat32Array _texture_ao_strengths;
PackedFloat32Array _texture_ao_light_affects;
PackedFloat32Array _texture_roughness_mods;
PackedFloat32Array _texture_uv_scales;
uint32_t _texture_vertical_projections;
@ -79,6 +80,7 @@ public:
PackedColorArray get_texture_colors() const { return _texture_colors; }
PackedFloat32Array get_texture_normal_depths() const { return _texture_normal_depths; }
PackedFloat32Array get_texture_ao_strengths() const { return _texture_ao_strengths; }
PackedFloat32Array get_texture_ao_light_affects() const { return _texture_ao_light_affects; }
PackedFloat32Array get_texture_roughness_mods() const { return _texture_roughness_mods; }
PackedFloat32Array get_texture_uv_scales() const { return _texture_uv_scales; }
uint32_t get_texture_vertical_projections() const { return _texture_vertical_projections; }

View File

@ -546,6 +546,7 @@ void Terrain3DMaterial::_update_texture_arrays() {
RS->material_set_param(_material, "_texture_color_array", asset_list->get_texture_colors());
RS->material_set_param(_material, "_texture_normal_depth_array", asset_list->get_texture_normal_depths());
RS->material_set_param(_material, "_texture_ao_strength_array", asset_list->get_texture_ao_strengths());
RS->material_set_param(_material, "_texture_ao_affect_array", asset_list->get_texture_ao_light_affects());
RS->material_set_param(_material, "_texture_roughness_mod_array", asset_list->get_texture_roughness_mods());
RS->material_set_param(_material, "_texture_uv_scale_array", asset_list->get_texture_uv_scales());
RS->material_set_param(_material, "_texture_vertical_projections", asset_list->get_texture_vertical_projections());

View File

@ -49,6 +49,10 @@ void Terrain3DTextureAsset::clear() {
_albedo_texture.unref();
_normal_texture.unref();
_thumbnail.unref();
_normal_depth = 1.0f;
_ao_strength = 0.5f;
_ao_light_affect = 0.0f;
_roughness = 0.f;
_uv_scale = 0.1f;
_vertical_projection = false;
_detiling_rotation = 0.0f;
@ -161,12 +165,19 @@ void Terrain3DTextureAsset::set_roughness(const real_t p_roughness) {
}
void Terrain3DTextureAsset::set_ao_strength(const real_t p_ao_strength) {
SET_IF_DIFF(_ao_strength, CLAMP(p_ao_strength, 0.0f, 2.0f));
SET_IF_DIFF(_ao_strength, CLAMP(p_ao_strength, 0.0f, 1.0f));
LOG(INFO, "Setting ao_strength: ", _ao_strength);
LOG(DEBUG, "Emitting setting_changed");
emit_signal("setting_changed");
}
void Terrain3DTextureAsset::set_ao_light_affect(const real_t p_ao_light_affect) {
SET_IF_DIFF(_ao_light_affect, CLAMP(p_ao_light_affect, 0.0f, 1.0f));
LOG(INFO, "Setting ao_light_affect: ", _ao_light_affect);
LOG(DEBUG, "Emitting setting_changed");
emit_signal("setting_changed");
}
void Terrain3DTextureAsset::set_uv_scale(const real_t p_scale) {
SET_IF_DIFF(_uv_scale, CLAMP(p_scale, 0.001f, 100.0f));
LOG(INFO, "Setting uv_scale: ", _uv_scale);
@ -223,6 +234,8 @@ void Terrain3DTextureAsset::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_normal_depth"), &Terrain3DTextureAsset::get_normal_depth);
ClassDB::bind_method(D_METHOD("set_ao_strength", "ao_strength"), &Terrain3DTextureAsset::set_ao_strength);
ClassDB::bind_method(D_METHOD("get_ao_strength"), &Terrain3DTextureAsset::get_ao_strength);
ClassDB::bind_method(D_METHOD("set_ao_light_affect", "ao_light_affect"), &Terrain3DTextureAsset::set_ao_light_affect);
ClassDB::bind_method(D_METHOD("get_ao_light_affect"), &Terrain3DTextureAsset::get_ao_light_affect);
ClassDB::bind_method(D_METHOD("set_roughness", "roughness"), &Terrain3DTextureAsset::set_roughness);
ClassDB::bind_method(D_METHOD("get_roughness"), &Terrain3DTextureAsset::get_roughness);
ClassDB::bind_method(D_METHOD("set_uv_scale", "scale"), &Terrain3DTextureAsset::set_uv_scale);
@ -240,7 +253,8 @@ void Terrain3DTextureAsset::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "albedo_texture", PROPERTY_HINT_RESOURCE_TYPE, "ImageTexture,CompressedTexture2D"), "set_albedo_texture", "get_albedo_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "ImageTexture,CompressedTexture2D"), "set_normal_texture", "get_normal_texture");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_depth", PROPERTY_HINT_RANGE, "0.0, 2.0"), "set_normal_depth", "get_normal_depth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao_strength", PROPERTY_HINT_RANGE, "0.0, 2.0"), "set_ao_strength", "get_ao_strength");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao_strength", PROPERTY_HINT_RANGE, "0.0, 1.0"), "set_ao_strength", "get_ao_strength");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao_light_affect", PROPERTY_HINT_RANGE, "0.0, 1.0"), "set_ao_light_affect", "get_ao_light_affect");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "roughness", PROPERTY_HINT_RANGE, "-1.0, 1.0"), "set_roughness", "get_roughness");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv_scale", PROPERTY_HINT_RANGE, "0.001, 2.0, or_greater"), "set_uv_scale", "get_uv_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical_projection", PROPERTY_HINT_NONE), "set_vertical_projection", "get_vertical_projection");

View File

@ -17,8 +17,9 @@ class Terrain3DTextureAsset : public Terrain3DAssetResource {
Color _albedo_color = Color(1.f, 1.f, 1.f, 1.f);
Ref<Texture2D> _albedo_texture;
Ref<Texture2D> _normal_texture;
real_t _normal_depth = 0.5f;
real_t _normal_depth = 1.0f;
real_t _ao_strength = 0.5f;
real_t _ao_light_affect = 0.0f;
real_t _roughness = 0.f;
real_t _uv_scale = 0.1f;
bool _vertical_projection = false;
@ -63,6 +64,9 @@ public:
void set_ao_strength(const real_t p_ao_strength);
real_t get_ao_strength() const { return _ao_strength; }
void set_ao_light_affect(const real_t p_ao_light_affect);
real_t get_ao_light_affect() const { return _ao_light_affect; }
void set_roughness(const real_t p_roughness);
real_t get_roughness() const { return _roughness; }