New AcDream.Core.Selection.WorldPicker static helper. BuildRay unprojects pixel (mouseX, mouseY) through a view+projection matrix pair into a world-space (origin, direction) ray. Used by GameWindow.OnInputAction to drive entity picking on click. Pure math, no state, no DI. Composes view*projection (System.Numerics row-vector convention, matching the rest of acdream's camera path — see GameWindow.cs:6445 FrustumPlanes.FromViewProjection). 2 xUnit tests cover center-of-viewport (forward ray) and right-of-center (positive-X deflection). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
54 lines
1.7 KiB
C#
54 lines
1.7 KiB
C#
using System;
|
|
using System.Numerics;
|
|
using AcDream.Core.Selection;
|
|
using Xunit;
|
|
|
|
namespace AcDream.Core.Tests.Selection;
|
|
|
|
public class WorldPickerTests
|
|
{
|
|
private const float Epsilon = 0.01f;
|
|
|
|
private static (Matrix4x4 View, Matrix4x4 Projection) MakeIdentityCamera()
|
|
{
|
|
var view = Matrix4x4.Identity;
|
|
var proj = Matrix4x4.CreatePerspectiveFieldOfView(
|
|
fieldOfView: MathF.PI / 3f,
|
|
aspectRatio: 16f / 9f,
|
|
nearPlaneDistance: 0.1f,
|
|
farPlaneDistance: 100f);
|
|
return (view, proj);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildRay_CenterOfViewport_ReturnsForwardRay()
|
|
{
|
|
var (view, proj) = MakeIdentityCamera();
|
|
const float vpW = 1920f, vpH = 1080f;
|
|
|
|
var (_, direction) = WorldPicker.BuildRay(
|
|
mouseX: vpW / 2f, mouseY: vpH / 2f,
|
|
viewportW: vpW, viewportH: vpH,
|
|
view, proj);
|
|
|
|
// Right-handed perspective + identity view -> camera looks down -Z.
|
|
// Center pixel ray = (0, 0, -1) within float epsilon.
|
|
Assert.True(MathF.Abs(direction.X) < Epsilon, $"direction.X = {direction.X}");
|
|
Assert.True(MathF.Abs(direction.Y) < Epsilon, $"direction.Y = {direction.Y}");
|
|
Assert.True(direction.Z < -0.99f, $"direction.Z = {direction.Z}");
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildRay_OffsetMouseRight_DeflectsRayPositiveX()
|
|
{
|
|
var (view, proj) = MakeIdentityCamera();
|
|
const float vpW = 1920f, vpH = 1080f;
|
|
|
|
var (_, direction) = WorldPicker.BuildRay(
|
|
mouseX: vpW * 0.75f, mouseY: vpH / 2f,
|
|
viewportW: vpW, viewportH: vpH,
|
|
view, proj);
|
|
|
|
Assert.True(direction.X > 0.1f, $"direction.X = {direction.X} (expected > 0.1)");
|
|
}
|
|
}
|