65 lines
2.7 KiB
GDScript
65 lines
2.7 KiB
GDScript
extends SceneTree
|
|
const EffectPlayer = preload("res://fx/effect_player.gd")
|
|
var failures := 0
|
|
func check(ok: bool, label: String) -> void:
|
|
if not ok:
|
|
failures += 1
|
|
printerr("FAIL: " + label)
|
|
func _init() -> void:
|
|
call_deferred("run")
|
|
func run() -> void:
|
|
for kind in [4, 5]:
|
|
var fx := EffectPlayer.new()
|
|
fx.build({"particles": [{"particle": {"BillboardType": kind, "ColorOperationType": 4}}]})
|
|
var emitter: GPUParticles3D = fx._emitters[0]
|
|
var mesh := emitter.draw_pass_1
|
|
var arrays := mesh.surface_get_arrays(0)
|
|
var angles := [-30.0, 30.0] if kind == 4 else [0.0, -60.0, 60.0]
|
|
check(arrays[Mesh.ARRAY_VERTEX].size() == angles.size() * 6, "one quad per reference face")
|
|
for i in angles.size():
|
|
for v in 6:
|
|
check(is_equal_approx(arrays[Mesh.ARRAY_TEX_UV2][i * 6 + v].x, deg_to_rad(angles[i])), "reference face angle")
|
|
check(emitter.material_override is ShaderMaterial, "custom face shader")
|
|
check(emitter.material_override.get_shader_parameter("billboard_mode") == 5, "multiface mode")
|
|
if DisplayServer.get_name() != "headless":
|
|
await pixels(mesh, emitter.material_override, kind)
|
|
fx.free()
|
|
print("effect_faces_test: failures=%d" % failures)
|
|
quit(1 if failures else 0)
|
|
func pixels(mesh: Mesh, material: ShaderMaterial, kind: int) -> void:
|
|
var viewport := SubViewport.new()
|
|
viewport.size = Vector2i(128, 128)
|
|
viewport.own_world_3d = true
|
|
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
|
root.add_child(viewport)
|
|
var world := WorldEnvironment.new()
|
|
world.environment = Environment.new()
|
|
world.environment.background_mode = Environment.BG_COLOR
|
|
world.environment.background_color = Color.BLACK
|
|
viewport.add_child(world)
|
|
var image := Image.create(2, 2, false, Image.FORMAT_RGBA8)
|
|
image.fill(Color.WHITE)
|
|
material.set_shader_parameter("albedo_texture", ImageTexture.create_from_image(image))
|
|
var instance := MeshInstance3D.new()
|
|
instance.mesh = mesh
|
|
instance.material_override = material
|
|
viewport.add_child(instance)
|
|
var camera := Camera3D.new()
|
|
camera.projection = Camera3D.PROJECTION_ORTHOGONAL
|
|
camera.size = 1.28
|
|
viewport.add_child(camera)
|
|
for angle in [0.0, 0.7]:
|
|
camera.position = Vector3(sin(angle) * 3, 0, cos(angle) * 3)
|
|
camera.look_at(Vector3.ZERO)
|
|
await process_frame
|
|
await RenderingServer.frame_post_draw
|
|
var pixels := viewport.get_texture().get_image()
|
|
var width := 0
|
|
for x in 128:
|
|
if pixels.get_pixel(x, 64).r > 0.5: width += 1
|
|
# Default width .64m: 2FACE projects cos(30deg), 3FACE includes a full front face.
|
|
var expected := 64.0 * (cos(PI / 6) if kind == 4 else 1.0)
|
|
check(absf(width - expected) <= 3.0, "Metal projection kind=%d camera=%f width=%d expected=%f" % [kind, angle, width, expected])
|
|
viewport.free()
|
|
await process_frame
|