Drawing grid wireframe with ArrayMesh
Asked Answered
C

7

0

Hi.
I am trying to add a grid wireframe(like the gizmo grid matrix in editor view) with ArrayMesh, the basic idea is:

  1. Get camera pos center
  2. Generation 100*100 quads based on camera center + offset with for in range loop every frame or upon camera movements
  3. Render the generated mesh in meshinstance3d.

Though I got a few questions:

  1. I cant seem to find a function to reset mesh, you could only generate new mesh with add_from_surface, but you can't remove exist vertices from ArrayMesh.

  2. The array mesh generated only supports lines or triangle primitives, and it requires vertices count to be power of 3, which is problematic since I am making quads grid.

  3. The ArrayMesh tutorial in 4.0 docs only give an example of how to generate array mesh file, but didn't give hints on how to update mesh in scene in real-time. So what is the proper way of updating generated array mesh in real-time?

I also looking into the possibility to use an exist model(subdivided plane) attached to camera center, though I am not sure if it's appropriate to use model as gridview wireframe renderer.

Thanks.

Chancechancel answered 27/10, 2022 at 2:38 Comment(0)
R
0

I believe the vertices are compiled and uploaded to the GPU. You cannot just arbitrarily change the mesh without recreating it. You can alter the position with a vertex shader though, but not erase or create new geometry.

You would create 2 triangles for each quad, and then remove the center line. You can do this with degenerate polygons (triangles where two vertices have the same position, they won't be drawn).

Also, why would you need to ever recreate the mesh. If it is a grid, then it would be a standard spacing (like 1 meter between each line). You can either set the range to be extremely large (so it goes past the far camera clip distance). Or you can move the whole mesh in GDScript after the camera has moved a certain distance. As long as you snap it to the same cadence as the grid, it will look like it's not moving. For example, let's say the whole grid is 300 meters. If the camera moves 100 meters, then you snap the grid in the same direction 100 meters, it won't look like anything has moved. You can also alter positions in the vertex shader, so the grid always follows the camera.

I posted some code on Reddit that might help you get started.

Romanism answered 27/10, 2022 at 3:29 Comment(0)
C
0

Thanks for the detailed explanation and clarification.
My game is a Homeworld–like space RTS, the grid stuff I want to add is to display " zero–y plane indicator" when issuing move command with vertical(y axis up vector movement in addition to x, z vector), so it needs to be synced with camera position to display properly when camera moves or active camera changed.

Chancechancel answered 27/10, 2022 at 3:52 Comment(0)
C
0

I looked at your video, which look great. But I failed to find the code on reddit, maybe because I rarely use that site.
So I used a static grid mesh made with blender primitive, and it seemed work good so far, except the z-conflicts in distance grid wireframes -_-
https://ibb.co/j8qfNFT

edit: borked image url

Chancechancel answered 29/10, 2022 at 14:15 Comment(0)
R
0

Chancechancel I looked at your video, which look great. But I failed to find the code on reddit, maybe because I rarely use that site.

You have to scroll down. Just like most of the internet works.

Romanism answered 29/10, 2022 at 15:36 Comment(0)
C
0

Romanism
Thanks. Just got the proper link to the code, will try if it works in 4.0b3 later.

Chancechancel answered 29/10, 2022 at 16:42 Comment(0)
R
0

Sorry, I realize it doesn't show the whole thread if you're not logged in on Reddit (there is a continue thread button).

Here's the code anyhow that way it's saved on the forum.

func make_wire_complex():
	var array = mesh_node.mesh.surface_get_arrays(0)
	var wire_array = []
	wire_array.resize(ArrayMesh.ARRAY_MAX)
	var mdt = MeshDataTool.new()
	mdt.create_from_surface(mesh_node.mesh, 0)
	var vertices = PoolVector3Array()
	
	for j in range(mdt.get_face_count()):
		var vert_0 = mdt.get_face_vertex(j, 0)
		var vert_1 = mdt.get_face_vertex(j, 1)
		var vert_2 = mdt.get_face_vertex(j, 2)
		
		var pos_0 = mdt.get_vertex(vert_0)
		var pos_1 = mdt.get_vertex(vert_1)
		var pos_2 = mdt.get_vertex(vert_2)
		
		var sides = get_sides(pos_0, pos_1, pos_2)
				
		for side in sides:
			vertices.push_back(side)

	wire_array[ArrayMesh.ARRAY_VERTEX] = vertices
	
	mesh_node.mesh = ArrayMesh.new()
	mesh_node.mesh.add_surface_from_arrays(Mesh.PRIMITIVE_LINES, wire_array)
	mesh_node.set_surface_material(0, mesh_mat)

func get_sides(pt_0, pt_1, pt_2):
	var dist_01 = (pt_0 - pt_1).length()
	var dist_12 = (pt_1 - pt_2).length()
	var dist_20 = (pt_2 - pt_0).length()
	
	var ret = []
	
	if dist_01 > dist_12 and dist_01 > dist_20:
		ret.push_back(pt_1)
		ret.push_back(pt_2)
		ret.push_back(pt_2)
		ret.push_back(pt_0)
	elif dist_12 > dist_01 and dist_12 > dist_20:
		ret.push_back(pt_0)
		ret.push_back(pt_1)
		ret.push_back(pt_2)
		ret.push_back(pt_0)
	else:
		ret.push_back(pt_0)
		ret.push_back(pt_1)
		ret.push_back(pt_1)
		ret.push_back(pt_2)
	
	return ret
shader_type spatial;
render_mode unshaded, skip_vertex_transform;

uniform float time;
const float one = 1.0;
const float PI = 3.14159265359;
const float TWO_PI = 2.0 * PI;
const vec4 line_color = vec4(0.0, 1.0, 0.0, 1.0);
const vec4 background_color = vec4(0.0, 0.0, 0.0, 1.0);

void vertex() {
	float offset = mod(TIME * 1.5, TWO_PI);
	float offset2 = mod(TIME * 2.0, TWO_PI);
	VERTEX.z += mod(TIME * 2.0, 1.0);
	VERTEX.y = sin(VERTEX.x * 0.5 + offset) * 0.5 + sin(VERTEX.z + offset2) * 0.2;
	COLOR = mix(line_color, background_color, -(VERTEX.z) * 0.1 + 0.1);
    VERTEX = (MODELVIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
}

void fragment() {
	ALBEDO = COLOR.rgb;
}
Romanism answered 29/10, 2022 at 16:57 Comment(0)
C
0

Romanism Thanks. I will take a look.

Chancechancel answered 29/10, 2022 at 23:46 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.