mirror of
https://github.com/GarrettGunnell/God-Machine.git
synced 2025-10-19 14:43:16 +00:00
Draw world with 2nd compositor effect
This commit is contained in:
parent
5607bc62bd
commit
f367df839a
5 changed files with 366 additions and 19 deletions
|
@ -3,7 +3,7 @@
|
|||
#kernel Blit
|
||||
|
||||
|
||||
layout(rgba16f, set = 0, binding = 0) uniform image2D _RenderTarget;
|
||||
layout(rgba8, set = 0, binding = 0) uniform image2D _RenderTarget;
|
||||
layout(r16f, set = 0, binding = 2) uniform image2D _AutomatonFrom;
|
||||
layout(r16f, set = 0, binding = 3) uniform image2D _AutomatonTo;
|
||||
|
||||
|
|
|
@ -17,9 +17,13 @@ var exposure_compute : ACompute
|
|||
var automaton_texture1 : RID
|
||||
var automaton_texture2 : RID
|
||||
|
||||
var world_texture : RID
|
||||
|
||||
var previous_generation : RID
|
||||
var next_generation : RID
|
||||
|
||||
var world_image_texture : ImageTexture
|
||||
|
||||
var timer = 0.0
|
||||
var needs_seeding = true
|
||||
|
||||
|
@ -46,6 +50,15 @@ func _init():
|
|||
next_generation = automaton_texture2
|
||||
|
||||
needs_seeding = true
|
||||
|
||||
var world_format : RDTextureFormat = RDTextureFormat.new()
|
||||
|
||||
world_format.height = 1024
|
||||
world_format.width = 1024
|
||||
world_format.format = RenderingDevice.DATA_FORMAT_R8G8B8A8_UNORM
|
||||
world_format.usage_bits = RenderingDevice.TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice.TEXTURE_USAGE_STORAGE_BIT | RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT | RenderingDevice.TEXTURE_USAGE_CAN_COPY_TO_BIT
|
||||
|
||||
world_texture = rd.texture_create(world_format, RDTextureView.new(), [])
|
||||
|
||||
|
||||
|
||||
|
@ -55,6 +68,7 @@ func _notification(what):
|
|||
exposure_compute.free()
|
||||
rd.free_rid(automaton_texture1)
|
||||
rd.free_rid(automaton_texture2)
|
||||
rd.free_rid(world_texture)
|
||||
|
||||
|
||||
func _render_callback(p_effect_callback_type, p_render_data):
|
||||
|
@ -98,7 +112,7 @@ func _render_callback(p_effect_callback_type, p_render_data):
|
|||
var uniform_array = PackedFloat32Array([exposure.x, exposure.y, exposure.z, exposure.w]).to_byte_array()
|
||||
|
||||
# ACompute handles uniform caching under the hood, as long as the exposure value doesn't change or the render target doesn't change, these functions will only do work once
|
||||
exposure_compute.set_texture(0, input_image)
|
||||
exposure_compute.set_texture(0, world_texture)
|
||||
exposure_compute.set_texture(2, previous_generation)
|
||||
exposure_compute.set_texture(3, next_generation)
|
||||
exposure_compute.set_uniform_buffer(1, uniform_array)
|
||||
|
@ -121,3 +135,6 @@ func _render_callback(p_effect_callback_type, p_render_data):
|
|||
next_generation = temp
|
||||
|
||||
timer += Engine.get_main_loop().root.get_process_delta_time()
|
||||
|
||||
func get_world_texture() -> RID:
|
||||
return world_texture;
|
||||
|
|
327
draw_world_compositor_effect.gd
Normal file
327
draw_world_compositor_effect.gd
Normal file
|
@ -0,0 +1,327 @@
|
|||
@tool
|
||||
extends CompositorEffect
|
||||
class_name DrawWorldEffect
|
||||
|
||||
|
||||
var rd : RenderingDevice
|
||||
|
||||
var transform : Transform3D
|
||||
var light : DirectionalLight3D
|
||||
|
||||
var p_framebuffer : RID
|
||||
var cached_framebuffer_format : int
|
||||
|
||||
var p_render_pipeline : RID
|
||||
var p_render_pipeline_uniform_set : RID
|
||||
var p_wire_render_pipeline : RID
|
||||
var p_vertex_buffer : RID
|
||||
var vertex_format : int
|
||||
var p_vertex_array : RID
|
||||
var p_index_buffer : RID
|
||||
var p_index_array : RID
|
||||
var p_shader : RID
|
||||
var p_sampler_state : RID
|
||||
var clear_colors := PackedColorArray([Color.DARK_BLUE])
|
||||
|
||||
var root_node : Node
|
||||
var compositor : Compositor
|
||||
|
||||
var world_texture_rid : RID
|
||||
|
||||
func _init():
|
||||
effect_callback_type = EFFECT_CALLBACK_TYPE_POST_TRANSPARENT
|
||||
rd = RenderingServer.get_rendering_device()
|
||||
|
||||
|
||||
|
||||
func compile_shader(vertex_shader : String, fragment_shader : String) -> RID:
|
||||
var src := RDShaderSource.new()
|
||||
src.source_vertex = vertex_shader
|
||||
src.source_fragment = fragment_shader
|
||||
|
||||
var shader_spirv : RDShaderSPIRV = rd.shader_compile_spirv_from_source(src)
|
||||
|
||||
var err = shader_spirv.get_stage_compile_error(RenderingDevice.SHADER_STAGE_VERTEX)
|
||||
if err: push_error(err)
|
||||
err = shader_spirv.get_stage_compile_error(RenderingDevice.SHADER_STAGE_FRAGMENT)
|
||||
if err: push_error(err)
|
||||
|
||||
var shader : RID = rd.shader_create_from_spirv(shader_spirv)
|
||||
|
||||
return shader
|
||||
|
||||
func initialize_render(framebuffer_format : int):
|
||||
var side_length = 2
|
||||
|
||||
p_shader = compile_shader(source_vertex, source_fragment)
|
||||
|
||||
var vertex_buffer := PackedFloat32Array([])
|
||||
var half_length = (side_length - 1) / 2.0
|
||||
|
||||
# Generate plane vertices on the xz plane
|
||||
for x in side_length:
|
||||
for z in side_length:
|
||||
var xz : Vector2 = Vector2(x - half_length, z - half_length)
|
||||
|
||||
var pos : Vector3 = Vector3(xz.x, xz.y, 0)
|
||||
|
||||
# Vertex color is not used but left as a demonstration for adding more vertex attributes
|
||||
var color : Vector4 = Vector4(x, z, randf(), 1)
|
||||
|
||||
# For some reason godot doesn't make it easy to append vectors to arrays
|
||||
for i in 3: vertex_buffer.push_back(pos[i])
|
||||
for i in 4: vertex_buffer.push_back(color[i])
|
||||
|
||||
|
||||
var vertex_count = vertex_buffer.size() / 7
|
||||
print("Vertex Count: " + str(vertex_count))
|
||||
|
||||
# Dump vertex data, I would delete this but it's probably helpful definitely do not uncomment this if your mesh has more than a couple vertices
|
||||
# for i in vertex_count:
|
||||
# var j = i * 7
|
||||
# var pos = Vector3()
|
||||
|
||||
# pos.x = vertex_buffer[j]
|
||||
# pos.y = vertex_buffer[j + 1]
|
||||
# pos.z = vertex_buffer[j + 2]
|
||||
|
||||
# var color = Vector4()
|
||||
|
||||
# color.x = vertex_buffer[j + 3]
|
||||
# color.y = vertex_buffer[j + 4]
|
||||
# color.z = vertex_buffer[j + 5]
|
||||
# color.w = vertex_buffer[j + 6]
|
||||
|
||||
# print("Vertex " + str(i) + " ---")
|
||||
# print("Position: " + str(pos))
|
||||
# print("Color: " + str(color))
|
||||
|
||||
|
||||
|
||||
var index_buffer := PackedInt32Array([])
|
||||
|
||||
|
||||
for row in range(0, side_length * side_length - side_length, side_length):
|
||||
for i in side_length - 1:
|
||||
var v = i + row # shift to row we're actively triangulating
|
||||
|
||||
var v0 = v
|
||||
var v1 = v + side_length
|
||||
var v2 = v + side_length + 1
|
||||
var v3 = v + 1
|
||||
|
||||
index_buffer.append_array([v0, v1, v3, v1, v2, v3])
|
||||
|
||||
print("Triangle Count: " + str(index_buffer.size() / 3))
|
||||
|
||||
|
||||
var vertex_buffer_bytes : PackedByteArray = vertex_buffer.to_byte_array()
|
||||
p_vertex_buffer = rd.vertex_buffer_create(vertex_buffer_bytes.size(), vertex_buffer_bytes)
|
||||
|
||||
var vertex_buffers := [p_vertex_buffer, p_vertex_buffer]
|
||||
|
||||
var sizeof_float := 4
|
||||
var stride := 7
|
||||
|
||||
# The GPU needs to know the memory layout of the vertex data, in this case each vertex has a position (3 component vector) and a color (4 component vector)
|
||||
var vertex_attrs = [RDVertexAttribute.new(), RDVertexAttribute.new()]
|
||||
vertex_attrs[0].format = rd.DATA_FORMAT_R32G32B32_SFLOAT
|
||||
vertex_attrs[0].location = 0
|
||||
vertex_attrs[0].offset = 0
|
||||
vertex_attrs[0].stride = stride * sizeof_float
|
||||
|
||||
vertex_attrs[1].format = rd.DATA_FORMAT_R32G32B32A32_SFLOAT
|
||||
vertex_attrs[1].location = 1
|
||||
vertex_attrs[1].offset = 3 * sizeof_float
|
||||
vertex_attrs[1].stride = stride * sizeof_float
|
||||
|
||||
vertex_format = rd.vertex_format_create(vertex_attrs)
|
||||
|
||||
|
||||
p_vertex_array = rd.vertex_array_create(vertex_buffer.size() / stride, vertex_format, vertex_buffers)
|
||||
|
||||
var index_buffer_bytes : PackedByteArray = index_buffer.to_byte_array()
|
||||
p_index_buffer = rd.index_buffer_create(index_buffer.size(), rd.INDEX_BUFFER_FORMAT_UINT32, index_buffer_bytes)
|
||||
p_index_array = rd.index_array_create(p_index_buffer, 0, index_buffer.size())
|
||||
|
||||
var sampler_state := RDSamplerState.new()
|
||||
p_sampler_state = rd.sampler_create(sampler_state)
|
||||
|
||||
|
||||
initialize_render_pipelines(framebuffer_format)
|
||||
|
||||
|
||||
func initialize_render_pipelines(framebuffer_format : int) -> void:
|
||||
var raster_state = RDPipelineRasterizationState.new()
|
||||
|
||||
raster_state.cull_mode = RenderingDevice.POLYGON_CULL_BACK
|
||||
raster_state.front_face = RenderingDevice.POLYGON_FRONT_FACE_COUNTER_CLOCKWISE
|
||||
|
||||
var depth_state = RDPipelineDepthStencilState.new()
|
||||
|
||||
depth_state.enable_depth_write = true
|
||||
depth_state.enable_depth_test = true
|
||||
depth_state.depth_compare_operator = RenderingDevice.COMPARE_OP_GREATER
|
||||
|
||||
var blend = RDPipelineColorBlendState.new()
|
||||
|
||||
blend.attachments.push_back(RDPipelineColorBlendStateAttachment.new())
|
||||
|
||||
p_render_pipeline = rd.render_pipeline_create(p_shader, framebuffer_format, vertex_format, rd.RENDER_PRIMITIVE_TRIANGLES, raster_state, RDPipelineMultisampleState.new(), depth_state, blend)
|
||||
|
||||
var regenerate = true
|
||||
func _render_callback(_effect_callback_type : int, render_data : RenderData):
|
||||
if not enabled: return
|
||||
if _effect_callback_type != effect_callback_type: return
|
||||
|
||||
root_node = Engine.get_main_loop().root
|
||||
var environment = root_node.get_node_or_null("Node3D/WorldEnvironment")
|
||||
|
||||
if not environment: return
|
||||
|
||||
compositor = environment.compositor
|
||||
|
||||
if (compositor.compositor_effects.size() > 1):
|
||||
world_texture_rid = compositor.compositor_effects[0].get_world_texture()
|
||||
|
||||
var render_scene_buffers : RenderSceneBuffersRD = render_data.get_render_scene_buffers()
|
||||
var render_scene_data : RenderSceneData = render_data.get_render_scene_data()
|
||||
|
||||
if not render_scene_buffers: return
|
||||
|
||||
if regenerate or not p_render_pipeline.is_valid():
|
||||
_notification(NOTIFICATION_PREDELETE)
|
||||
p_framebuffer = FramebufferCacheRD.get_cache_multipass([render_scene_buffers.get_color_texture(), render_scene_buffers.get_depth_texture()], [], 1)
|
||||
initialize_render(rd.framebuffer_get_format(p_framebuffer))
|
||||
regenerate = false
|
||||
|
||||
var current_framebuffer = FramebufferCacheRD.get_cache_multipass([render_scene_buffers.get_color_texture(), render_scene_buffers.get_depth_texture()], [], 1)
|
||||
|
||||
# If the framebuffer has changed then we need to reinitialize the render pipeline objects, this happens when the editor window changes or the game window changes
|
||||
if p_framebuffer != current_framebuffer:
|
||||
p_framebuffer = current_framebuffer
|
||||
initialize_render_pipelines(rd.framebuffer_get_format(p_framebuffer))
|
||||
|
||||
var uniform_buffer_data = Array()
|
||||
|
||||
var model = transform
|
||||
var view = render_scene_data.get_cam_transform().inverse()
|
||||
var projection = render_scene_data.get_view_projection(0)
|
||||
|
||||
var model_view = Projection(view * model)
|
||||
var MVP = projection * model_view;
|
||||
|
||||
for i in range(0,16):
|
||||
uniform_buffer_data.push_back(MVP[i / 4][i % 4])
|
||||
|
||||
|
||||
# All of our settings are stored in a single uniform buffer, certainly not the best decision, but it's easy to work with
|
||||
var buffer_bytes : PackedByteArray = PackedFloat32Array(uniform_buffer_data).to_byte_array()
|
||||
var p_uniform_buffer_rid : RID = rd.uniform_buffer_create(buffer_bytes.size(), buffer_bytes)
|
||||
|
||||
|
||||
var uniforms = []
|
||||
var uniform_buffer_uniform := RDUniform.new()
|
||||
|
||||
# The gpu needs to know the layout of the uniform variables, even though we have many variables here on the cpu, they're all in one uniform buffer, and so there is technically only one shader uniform
|
||||
uniform_buffer_uniform.binding = 0
|
||||
uniform_buffer_uniform.uniform_type = rd.UNIFORM_TYPE_UNIFORM_BUFFER
|
||||
uniform_buffer_uniform.add_id(p_uniform_buffer_rid)
|
||||
uniforms.push_back(uniform_buffer_uniform)
|
||||
|
||||
var world_texture_uniform := RDUniform.new()
|
||||
world_texture_uniform.binding = 1
|
||||
world_texture_uniform.uniform_type = rd.UNIFORM_TYPE_SAMPLER_WITH_TEXTURE
|
||||
world_texture_uniform.add_id(p_sampler_state)
|
||||
world_texture_uniform.add_id(world_texture_rid)
|
||||
uniforms.push_back(world_texture_uniform)
|
||||
|
||||
# Currently we just free the previously instantiated uniform set and then make a new one, ideally this is only done when the uniform variables change
|
||||
if p_render_pipeline_uniform_set.is_valid():
|
||||
rd.free_rid(p_render_pipeline_uniform_set)
|
||||
|
||||
p_render_pipeline_uniform_set = rd.uniform_set_create(uniforms, p_shader, 0)
|
||||
|
||||
# If you frame capture the program with something like NVIDIA NSight you will see this label show up so you can easily see the render time of the terrain
|
||||
rd.draw_command_begin_label("Terrain Mesh", Color(1.0, 1.0, 1.0, 1.0))
|
||||
|
||||
# The rest of this code is the creation of the draw call command list whether we are doing wireframe mode or not
|
||||
var draw_list = rd.draw_list_begin(p_framebuffer, rd.DRAW_IGNORE_ALL, clear_colors, 1.0, 0, Rect2(), 0)
|
||||
|
||||
rd.draw_list_bind_render_pipeline(draw_list, p_render_pipeline)
|
||||
|
||||
rd.draw_list_bind_vertex_array(draw_list, p_vertex_array)
|
||||
|
||||
rd.draw_list_bind_index_array(draw_list, p_index_array)
|
||||
|
||||
rd.draw_list_bind_uniform_set(draw_list, p_render_pipeline_uniform_set, 0)
|
||||
rd.draw_list_draw(draw_list, true, 1)
|
||||
rd.draw_list_end()
|
||||
|
||||
rd.draw_command_end_label()
|
||||
|
||||
|
||||
|
||||
func _notification(what):
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
if p_render_pipeline.is_valid():
|
||||
rd.free_rid(p_render_pipeline)
|
||||
if p_wire_render_pipeline.is_valid():
|
||||
rd.free_rid(p_wire_render_pipeline)
|
||||
if p_vertex_array.is_valid():
|
||||
rd.free_rid(p_vertex_array)
|
||||
if p_vertex_buffer.is_valid():
|
||||
rd.free_rid(p_vertex_buffer)
|
||||
if p_index_array.is_valid():
|
||||
rd.free_rid(p_index_array)
|
||||
if p_index_buffer.is_valid():
|
||||
rd.free_rid(p_index_buffer)
|
||||
if p_sampler_state.is_valid():
|
||||
rd.free_rid(p_sampler_state)
|
||||
|
||||
|
||||
const source_vertex = "
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 0, std140) uniform UniformBufferObject {
|
||||
mat4 MVP;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D _WorldTexture;
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec4 a_Color;
|
||||
|
||||
layout(location = 2) out vec3 v_uv;
|
||||
|
||||
|
||||
void main() {
|
||||
v_uv = a_Color.rgb;
|
||||
|
||||
vec3 pos = a_Position;
|
||||
|
||||
gl_Position = MVP * vec4(pos, 1);
|
||||
}
|
||||
"
|
||||
|
||||
|
||||
const source_fragment = "
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 0, std140) uniform UniformBufferObject {
|
||||
mat4 MVP;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D _WorldTexture;
|
||||
|
||||
layout(location = 2) in vec3 v_uv;
|
||||
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
|
||||
|
||||
void main() {
|
||||
float cell = texture(_WorldTexture, v_uv.xy).r;
|
||||
|
||||
frag_color = vec4(cell, 0.0, 0.0, 1.0);
|
||||
}
|
||||
"
|
1
draw_world_compositor_effect.gd.uid
Normal file
1
draw_world_compositor_effect.gd.uid
Normal file
|
@ -0,0 +1 @@
|
|||
uid://bjuwof03jt0ds
|
36
main.tscn
36
main.tscn
|
@ -1,43 +1,45 @@
|
|||
[gd_scene load_steps=7 format=3 uid="uid://cfsgy7huubpok"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://drfxlavovcgta" path="res://automata_compositor_effect.gd" id="1_ig7tw"]
|
||||
[ext_resource type="Script" uid="uid://bjuwof03jt0ds" path="res://draw_world_compositor_effect.gd" id="2_0xm2m"]
|
||||
|
||||
[sub_resource type="Environment" id="Environment_0xm2m"]
|
||||
|
||||
[sub_resource type="CompositorEffect" id="CompositorEffect_ig7tw"]
|
||||
resource_local_to_scene = false
|
||||
resource_name = ""
|
||||
enabled = false
|
||||
enabled = true
|
||||
effect_callback_type = 4
|
||||
needs_motion_vectors = false
|
||||
needs_normal_roughness = false
|
||||
script = ExtResource("1_ig7tw")
|
||||
pause = false
|
||||
update_speed = 0.046
|
||||
current_seed = 5822
|
||||
random_seed = true
|
||||
reseed = false
|
||||
update_speed = 0.05
|
||||
current_seed = 0
|
||||
random_seed = false
|
||||
reseed = true
|
||||
exposure = Vector4(2, 1, 1, 1)
|
||||
metadata/_custom_type_script = "uid://drfxlavovcgta"
|
||||
|
||||
[sub_resource type="CompositorEffect" id="CompositorEffect_h2yge"]
|
||||
resource_local_to_scene = false
|
||||
resource_name = ""
|
||||
enabled = true
|
||||
effect_callback_type = 4
|
||||
needs_motion_vectors = false
|
||||
needs_normal_roughness = false
|
||||
script = ExtResource("2_0xm2m")
|
||||
metadata/_custom_type_script = "uid://bjuwof03jt0ds"
|
||||
|
||||
[sub_resource type="Compositor" id="Compositor_1bvp3"]
|
||||
compositor_effects = Array[CompositorEffect]([SubResource("CompositorEffect_ig7tw")])
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ig7tw"]
|
||||
shading_mode = 0
|
||||
|
||||
[sub_resource type="QuadMesh" id="QuadMesh_0xm2m"]
|
||||
material = SubResource("StandardMaterial3D_ig7tw")
|
||||
compositor_effects = Array[CompositorEffect]([SubResource("CompositorEffect_ig7tw"), SubResource("CompositorEffect_h2yge")])
|
||||
|
||||
[node name="Node3D" type="Node3D"]
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.485)
|
||||
projection = 1
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="Camera3D"]
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment_0xm2m")
|
||||
compositor = SubResource("Compositor_1bvp3")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Camera3D"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.845244)
|
||||
mesh = SubResource("QuadMesh_0xm2m")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue