-
Notifications
You must be signed in to change notification settings - Fork 145
Description
First off, thank you for providing this project. It's incredible. Looks great. Technical marvel.
I am working on adding buoyancy to a sample project following this video.
The provided code for the floating cube requires a function get_height which samples the noise map of a simple water shader at a given point (or points).
func _physics_process(delta):
submerged = false
for p in probes:
var depth = water.get_height(p.global_position) - p.global_position.y
if depth > 0:
submerged = true
apply_force(Vector3.UP * float_force * gravity * depth, p.global_position - global_position)The shader in this project is much more complex, but it should still be possible to accomplish this. I'm curious what method I can use to access height info.
My basic approach was going to be similar to the code in the video:
- Get the shader ShaderMaterial
- Get the
sampler2DArray displacementsandmap_scalesusingget_shader_parameter( ) - Implement a new
get_heightfunction inwater.gdthat would mirror the shader'svertexfunc by:- Iterating over the displacements, creating images or textures
texture.get_image()or something- Not sure how to do this conversion in gdscript
texture(displacements, vec3(UV*scales.xy, float(i))).xyz * scales.z;
- Not sure how to do this conversion in gdscript
- Add up the displacement
displacement +=for each - return the pixel's height like:
global_position.y + noise.get_pixelv(pixel_pos).r * height_scale;
- Iterating over the displacements, creating images or textures
Here's the sample:
func get_height(world_position: Vector3) -> float:
var uv_x = wrapf(world_position.x / noise_scale + time * wave_speed, 0, 1)
var uv_y = wrapf(world_position.z / noise_scale + time * wave_speed, 0, 1)
var pixel_pos = Vector2(uv_x * noise.get_width(), uv_y * noise.get_height())
return global_position.y + noise.get_pixelv(pixel_pos).r * height_scale;For my code, I couldn't get very far. I first tried collecting the information I needed via get_shader_parameter() and found many were null.
var water_shader:ShaderMaterial
func _ready() -> void:
RenderingServer.global_shader_parameter_set(&'water_color', water_color.srgb_to_linear())
RenderingServer.global_shader_parameter_set(&'foam_color', foam_color.srgb_to_linear())
// Added new code to test:
water_shader = material_override
print('water shader', water_shader)
print('get_shader_parameter, roughness: ', water_shader.get_shader_parameter('roughness'))
print('get_shader_parameter: normal_strength: ', water_shader.get_shader_parameter('normal_strength'))
print('get_shader_parameter: map_scales: ', water_shader.get_shader_parameter('map_scales'))
print('-----------')
print('RenderingServer.get_shader_parameter_list: ', '[&"displacements", &"foam_color", &"normals", &"num_cascades", &"water_color"]')
print('-----------')
print('get_shader_parameter: water_color: ', water_shader.get_shader_parameter('water_color'))
print('get_shader_parameter: displacements: ', water_shader.get_shader_parameter('displacements'))
print('get_shader_parameter: &"displacements": ', water_shader.get_shader_parameter(&"displacements"))Which yields the output:
water shader<ShaderMaterial#-9223372007175879383>
get_shader_parameter, roughness: 0.65
get_shader_parameter: normal_strength: 1
get_shader_parameter: map_scales: [(0.011364, 0.011364, 1, 1), (0.017544, 0.017544, 0.75, 1), (0.0625, 0.0625, 0, 0.25)]
-----------
RenderingServer.get_shader_parameter_list: [&"displacements", &"foam_color", &"normals", &"num_cascades", &"water_color"]
-----------
get_shader_parameter: water_color: <null>
get_shader_parameter: displacements: <null>
get_shader_parameter: &"displacements": <null>
The displacements are null, as are all of the ones in the get_shader_parameter_list. I think that may be because global, so they could be tough to access. Ones I can get do not have global.
uniform float roughness : hint_range(0.0, 1.0) = 0.4;
uniform float normal_strength : hint_range(0.0, 1.0) = 1.0; // Global normal strength
group_uniforms cascade_data;
uniform vec4 map_scales[MAX_CASCADES]; // Scales for displacement/normal maps. Packed: [uv scale, displacement scale, normal scale]
global uniform uint num_cascades;
global uniform sampler2DArray displacements; // Each layer represents one wave cascade.
global uniform sampler2DArray normals : hint_normal; // Each layer represents one wave cascade.
roughness is available but water_color is not. I can also get map_scales which seems useful for what I want to do eventually.
So far, I am stuck trying to figure out how to get displacements. Even if I could access it, it's probably likely that I'd have trouble unpacking it.
Next, I tried to access the displacement_map created in water.gd, hoping it might be passed in by reference (unlikely, but possible) and be updated with the water shader and I could query for a pixel's height on those images by sampling it.
var displacement_maps := Texture2DArrayRD.new()
var normal_maps := Texture2DArrayRD.new()Can count them, but I tried to see if I could get an image according to the Texture2DArrayRD docs:
displacement_maps.get_layer_data(0)I got:
E 0:00:01:0221 water.gd:91 @ _ready(): Texture requires the `RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT` to be set to
Which of course led me into res://assets/render_context.gd, which is likely not something I'm able to change.
Several open questions:
- Is this approach fundamentally flawed?
- Is there a way to expose a more simplistic deformed noise map that's "roughly" in sync with the cascades?
- Maybe also provide a new noise map that can be updated with wave height and queried easily by buoyant objects
So, if anyone has suggestions on how best to add basic bouncy please let me know. Happy to take this discussion elsewhere if there's a better place for it. Thanks again for the project.