Skip to content

Instantly share code, notes, and snippets.

@partybusiness
Last active June 17, 2024 15:07
Show Gist options
  • Save partybusiness/f624749bebdcf9892367afbf9e0a60c0 to your computer and use it in GitHub Desktop.
Save partybusiness/f624749bebdcf9892367afbf9e0a60c0 to your computer and use it in GitHub Desktop.
generates a mesh in a figure-eight shape and saves it as a resource
shader_type spatial;
render_mode cull_disabled, unshaded, depth_draw_opaque;
//just something I used to diaply the figure eight
uniform sampler2D tex:source_color;
uniform float spin_speed = 1.0;
void vertex() {
UV.y = UV.y + TIME * spin_speed;
}
void fragment() {
vec4 col = texture(tex,UV);
float modof = 0.0;
if (FRONT_FACING){
ALBEDO = col.rgb*col.a;
modof = 1.0;
} else
ALBEDO = col.brg*col.a;
ALPHA = col.a * floor(mod (floor(SCREEN_UV.x*VIEWPORT_SIZE.x)+floor(SCREEN_UV.y*VIEWPORT_SIZE.y) + modof, 2.0));
ALPHA_SCISSOR_THRESHOLD = 0.5;
}
@tool
extends EditorScript
#Godot editorscript that generates a mesh and saves it to a resource file
# this one is a figure eight but the same idea could be used for other shapes.
#name of MeshInstance3D in current scene that will display generated mesh
var display_mesh_name:String = "meshDisplay"
#file path of mesh resource you want to save
var file_path:String = "res://figure_eight.res"
func _run():
var surface = SurfaceTool.new()
surface.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP)
#generate figure eight
for i in range(0,32+1):
var rad = i/16.0 * PI * 2.0
var spacing = 1.0
var circle1 = Vector2(cos(rad) + spacing,sin(rad))
var circle2 = Vector2(cos(-rad-PI) - spacing,sin(-rad-PI))
var circle = circle1;
if (rad>PI && rad<PI*3.0):
circle = circle2;
var height = sin(rad/2.0 + PI)*0.5
surface.set_uv(Vector2(0,i*0.25))
surface.add_vertex(Vector3(circle.x,-0.5+height,circle.y))
surface.set_uv(Vector2(1,i*0.25))
surface.add_vertex(Vector3(circle.x,0.5+height,circle.y))
var mesh = surface.commit() #generate the mesh
var currentScene = get_scene()
var mesh_instance:MeshInstance3D = currentScene.find_child(display_mesh_name, true)
mesh_instance.mesh = mesh #assign to MeshInstance3D in scene
ResourceSaver.save( mesh, file_path ) #save it to a file
@tool
extends EditorScript
#generates series of meshes and assigns them to a MeshLibrary for use in a GridMap
#at the moment this makes ground planes with each corner at one of two heights
#name of MeshInstance3D in current scene that will display generated mesh
var display_mesh_name:String = "meshDisplay"
var grid_name:String = "GridMap"
var xx = 32 #number of vertices in each direction
var yy = 32 #
var width:float = 1.0 #metres in each direction
var depth:float = 1.0
var height:float = 0.5
var grid_material:Material
#file path of mesh resource you want to save
var file_path:String = "res://waves/wave_%d_%d_%d_%d.res"
var material_name:String = "res://waves/wave_material.res"
func get_h(u:float,v:float, c00:int, c01:int, c10:int, c11:int)-> float:
var sv = sin(v*PI - PI/2.0)*0.5+0.5
var su = sin(u*PI - PI/2.0)*0.5+0.5
var xh0 = lerp(c00,c01,sv)
var xh1 = lerp(c10,c11,sv)
var yh0 = lerp(c00,c10,su)
var yh1 = lerp(c01,c11,su)
var h = lerp(xh0,xh1, su) * height
return h
func generate_wave(c00:int, c01:int, c10:int, c11:int) -> Mesh:
var arr = []
arr.resize(Mesh.ARRAY_MAX)
var verts:PackedVector3Array
var uvs:PackedVector2Array
var normals:PackedVector3Array
var indices:PackedInt32Array
var radius = 2.0
#make vertices
for x in range(0, xx+1): #one extra so UVs wrap seamlessly
for y in range (0, yy+1):
var u = x/float(xx)
var v = y/float(yy)
var h = get_h(u,v,c00,c01,c10,c11)
#calculates u delta height and v delta height and creates tangents from those
var udh = get_h(u+0.1/float(xx),v,c00,c01,c10,c11) - get_h(u-0.1/float(xx),v,c00,c01,c10,c11)
var vdh = get_h(u,v+0.1/float(yy),c00,c01,c10,c11) - get_h(u,v-0.1/float(yy),c00,c01,c10,c11)
var udvec = Vector3(0.1/float(xx),udh,0).normalized()
var vdvec = Vector3(0,vdh,0.1/float(yy)).normalized()
uvs.append(Vector2(u,v))
verts.append(Vector3(lerp(-width,width, u),h,lerp(-depth,depth, v)))
#uses cross-product of two tangents to set normal
normals.append(-(udvec.cross(vdvec)).normalized())
#assign indices
for x in range(0, xx):
for y in range (0, yy):
var i = x * (yy+1) + y
var n = (i + yy + 1)
indices.append_array([n,i+1,i])
indices.append_array([n+1,i+1,n])
arr[Mesh.ARRAY_VERTEX] = verts
arr[Mesh.ARRAY_TEX_UV] = uvs
arr[Mesh.ARRAY_NORMAL] = normals
arr[Mesh.ARRAY_INDEX] = indices
var mesh:ArrayMesh = ArrayMesh.new()
# Create mesh surface from mesh array.
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr)
mesh.regen_normal_maps() #if you don't want to customize normals this is eaasiest
var currentScene = get_scene()
var mesh_instance:MeshInstance3D = currentScene.find_child(display_mesh_name, true)
mesh_instance.mesh = mesh
mesh.surface_set_material(0, grid_material)
ResourceSaver.save( mesh, file_path%[c00,c01,c10,c11] )
return mesh
func _run():
var currentScene = get_scene()
var grid_map:GridMap = currentScene.find_child(grid_name, true)
grid_map.visible = false #prevents errors from trying to render
grid_map.mesh_library = MeshLibrary.new()
var lib:MeshLibrary = grid_map.mesh_library
grid_material = ShaderMaterial.new()
ResourceSaver.save (grid_material, material_name)
var meshes:Array[Mesh]
for a in range(0,2):
for b in range(0,2):
for c in range(0,2):
for d in range(0,2):
var new_mesh = generate_wave(a,b,c,d)
meshes.append(new_mesh)
var id = lib.get_last_unused_item_id()
lib.create_item(id)
lib.set_item_mesh(id, new_mesh)
#These are for adding colliders
lib.set_item_shapes(id,[new_mesh.create_trimesh_shape()])
lib.set_item_mesh_transform(id, Transform3D.IDENTITY)
lib.set_item_name(id, "wave_%d_%d_%d_%d.res"%[a,b,c,d])
grid_map.visible = true
@tool
extends EditorScript
#alternate version of generating a mesh that assigns values to arrays rather than call the SurfaceTool functions
#name of MeshInstance3D in current scene that will display generated mesh
var display_mesh_name:String = "meshDisplay"
#file path of mesh resource you want to save
var file_path:String = "res://loop.res"
func _run():
var arr = []
arr.resize(Mesh.ARRAY_MAX)
var verts:PackedVector3Array
var uvs:PackedVector2Array
var normals:PackedVector3Array
var indices:PackedInt32Array
var h = 16 #height of loop in number of vertices
var w = 32 #segments of loop as number of vertices
var radius = 2.0
#make vertices
for x in range(0, w+1): #one extra so UVs wrap seamlessly
for y in range (0, h):
var u = y/float(h)
var v = x/float(w) * 5.0
var rad = x/float(w) * 2.0 * PI
var radius_ult = lerp(radius + sin(u*PI), radius, u)
uvs.append(Vector2(u,v))
verts.append(Vector3(sin(rad)*radius_ult,u,cos(rad)*radius_ult))
normals.append(Vector3(sin(rad),u-0.5,cos(rad)).normalized())
#assign indices
for x in range(0, w):
for y in range (0, h-1):
var i = x * h + y
var n = (i + h)
indices.append_array([i,i+1,n])
indices.append_array([i+1,n+1,n])
arr[Mesh.ARRAY_VERTEX] = verts
arr[Mesh.ARRAY_TEX_UV] = uvs
arr[Mesh.ARRAY_NORMAL] = normals
arr[Mesh.ARRAY_INDEX] = indices
var mesh:ArrayMesh = ArrayMesh.new()
# Create mesh surface from mesh array.
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arr)
var currentScene = get_scene()
var mesh_instance:MeshInstance3D = currentScene.find_child(display_mesh_name, true)
mesh_instance.mesh = mesh #this works fine
ResourceSaver.save( mesh, file_path )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment