Godot Version
v4.4 beta 3
Question
I am working with a 3D Mesh Instance for which I am generating a mesh.
All this works just fine but the addition of normal’s appears to not work properly. What am I doing wrong?
I have the vertices and indices correctly generated but the normal i calculate as the cross-product of two of the three edges, when applied to the mesh information, is displayed weirdly at first, and not at all after extending the mesh once more.
The normal’s themselves look alright, see below.
The look of the surface after shading does not. Why?
Thanks for your expertise in advance. The code might help a bit:
extends MeshInstance3D
@export var radius: float = 1.0
@export var material: StandardMaterial3D
@onready var camera: Camera3D = get_node("../Camera3D")
var is_first_point = true
var last_point: Vector3
const CIRCLE_RESOLUTION: int = 6
var vertices: PackedVector3Array = []
var indices: PackedInt32Array = []
var normals: PackedVector3Array = []
func _process(delta: float) -> void:
debug_draw()
func extend_mesh(point: Vector3):
# Set (initial) plant direction
var direction: Vector3
if is_first_point:
direction = Vector3.UP
else:
direction = (point - last_point).normalized()
# Generate disc (points in circle)
var current_point: Vector3 = direction.cross(Vector3.FORWARD) # Start point on disc
for i in range(CIRCLE_RESOLUTION):
current_point = current_point.rotated(direction, TAU / CIRCLE_RESOLUTION)
vertices.append(point + radius * current_point.normalized())
# Generate face and normal information
if not is_first_point:
for left_column in range(CIRCLE_RESOLUTION):
var right_column = (left_column + 1) % CIRCLE_RESOLUTION
var top_row = -CIRCLE_RESOLUTION
var bottom_row = -2 * CIRCLE_RESOLUTION
var p1: int = len(vertices) + top_row + left_column # Top point left
var p2: int = len(vertices) + bottom_row + left_column # Bottom point left
var p3: int = len(vertices) + top_row + right_column # Top point right
var p4: int = len(vertices) + bottom_row + right_column # Bottom point right
indices.append_array([p3, p2, p1])
normals.append(((vertices[p1]-vertices[p2]).cross(vertices[p1]-vertices[p3])).normalized())
indices.append_array([p2, p3, p4])
normals.append(-((vertices[p2]-vertices[p3]).cross(vertices[p2]-vertices[p4])).normalized())
# Create mesh, set information
self.mesh = ArrayMesh.new()
var array = []
array.resize(Mesh.ARRAY_MAX)
array[Mesh.ARRAY_VERTEX] = vertices
if not indices.is_empty():
array[Mesh.ARRAY_INDEX] = indices
array[Mesh.ARRAY_NORMAL] = normals
self.mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, array)
last_point = point
is_first_point = false
func debug_draw() -> void:
return
print("\rVeticies: %s \tFaces: %s \tNormals: %s" % [len(vertices), len(indices) / 3, len(normals)])
# Draw Vertices
DebugDraw3D.draw_points(vertices, DebugDraw3D.POINT_TYPE_SPHERE, 0.02, Color.MEDIUM_VIOLET_RED)
if indices.is_empty(): return
for i in range(0, len(indices), 3):
# Draw Triangles
DebugDraw3D.draw_line(vertices[indices[i]], vertices[indices[i+1]], Color.BLUE_VIOLET)
DebugDraw3D.draw_line(vertices[indices[i+1]], vertices[indices[i+2]], Color.BLUE_VIOLET)
DebugDraw3D.draw_line(vertices[indices[i]], vertices[indices[i+2]], Color.BLUE_VIOLET)
# Draw Normals
var avg: Vector3 = (vertices[indices[i]] + vertices[indices[i+1]] + vertices[indices[i+2]]) / 3.0
var dir: Vector3 = normals[i / 3]
if dir.dot(camera.position - avg) < 0: continue
DebugDraw3D.draw_arrow(avg, avg + dir * 0.5, Color.YELLOW, 0.1, true)