Godot Version
4.5
Question
I’m trying to access the Normal and Roughness buffer through the compositor. If I’m understanding the documentation ( CompositorEffect — Godot Engine (stable) documentation in English ) correctly, I need to:
- In func _init(): of my CompositorEffect.gdscript, add the following boolean:
func _init():effect_callback_type = CompositorEffect.EFFECT_CALLBACK_TYPE_POST_SKY
rd = RenderingServer.get_rendering_device()
shader = rd.shader_create_from_spirv(shader_file.get_spirv())
pipeline = rd.compute_pipeline_create(shader)
#Enable Normal and roughness pass.
needs_normal_roughness = true;
- In func _render_callback of my CompistorEffect.gdscript, create the RDUniform (and add it to the uniform_set) using the below specific command to get the texture:
var u_rough: RDUniform = RDUniform.new()
u_rough.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE
u_rough.binding = 2
u_rough.add_id(render_scene_buffers.get_texture("forward_clustered", "normal_roughness"))
- In the .glsl file, include the following to pass the buffer into, so it’s converted to the expected output:
vec4 normal_roughness_compatibility(vec4 p_normal_roughness) {
float roughness = p_normal_roughness.w;
if (roughness > 0.5) {
roughness = 1.0 - roughness;
}
roughness /= (127.0 / 255.0);
return vec4(normalize(p_normal_roughness.xyz * 2.0 - 1.0) * 0.5 + 0.5, roughness);
}
- Then I figured it was just a case in void main() of the glsl file doing:
vec4 NRough = imageLoad(normalroughness_image, uv);
vec4 NRough2 = normal_roughness_compatibility(NRough);
-or-
vec4 NRough = normal_roughness_compatibility(imageLoad(normalroughness_image, uv));
However, if I try and use either the converted normal/roughness or just try and output the unmodified normalroughness_image through ImageStore.
I get flooded with these errors:
ERROR: Can’t create a shader from an errored bytecode. Check errors in source bytecode.
ERROR: servers/rendering/rendering_device.cpp:4175 - Parameter “shader” is null.
ERROR: servers/rendering/rendering_device.cpp:3562 - Parameter “shader” is null.
ERROR: servers/rendering/renderer_rd/uniform_set_cache_rd.h:120 - Condition “rid.is_null()” is true. Returning: rid
ERROR: servers/rendering/rendering_device.cpp:5139 - Parameter “pipeline” is null.
ERROR: servers/rendering/rendering_device.cpp:5221 - Parameter “uniform_set” is null.
ERROR: This compute pipeline requires (0) bytes of push constant data, supplied: (16)
ERROR: No compute pipeline was set before attempting to draw.
Which I’m presuming (but don’t actually know for sure) means that the Normal/Roughness buffer is failing to be created/added at the:
u_rough.add_id(render_scene_buffers.get_texture(“forward_clustered”, “normal_roughness”))
line of the CompositorEffect.gdscript?
So, I was wondering if I’m doing something wrong?
Thanks for any help you can give 
The error suggests that shader didn’t compile. Double click on the glsl file in the file system panel to display the compile error.
Sorry, to clarify I meant that those errors only ever happen if I try and output the input buffer either its’ direct image or the output vec4 from the compatibility return.
So, if I had for example:
imageStore(main_image, uv, vec4(1.0));
This compiles correctly, and just outputs the main scene layer.
However, if I were to try:
imageStore(normalroughness_image, uv, vec4(1.0));
This also compiles correctly (“Shader stage compiled without errors.”) but the Output is then flooded with the previous posts list of error messages (and t.
The same occurs if I try outputting the vec4 thats been returned from the compatibility code.
Edit: I just relaunched the editor, this time, shader compiled fine, no output error spam, but it’s just showing the regular scene - not displaying normals etc. as I would expect to see (the imageStore is as above normalroughness_image).
The first argument to imageStore() is supposed to be the target. So if you want to display nr texture then: imageStore(main_image, uv, imageLoad(normalroughness_image, uv));
#[compute]
#version 450
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(rgba16f, set = 0, binding = 0) uniform image2D main_image;
layout(rgba16f, set = 0, binding = 1) uniform image2D nr_image;
layout(push_constant) uniform Params {
vec2 image_size;
vec2 padding;
} params;
void main() {
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
if(uv.x >= params.image_size.x || uv.y >= params.image_size.y){
return;
}
imageStore(main_image, uv, imageLoad(nr_image, uv));
}
Okay, so due to my lack of knowledge, and going by the unshaded through the compositor thread, I was thinking that imageStore was just modifying each input binding.
So we were storing the modifications back to each image.
But, if I understand correctly now - main_image being color layer 0, means whatever I store to that name will be what renders on the viewport.
So in your example we’re telling main_image as the target to use the source from nr_image - which in turn is telling the engine this is what we want to render?
I notice that the output whether nr_image or converted and returned through the vec4 info in the documentation looks like it’s in Viewspace and not Worldspace since the camera movement changes the normal colours.
It’s simple. imageLoad() reads the rgba value of a pixel in the image and imageStore() writes a rgba value to a pixel in the image.
Normals in NR texture are in view/camera space. So if you need them in world space, pass the view to world matrix to the shader and multiply the normal with it.
If this is for custom illumination, you can just pass the light vector in view space instead.
Thanks for the explanation, I admit that because of the word “image” it was making me forget that these would be per-pixel and I was thinking in terms of whole screen at once.
I don’t think I actually need it in world space, but it was good to confirm that it was in Viewspace as a precaution - it’s actually the roughness values (which you can see I did get in the test scene below) I’m after rather than the normals but I wanted to see the normals in the viewport to confirm the glsl file was recieving the vec4.