add triplanar normal overlay?
- Edited
i got it working yay! there was a problem with my triplanar calculation in the shader.
works fine now, i didnt had to set normal to disabled
shader_type spatial;
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx;
uniform sampler2D texture_albedo : source_color,filter_linear_mipmap,repeat_enable;
uniform sampler2D texture_roughness : hint_roughness_gray,filter_linear_mipmap,repeat_enable;
uniform sampler2D texture_normal : hint_roughness_normal,filter_linear_mipmap,repeat_enable;
uniform float roughness = 1.0;
uniform sampler2D detail_normal : hint_roughness_normal,filter_linear_mipmap,repeat_enable;
uniform sampler2D detail_overlay : source_color,filter_linear_mipmap,repeat_enable;
uniform vec3 detail_scale = vec3(1.0);
uniform float normal_scale = 1.0;
varying vec3 triplanar_pos;
varying vec3 power_normal;
void vertex() {
TANGENT = vec3(0.0,0.0,-1.0) * abs(NORMAL.x);
TANGENT += vec3(1.0,0.0,0.0) * abs(NORMAL.y);
TANGENT += vec3(1.0,0.0,0.0) * abs(NORMAL.z);
TANGENT = normalize(TANGENT);
BINORMAL = vec3(0.0,1.0,0.0) * abs(NORMAL.x);
BINORMAL += vec3(0.0,0.0,-1.0) * abs(NORMAL.y);
BINORMAL += vec3(0.0,1.0,0.0) * abs(NORMAL.z);
BINORMAL = normalize(BINORMAL);
power_normal = pow(abs(NORMAL),vec3(1.0));
triplanar_pos = VERTEX;
power_normal /= dot(power_normal,vec3(1.0));
triplanar_pos *= vec3(1.0,-1.0, 1.0);
}
vec3 triplanar_texture(sampler2D p_sampler, vec3 p_triplanar_pos) {
vec3 samp = vec3(0.0);
samp += texture(p_sampler,p_triplanar_pos.xy).xyz * power_normal.z;
samp += texture(p_sampler,p_triplanar_pos.xz).xyz * power_normal.y;
samp += texture(p_sampler,p_triplanar_pos.zy * vec2(-1.0,1.0)).xyz * power_normal.x;
return samp;
}
//Overlay
vec3 overlay (vec3 target, vec3 blend){
vec3 temp;
temp.x = (target.x > 0.5) ? (1.0-(1.0-2.0*(target.x-0.5))*(1.0-blend.x)) : (2.0*target.x)*blend.x;
temp.y = (target.y > 0.5) ? (1.0-(1.0-2.0*(target.y-0.5))*(1.0-blend.y)) : (2.0*target.y)*blend.y;
temp.z = (target.z > 0.5) ? (1.0-(1.0-2.0*(target.z-0.5))*(1.0-blend.z)) : (2.0*target.z)*blend.z;
return temp;
}
// Linear Blending
vec3 NormalBlend_Linear(vec3 n1, vec3 n2)
{
// Unpack
n1 = n1*2.0 - 1.0;
n2 = n2*2.0 - 1.0;
return normalize(n1 + n2);
}
vec3 CombineNormal(vec3 n1, vec3 n2)
{
return NormalBlend_Linear(n1, n2);
}
void fragment() {
vec2 base_uv = UV;
vec4 albedo_tex = texture(texture_albedo,base_uv);
vec3 overlayertex = triplanar_texture(detail_overlay,triplanar_pos * detail_scale/100.0);
ALBEDO = overlay(albedo_tex.rgb,overlayertex.rgb);
METALLIC = 0.0;
vec4 roughness_texture_channel = vec4(0.333333,0.333333,0.333333,0.0);
float roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel);
ROUGHNESS = roughness_tex * roughness;
SPECULAR = 0.5;
vec3 detail_norm_tex = triplanar_texture(detail_normal,triplanar_pos * detail_scale/100.0);
detail_norm_tex *= 2.0;
NORMAL_MAP = CombineNormal(texture(texture_normal,base_uv).rgb,detail_norm_tex.rgb );
NORMAL_MAP_DEPTH = normal_scale;
}
- Edited
DJMaesen i didnt had to set normal to disabled
You still want to do it though to make blending work properly and final result appear more crisp, especially if you use a better blending function than simple linear blend you initially had (the one I posted last). You also want to use a better blending function to blend triplanar normals. Using plain linear blend will again result in weakened texture appearance in areas where projections overlap. Do some test on gray spheres with only normal textures so you can better see what's happening.
Note that "Normal map" option is in "Compression" section. So you're not disabling normal maps, you're disabling their RG compression. If compression is enabled then Godot will eliminate blue channel from the map immediately on import. When a shader reads/decodes such normal maps for blending, the z component will likely be the same for all normals, making the vectors mangled, specifically the normals will not have unit length and will point off the intended direction. It may look passable for some maps but you'll not be working with correct normals.
The whole thing can still be made to work correctly even with RG compressed normals but in that case you'll need to calculate normal's Z component when decoding it from a texture, prior to blending.
Bottom line, do some tests with gray spheres, compare compressed vs. uncompressed textures and try several blending functions and detail maps.
You'll likely reuse this code in the future, possibly on less organic textures that are not as forgiving towards errors as rock textures, so do it properly to avoid future shader woes.
- Edited
DJMaesen Blending method and the z component are two separate problems. So if you haven't tried it with uncompressed normal maps you have no actual quality reference as all your blending function tests were done with a missing z component. You want to provide the proper normal vector for the shader, the one that's actually encoded in the original normal map, only then can you test and compare the nuances of various blending methods.
Do as you wish. If it's good enough - fine. just have in mind that your current shader coupled with compressed normal maps is not performing correct calculations.
xyz yes they are not corect calculations. i have tried with uncompressed normals but no good results.
ive tried your blending technique and normals are worse than the simple linear blending.
i appreciate your help
but im a noob at shader coding u see.
all i want is a shader that can add detail color and detail normal maps in a triplanar way, so big objects dont look so pixelated when upclose.
thats what im trying to achieve
- Edited
DJMaesen i have tried with uncompressed normals but no good results
Not sure what you mean by "no good results". The results should be the same at worst. Your triplanar blending code may be messing things up. I haven't checked it. That's why I suggested to first try detail blending without triplanar.
RG compressed normal maps, linear blend:
Without compression, UDN blend:
- Edited
also why would an engine discard the blue channel on import?
- Edited
DJMaesen also why would an engine discard the blue channel on import?
From the docs:
When using a texture as normal map, only the red and green channels are required. Given regular texture compression algorithms produce artifacts that don't look that nice in normal maps, the RGTC compression format is the best fit for this data. Forcing this option to Enable will make Godot import the image as RGTC compressed. By default, it's set to Detect. This means that if the texture is ever detected to be used as a normal map, it will be changed to Enable and reimported automatically.
And especially relevant for the discussion here:
Note that RGTC compression affects the resulting normal map image. You will have to adjust custom shaders that use the normal map's blue channel to take this into account. Built-in material shaders already ignore the blue channel in a normal map (regardless of the actual normal map's contents).
Why the blue channel can be discarded from normal maps? Because we operate under constraint that normals are always normalized, i.e. the normal vectors have length of exactly 1.0. This means that for each normal vector the following is true:
x*x + y*y + z*z = 1.0
From this follows that if we know x and y components of a normal vector, we can easily calculate the z component:
z = 1.0 - sqrt(x*x + y*y)
The whole thing is done to save texture storage at the cost of some additional computation.
In addition to dropping a channel, RG textures are additionally compressed using an algorithm that doesn't compromise the pixel data in the way the regular vram compression does.
- Edited
for the love of god can someone post a working shader?
this is taking too much time allready
DJMaesen the code comments says something along the lines of "normal B channel can not be trusted".
Normal maps generated from textures have the blue channel as pure white, while only baked normals have correct vectors.