Modifying geometry and then sampling it

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By canias

I’m making a sea with waves and buoyancy

I’ve got running a shader that modifies vertices height so I’ve got a visual sea going on, but I have trouble getting the vertices height to implement buoyancy. That’s the only parameter I need to succeed. I’m using a shader material in a PlaneMesh that I’ve subdivided.

My sea level is not constant because It’s got waves so I can’t use y=0 as reference. I’ve tried 3 aproaches unsuccessfully thus far:

-Trying to get the height back from a shader → Turns out you can only get uniform params and those can’t be modified inside the shader as far as I know

-Using MeshDataTool to access the vertices → Somehow even if the shader modifies the vertices, they all keep their y=0 when I access them via MeshDataTool, I’ve tried creating a new MeshDataTool every frame too

    Samplecode:
extends MeshInstance
    (...)
var surface_tool = SurfaceTool.new()
var mesh_data_tool = MeshDataTool.new()
surface_tool.create_from(mesh,0)
var array_mesh = surface_tool.commit()
mesh_data_tool.create_from_surface(array_mesh,0)

-Generating a collider with create_trimesh_collision() and create_convex_collision() → The resulting collider is always a plane, no waves to be touched. Maybe it could be a way to generate a collider from vertices? Either way I haven’t found either the way to do that nor the way to get those vertices correctly

It is absolutely needed for the final result to be a sea in movement in which is possible to sample the varying height at any point, if you have any suggestions in the way of achieving that it would be most welcome

Thanks in advance

Update:
I made it work as intended by modifying geometry in CPU instead of the GPU. I figured shaders don’t make permanent changes. It is however noticeably slower, maybe I can apralelize it but I doubt the scalability of this solution, the best case scenario remains somehow getting the output of a shader. Maybe I could do it with a texture but I don’t know how to do that

Here the code until now:

func apply_sea(delta):
var time_now = OS.get_ticks_msec()
var time = time_now - time_start
surface_tool.create_from(mesh,0)
var array_mesh = surface_tool.commit()
mesh_data_tool.create_from_surface(array_mesh,0)

for i in range(mesh_data_tool.get_vertex_count()):
	var v = mesh_data_tool.get_vertex(i)
	var f1 = amplitude.x * sin(v.x * frequency.x + time * time_factor.x)
	var f2 = amplitude.y * sin(v.y * frequency.y + time * time_factor.y)
	var height = f1 + f2
	v.y = height
	mesh_data_tool.set_vertex(i,v)

for i in range(array_mesh.get_surface_count()):
	array_mesh.surface_remove(i)

mesh_data_tool.commit_to_surface(array_mesh)
surface_tool.begin(Mesh.PRIMITIVE_TRIANGLES)
surface_tool.create_from(array_mesh,0)
surface_tool.generate_normals()
mesh = surface_tool.commit()
mesh.surface_set_material(0,material_shader)

canias | 2021-04-02 11:51