This script should be everything you need to make a simple UV sphere, possibly exactly the same as the UV sphere in blender.

<details>
<summary>Click this line to see code.</summary>
Put this on a regular node then add a MeshInstance child.
tool
extends Spatial
export (NodePath) var mesh_node = null setget set_mesh_node
func set_mesh_node(val):
_clear()
mesh_node = val
_initialize()
export (int) var segments = 16 setget set_segments
func set_segments(val):
_clear()
segments = val
segments = clamp(segments, 1, 256)
_initialize()
export (int) var rings = 16 setget set_rings
func set_rings(val):
_clear()
rings = val
rings = clamp(rings, 1, 256)
_initialize()
export (float) var radius = 1.0 setget set_radius
func set_radius(val):
_clear()
radius = val
if radius < 0.0:
radius = 0.0
_initialize()
export (Vector3) var Scale = Vector3(1,1,1) setget set_scale
func set_scale(val):
_clear()
Scale = val
_initialize()
var mesh_nd : MeshInstance = null
var vertices : PoolVector3Array
var UVs : PoolVector2Array
var normals : PoolVector3Array
var indices : PoolIntArray
var is_initialized = false
func _generate_sphere():
vertices = PoolVector3Array()
UVs = PoolVector2Array()
normals = PoolVector3Array()
indices = PoolIntArray()
# Vertex indices.
var thisrow = 0
var prevrow = 0
var point = 0
# Loop over rings.
for i in range(rings + 1):
var v = float(i) / rings
var w = sin(PI * v)
var y = cos(PI * v)
# Loop over segments in ring.
for j in range(segments):
var u = float(j) / segments
var x = sin(u * PI * 2.0)
var z = cos(u * PI * 2.0)
var vert = Vector3(x * radius * w * Scale.x, y * radius * Scale.y, z * radius * w * Scale.z)
vertices.append(vert)
normals.append(vert.normalized())
UVs.append(Vector2(u, v))
point += 1
# Create triangles in ring using indices.
if i > 0 and j > 0:
indices.append(prevrow + j - 1)
indices.append(prevrow + j)
indices.append(thisrow + j - 1)
indices.append(prevrow + j)
indices.append(thisrow + j)
indices.append(thisrow + j - 1)
if i > 0:
indices.append(prevrow + segments - 1)
indices.append(prevrow)
indices.append(thisrow + segments - 1)
indices.append(prevrow)
indices.append(prevrow + segments)
indices.append(thisrow + segments - 1)
prevrow = thisrow
thisrow = point
func _generate_mesh():
_generate_sphere()
var mesh = ArrayMesh.new()
var data = []
data.resize(ArrayMesh.ARRAY_MAX)
data[ArrayMesh.ARRAY_VERTEX] = vertices
data[ArrayMesh.ARRAY_TEX_UV] = UVs
data[ArrayMesh.ARRAY_INDEX] = indices
data[ArrayMesh.ARRAY_NORMAL] = normals
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLE_STRIP, data)
mesh.regen_normalmaps()
return mesh
func _initialize():
if is_initialized:
return
if mesh_node == null:
return
mesh_nd = get_node_or_null(mesh_node)
if mesh_nd == null:
return
mesh_nd.mesh = _generate_mesh()
is_initialized = true
func _clear():
if mesh_nd != null and is_initialized:
is_initialized = false
mesh_nd.mesh = null
func _ready():
_initialize()
</details>
Note, I am only 20% sure this code is flawless. Would appreciate someone with related experience play around with this.