Open jasperbrooks79 opened 4 years ago
There's the Image.bumpmap_to_normalmap()
method for this. While it could be exposed as an import option, keep in mind it can take a while to generate on large textures and doesn't offer the best visual results.
I don't think there's much point integrating this in core, but it can be implemented in a third-party plugin.
Edit: See also my comment here: https://github.com/godotengine/godot-proposals/issues/2989#issuecomment-881075236
Bumpmaps would be far easier to modify in shaders tho. Since you can sample them with modified uvs or just rotate them easily.
With normals it's not that easy because you have to apply them to your model as is. Else you'll get odd lighting behaviour.
Bumpmaps would be far easier to modify in shaders tho. Since you can sample them with modified uvs or just rotate them easily.
With normals it's not that easy because you have to apply them to your model as is. Else you'll get odd lighting behaviour.
It should be possible to write a shader that converts an height map to a normal map: https://forum.unity.com/threads/solved-height-to-nomal-in-shader.713894/ This link is about Unity, but the same principle should be applicable to Godot.
See also https://stackoverflow.com/questions/26045527/normal-map-from-height-map.
+1 on the request for a bump-to-normal shader node. Blender has one and I use it all the time in procedural materials
+1 on the request for a bump-to-normal shader node.
This should be already feasible with a custom shader (on GLES3 at least), but for the reasons mentioned above, I don't think it makes sense to provide as a built-in visual shader node.
A visual shader node that calculates the normal map seems like a good idea.
// heightmap_location = the XZ coordinates of the terrain, in meters.
// The terrain is texture modulated by `heightmap`
vec3 get_normal_from_heightmap_simple(vec2 heightmap_location) {
// The width of the terrain, in meters
float terrain_scale = terrain_dimensions.x;
// The texelSize, referring to the resolution of the heightmap.
float delta = 1.0 / heightmap_dimensions.x;
float top = texture(heightmap, heightmap_location + vec2(0, -delta)).x;
float bottom = texture(heightmap, heightmap_location + vec2(0, delta)).x;
float left = texture(heightmap, heightmap_location + vec2(-delta, 0)).x;
float right = texture(heightmap, heightmap_location + vec2(delta, 0)).x;
// heightmap_scale = The number of meters difference in height between heightmap=0 and heightmap=1
return normalize(vec3(-(right-left), 2.0*delta*terrain_scale/heightmap_scale, (top-bottom)));
}
vec3 get_normal_from_heightmap(vec2 heightmap_location) {
float terrain_scale = terrain_dimensions.x;
float delta = 1.0 / heightmap_dimensions.x;
// 3x3 Edge-Detection Filter
// [6][7][8]
// [3][4][5]
// [0][1][2]
float s6 = texture(heightmap, heightmap_location + vec2(-delta, -delta)).x;
float s7 = texture(heightmap, heightmap_location + vec2(0, -delta)).x;
float s8 = texture(heightmap, heightmap_location + vec2(delta, -delta)).x;
float s3 = texture(heightmap, heightmap_location + vec2(-delta, 0)).x;
// float s4 = texture(heightmap, heightmap_location + vec2(0, 0)).x;
float s5 = texture(heightmap, heightmap_location + vec2(delta, 0)).x;
float s0 = texture(heightmap, heightmap_location + vec2(-delta, delta)).x;
float s1 = texture(heightmap, heightmap_location + vec2(0, delta)).x;
float s2 = texture(heightmap, heightmap_location + vec2(delta, delta)).x;
// Scharr Filter
vec3 n;
n.x = -((s2-s0)+(10.0/3.0)*(s5-s3)+(s8-s6));
n.y = delta*terrain_scale/heightmap_scale*(32.0/3.0);
n.z = ((s6-s0)+(10.0/3.0)*(s7-s1)+(s8-s2));
return normalize(n);
}
Performance Benchmarks ~ 2017 Laptop: GTX 1060 Mobile
NORMAL = vec3(0, 1, 0); // 1.67ms
NORMAL = (VIEW_MATRIX * vec4(get_normal_from_heightmap_simple(v_terrain_uv), 0.0)).xyz; // 1.79ms
NORMAL = (VIEW_MATRIX * vec4(get_normal_from_heightmap(v_terrain_uv), 0.0)).xyz; // 1.87ms
And using vertex->fragment shader interpolation,
Vertex Shader:
v_vertex_coords = world_position.xz;
v_normal = get_normal_from_heightmap(v_terrain_uv);
Fragment Shader:
NORMAL = (VIEW_MATRIX * vec4(v_normal, 0.0)).xyz; // 1.69ms
I have no issue writing shader code, I have no interest in visual shaders. But, it would make sense to include a visual shader node that makes workflow between Blender shader nodes and Godot easy. The performance impact is fairly minimal, and it's required in any situation where you can't bake (Procedural/dynamic/periodically updated heightmaps). For context, enabling shadowmaps on my DirectionalLight3D with default settings gives me a render time of 2.35ms
. For now, I hope the above code helps anyone who stumbles upon this Github issue.
Describe the project you are working on: A Tomb Raider type game . .
Describe the problem or limitation you are having in your project: I can very easily make some really nice bump maps, by painting grey-scale tones, on a surface, or material, in Blender, and it makes some super-nice, near pro-normal map quality results, it's fast, and just works . . The problem is, Godot doesn't support this texture format, ie. it has to be converted into a normal map, which takes some times, to bake, in Blender, or external programs . . Could it be possible to add support for classic bump maps, in Godot, since the work-flow is really nice, one can paint almost any normal, at least many, with simple bump maps . . Or, there could be a simple converter, if one loads a bump map, into the normal map slot, there could be a button, ' convert bump to normal ', in Godot, it seems to be a fairly simple process, in gIMP, and it would make Godot nicer, at least for me, a beginner, or so . . <3
Describe the feature / enhancement and how it helps to overcome the problem or limitation: Add support for classic bump maps, in the shader, since for many beginners, they're a lot more intuitive to work with, since one can't directly paint a ' normal ' map, using texture painting, or with a simple grey-scale image, made in a paint program . . . It could either be with a new section, ie. we have normal, metallic, roughness, AO, add also bump, or, make a feature where after importing it, one converts to normal map, in import settings, or a setting under normal map, in material, PBRMaterial in Godot, that converts the bump maps, to a normal map, 1-to-1, or so . . This would be a nice feature, to have support for bump, as they make a lot of sense, to beginners, and even advanced users can make some quick normal maps, almost no work, in Blender, plug a bump map into principled shader, and paint it grey-scale, and booom, one has near professional normal maps, for many, many use cases, or so . .
Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams: Find a way, to make Godot support ordinary grey-scale bump maps, since they've been in the industry, for so many years, not sure how, an elegant way, some-thing fast, robust . . .
If this enhancement will not be used often, can it be worked around with a few lines of script?: I don't know how to reprogram Godot, to do this stuff, atm . .
Is there a reason why this should be core and not an add-on in the asset library?: Well, bump maps are so common, and have been in game making, for so long, it makes sense to me, to have them, ie. cheap normal maps, that work . . .
Thanks . . .