2025/01/15(水) [n年前の日記]
#1 [godot] ボールの軌跡の形状について試行錯誤中
_昨日の作業
の続き。Windows10 x64 22H2 + Godot Engine 4.3 64bit でゴルフゲームっぽいものが作れないものかなと試してる。
ボールの軌跡を、ImmediateMesh を使って、動的にポリゴンモデルを生成することで表現したい。別プロジェクトで実験していたけれど、それらしく描画できそうな気がしてきた。以下のような見た目になった。
ソースは以下。白いソレ、青いソレ、赤いソレの順番で並べてある。
_im3_mesh_instance_3d.gd
_im2_mesh_instance_3d.gd
_im1_mesh_instance_3d.gd
それぞれを、MeshInstance3Dノードにアタッチしている。

一応、ソースの中身も貼っておく。毎フレーム、配列 poslist: PackedVector3Array に座標値群を入れておいて、その座標値群を元にして、ImmediateMesh によるポリゴンモデルを作成している。
_im3_mesh_instance_3d.gd
ベクトルに垂直な矩形を求めるあたりは、以下の図が参考になる…のかな…どうなんだろ…。
元ベクトルとY軸の外積で横方向に垂直なベクトルを求めてから、元ベクトルと横方向のベクトルの外積で縦方向のベクトルを求めて、その縦方向と横方向のベクトルから矩形の頂点座標を求める。上のソースで言えば、get_rect_pos() がその処理をしている。
ゴルフゲームにも組み込んでみた。
イイ感じになってきた気がする。
ちなみに、以前の版の見た目は以下。
ボールの軌跡を、ImmediateMesh を使って、動的にポリゴンモデルを生成することで表現したい。別プロジェクトで実験していたけれど、それらしく描画できそうな気がしてきた。以下のような見た目になった。
ソースは以下。白いソレ、青いソレ、赤いソレの順番で並べてある。
_im3_mesh_instance_3d.gd
_im2_mesh_instance_3d.gd
_im1_mesh_instance_3d.gd
それぞれを、MeshInstance3Dノードにアタッチしている。

一応、ソースの中身も貼っておく。毎フレーム、配列 poslist: PackedVector3Array に座標値群を入れておいて、その座標値群を元にして、ImmediateMesh によるポリゴンモデルを作成している。
_im3_mesh_instance_3d.gd
extends MeshInstance3D
var mat: StandardMaterial3D
var ang: float = 0.0
var poslist: PackedVector3Array = PackedVector3Array()
func _ready():
mat = StandardMaterial3D.new()
mat.albedo_color = Color(1, 1, 1, 0.25)
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
mesh = ImmediateMesh.new()
var n = 30
for i in range(0, n, 1):
poslist.append(Vector3.ZERO)
func _process(delta):
# store positon to PackedVector3Array
for i in range(0, poslist.size(), 1):
var x1 = -12.0 + 4.0 * sin(deg_to_rad((ang + 10 * i) * 0.75))
var y1 = 4.0 + 4.0 * sin(deg_to_rad(ang + 10 * i))
var z1 = 10 - 1.0 * i
poslist[i] = Vector3(x1, y1, z1)
# set ImmediateMesh
mesh.clear_surfaces()
mesh.surface_begin(Mesh.PRIMITIVE_TRIANGLES, mat)
# mesh.surface_set_color(Color.WHITE)
var r = 0.5
for i in range(0, poslist.size() - 2, 1):
var p0 = get_rect_pos(poslist[i], poslist[i+1], r)
var p1 = get_rect_pos(poslist[i+1], poslist[i+2], r)
mesh.surface_add_vertex(p0[3])
mesh.surface_add_vertex(p0[0])
mesh.surface_add_vertex(p1[3])
mesh.surface_add_vertex(p1[3])
mesh.surface_add_vertex(p0[0])
mesh.surface_add_vertex(p1[0])
mesh.surface_add_vertex(p0[0])
mesh.surface_add_vertex(p0[2])
mesh.surface_add_vertex(p1[0])
mesh.surface_add_vertex(p1[0])
mesh.surface_add_vertex(p0[2])
mesh.surface_add_vertex(p1[2])
mesh.surface_add_vertex(p0[2])
mesh.surface_add_vertex(p0[1])
mesh.surface_add_vertex(p1[2])
mesh.surface_add_vertex(p1[2])
mesh.surface_add_vertex(p0[1])
mesh.surface_add_vertex(p1[1])
mesh.surface_add_vertex(p0[1])
mesh.surface_add_vertex(p0[3])
mesh.surface_add_vertex(p1[1])
mesh.surface_add_vertex(p1[1])
mesh.surface_add_vertex(p0[3])
mesh.surface_add_vertex(p1[3])
mesh.surface_end()
ang += 120.0 * delta
func get_rect_pos(v0: Vector3, v1: Vector3, r: float):
var v = v1 - v0
var va = v.cross(Vector3.UP).normalized()
var vb = v.cross(va).normalized()
var pv0 = v0 + r * vb
var pv1 = v0 - r * vb
var pv2 = v0 + r * va
var pv3 = v0 - r * va
return [pv0, pv1, pv2, pv3]
ベクトルに垂直な矩形を求めるあたりは、以下の図が参考になる…のかな…どうなんだろ…。
元ベクトルとY軸の外積で横方向に垂直なベクトルを求めてから、元ベクトルと横方向のベクトルの外積で縦方向のベクトルを求めて、その縦方向と横方向のベクトルから矩形の頂点座標を求める。上のソースで言えば、get_rect_pos() がその処理をしている。
ゴルフゲームにも組み込んでみた。
イイ感じになってきた気がする。
ちなみに、以前の版の見た目は以下。
◎ 課題 :
Godot Engine の ImmediateMesh で描画できるプリミティブは以下がある。点、線、三角ポリゴンが指定できる模様。
今回は三角ポリゴン、PRIMITIVE_TRIANGLES を使ったけれど、おそらく PRIMITIVE_TRIANGLE_STRIP を使ったほうが描画の効率は良さそうな気もする。
ただ、どういう順番、どういう形で頂点を指定していけばいいのか、そこが分からない…。輪を描くように描画したほうがいいのか、帯を描くように描画したほうがいいのか…。
- PrimitiveType PRIMITIVE_POINTS = 0
- PrimitiveType PRIMITIVE_LINES = 1
- PrimitiveType PRIMITIVE_LINE_STRIP = 2
- PrimitiveType PRIMITIVE_TRIANGLES = 3
- PrimitiveType PRIMITIVE_TRIANGLE_STRIP = 4
今回は三角ポリゴン、PRIMITIVE_TRIANGLES を使ったけれど、おそらく PRIMITIVE_TRIANGLE_STRIP を使ったほうが描画の効率は良さそうな気もする。
ただ、どういう順番、どういう形で頂点を指定していけばいいのか、そこが分からない…。輪を描くように描画したほうがいいのか、帯を描くように描画したほうがいいのか…。
[ ツッコむ ]
以上、1 日分です。
