feat: more rotation gizmo improvements
This commit is contained in:
Binary file not shown.
@@ -8,9 +8,15 @@ class _Gizmo {
|
|||||||
final ThermionViewer viewer;
|
final ThermionViewer viewer;
|
||||||
final GizmoAsset _gizmo;
|
final GizmoAsset _gizmo;
|
||||||
ThermionEntity? _attachedTo;
|
ThermionEntity? _attachedTo;
|
||||||
final GizmoType type;
|
|
||||||
|
|
||||||
_Gizmo(this._gizmo, this.viewer, this.type);
|
final GizmoType _gizmoType;
|
||||||
|
|
||||||
|
_Gizmo(this._gizmo, this.viewer, this._gizmoType);
|
||||||
|
|
||||||
|
static Future<_Gizmo> forType(ThermionViewer viewer, GizmoType type) async {
|
||||||
|
final view = await viewer.getViewAt(0);
|
||||||
|
return _Gizmo(await viewer.createGizmo(view, type), viewer, type);
|
||||||
|
}
|
||||||
|
|
||||||
final _onEntityTransformUpdated = StreamController<
|
final _onEntityTransformUpdated = StreamController<
|
||||||
({ThermionEntity entity, Matrix4 transform})>.broadcast();
|
({ThermionEntity entity, Matrix4 transform})>.broadcast();
|
||||||
@@ -18,7 +24,6 @@ class _Gizmo {
|
|||||||
Axis? _active;
|
Axis? _active;
|
||||||
Axis? get active => _active;
|
Axis? get active => _active;
|
||||||
|
|
||||||
|
|
||||||
double _getAngleBetweenVectors(Vector2 v1, Vector2 v2) {
|
double _getAngleBetweenVectors(Vector2 v1, Vector2 v2) {
|
||||||
// Normalize vectors to ensure consistent rotation regardless of distance from center
|
// Normalize vectors to ensure consistent rotation regardless of distance from center
|
||||||
v1.normalize();
|
v1.normalize();
|
||||||
@@ -87,9 +92,9 @@ class _Gizmo {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == GizmoType.translation) {
|
if (_gizmoType == GizmoType.translation) {
|
||||||
await _updateTranslation(currentPosition, delta);
|
await _updateTranslation(currentPosition, delta);
|
||||||
} else if (type == GizmoType.rotation) {
|
} else if (_gizmoType == GizmoType.rotation) {
|
||||||
await _updateRotation(currentPosition, delta);
|
await _updateRotation(currentPosition, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +102,8 @@ class _Gizmo {
|
|||||||
.add((entity: _attachedTo!, transform: gizmoTransform!));
|
.add((entity: _attachedTo!, transform: gizmoTransform!));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateTranslation(Vector2 currentPosition, Vector2 delta) async {
|
Future<void> _updateTranslation(
|
||||||
|
Vector2 currentPosition, Vector2 delta) async {
|
||||||
var view = await viewer.getViewAt(0);
|
var view = await viewer.getViewAt(0);
|
||||||
var camera = await viewer.getActiveCamera();
|
var camera = await viewer.getActiveCamera();
|
||||||
var viewport = await view.getViewport();
|
var viewport = await view.getViewport();
|
||||||
@@ -115,17 +121,13 @@ class _Gizmo {
|
|||||||
|
|
||||||
var gizmoNdc = gizmoClipSpace / gizmoClipSpace.w;
|
var gizmoNdc = gizmoClipSpace / gizmoClipSpace.w;
|
||||||
|
|
||||||
var gizmoScreenSpace = Vector2(
|
var gizmoScreenSpace = Vector2(((gizmoNdc.x / 2) + 0.5) * viewport.width,
|
||||||
((gizmoNdc.x / 2) + 0.5) * viewport.width,
|
|
||||||
viewport.height - (((gizmoNdc.y / 2) + 0.5) * viewport.height));
|
viewport.height - (((gizmoNdc.y / 2) + 0.5) * viewport.height));
|
||||||
|
|
||||||
gizmoScreenSpace += delta;
|
gizmoScreenSpace += delta;
|
||||||
|
|
||||||
gizmoNdc = Vector4(
|
gizmoNdc = Vector4(((gizmoScreenSpace.x / viewport.width) - 0.5) * 2,
|
||||||
((gizmoScreenSpace.x / viewport.width) - 0.5) * 2,
|
(((gizmoScreenSpace.y / viewport.height)) - 0.5) * -2, gizmoNdc.z, 1.0);
|
||||||
(((gizmoScreenSpace.y / viewport.height)) - 0.5) * -2,
|
|
||||||
gizmoNdc.z,
|
|
||||||
1.0);
|
|
||||||
|
|
||||||
var gizmoViewSpace = inverseProjectionMatrix * gizmoNdc;
|
var gizmoViewSpace = inverseProjectionMatrix * gizmoNdc;
|
||||||
gizmoViewSpace /= gizmoViewSpace.w;
|
gizmoViewSpace /= gizmoViewSpace.w;
|
||||||
@@ -142,7 +144,6 @@ class _Gizmo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateRotation(Vector2 currentPosition, Vector2 delta) async {
|
Future<void> _updateRotation(Vector2 currentPosition, Vector2 delta) async {
|
||||||
|
|
||||||
var view = await viewer.getViewAt(0);
|
var view = await viewer.getViewAt(0);
|
||||||
var camera = await viewer.getActiveCamera();
|
var camera = await viewer.getActiveCamera();
|
||||||
var viewport = await view.getViewport();
|
var viewport = await view.getViewport();
|
||||||
@@ -157,8 +158,7 @@ class _Gizmo {
|
|||||||
gizmoPositionWorldSpace.z, 1.0);
|
gizmoPositionWorldSpace.z, 1.0);
|
||||||
|
|
||||||
var gizmoNdc = gizmoClipSpace / gizmoClipSpace.w;
|
var gizmoNdc = gizmoClipSpace / gizmoClipSpace.w;
|
||||||
var gizmoScreenSpace = Vector2(
|
var gizmoScreenSpace = Vector2(((gizmoNdc.x / 2) + 0.5) * viewport.width,
|
||||||
((gizmoNdc.x / 2) + 0.5) * viewport.width,
|
|
||||||
viewport.height - (((gizmoNdc.y / 2) + 0.5) * viewport.height));
|
viewport.height - (((gizmoNdc.y / 2) + 0.5) * viewport.height));
|
||||||
|
|
||||||
// Calculate vectors from gizmo center to previous and current mouse positions
|
// Calculate vectors from gizmo center to previous and current mouse positions
|
||||||
@@ -207,23 +207,48 @@ class _Gizmo {
|
|||||||
// Apply rotation to the current transform
|
// Apply rotation to the current transform
|
||||||
gizmoTransform = rotationMatrix * gizmoTransform!;
|
gizmoTransform = rotationMatrix * gizmoTransform!;
|
||||||
await viewer.setTransform(_attachedTo!, gizmoTransform!);
|
await viewer.setTransform(_attachedTo!, gizmoTransform!);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class GizmoInputHandler extends InputHandler {
|
class GizmoInputHandler extends InputHandler {
|
||||||
final InputHandler wrapped;
|
final InputHandler wrapped;
|
||||||
final ThermionViewer viewer;
|
final ThermionViewer viewer;
|
||||||
late final _Gizmo translationGizmo;
|
|
||||||
late final _Gizmo rotationGizmo;
|
|
||||||
_Gizmo get active =>
|
|
||||||
type == GizmoType.translation ? translationGizmo : rotationGizmo;
|
|
||||||
GizmoType type = GizmoType.translation;
|
|
||||||
|
|
||||||
|
late final _gizmos = <GizmoType, _Gizmo>{};
|
||||||
|
_Gizmo? active;
|
||||||
|
StreamSubscription? _entityTransformUpdatedListener;
|
||||||
|
|
||||||
|
GizmoType? getGizmoType() {
|
||||||
|
return active?._gizmoType;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future setGizmoType(GizmoType? type) async {
|
||||||
|
if (type == null) {
|
||||||
|
await active?.detach();
|
||||||
|
active = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var target = _gizmos[type]!;
|
||||||
|
if (target != active) {
|
||||||
|
await _entityTransformUpdatedListener?.cancel();
|
||||||
|
if (active?._attachedTo != null) {
|
||||||
|
var attachedTo = active!._attachedTo!;
|
||||||
|
await active!.detach();
|
||||||
|
await target.attach(attachedTo);
|
||||||
|
}
|
||||||
|
active = target;
|
||||||
|
_entityTransformUpdatedListener =
|
||||||
|
active!._onEntityTransformUpdated.stream.listen((event) {
|
||||||
|
_transformUpdatedController.add(event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final _transformUpdatedController =
|
||||||
|
StreamController<({ThermionEntity entity, Matrix4 transform})>();
|
||||||
Stream<({ThermionEntity entity, Matrix4 transform})>
|
Stream<({ThermionEntity entity, Matrix4 transform})>
|
||||||
get onEntityTransformUpdated =>
|
get onEntityTransformUpdated => _transformUpdatedController.stream;
|
||||||
translationGizmo._onEntityTransformUpdated.stream;
|
|
||||||
|
|
||||||
GizmoInputHandler({required this.wrapped, required this.viewer}) {
|
GizmoInputHandler({required this.wrapped, required this.viewer}) {
|
||||||
initialize();
|
initialize();
|
||||||
@@ -236,13 +261,12 @@ class GizmoInputHandler extends InputHandler {
|
|||||||
throw Exception("Already initialized");
|
throw Exception("Already initialized");
|
||||||
}
|
}
|
||||||
await viewer.initialized;
|
await viewer.initialized;
|
||||||
final view = await viewer.getViewAt(0);
|
|
||||||
|
|
||||||
var tg = await viewer.createGizmo(view, GizmoType.translation);
|
|
||||||
this.translationGizmo = _Gizmo(tg, viewer, GizmoType.translation);
|
|
||||||
var rg = await viewer.createGizmo(view, GizmoType.rotation);
|
|
||||||
this.rotationGizmo = _Gizmo(rg, viewer, GizmoType.rotation);
|
|
||||||
|
|
||||||
|
_gizmos[GizmoType.translation] =
|
||||||
|
await _Gizmo.forType(viewer, GizmoType.translation);
|
||||||
|
_gizmos[GizmoType.rotation] =
|
||||||
|
await _Gizmo.forType(viewer, GizmoType.rotation);
|
||||||
|
await setGizmoType(GizmoType.translation);
|
||||||
_initialized.complete(true);
|
_initialized.complete(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,8 +275,8 @@ class GizmoInputHandler extends InputHandler {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future dispose() async {
|
Future dispose() async {
|
||||||
await viewer.removeEntity(rotationGizmo._gizmo);
|
await viewer.removeEntity(_gizmos[GizmoType.rotation]!._gizmo);
|
||||||
await viewer.removeEntity(translationGizmo._gizmo);
|
await viewer.removeEntity(_gizmos[GizmoType.translation]!._gizmo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -288,13 +312,13 @@ class GizmoInputHandler extends InputHandler {
|
|||||||
|
|
||||||
await viewer.pick(localPosition.x.toInt(), localPosition.y.toInt(),
|
await viewer.pick(localPosition.x.toInt(), localPosition.y.toInt(),
|
||||||
(result) async {
|
(result) async {
|
||||||
if (active._gizmo.isNonPickable(result.entity) ||
|
if (active?._gizmo.isNonPickable(result.entity) == true ||
|
||||||
result.entity == FILAMENT_ENTITY_NULL) {
|
result.entity == FILAMENT_ENTITY_NULL) {
|
||||||
await active.detach();
|
await active!.detach();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!active._gizmo.isGizmoEntity(result.entity)) {
|
if (active?._gizmo.isGizmoEntity(result.entity) != true) {
|
||||||
active.attach(result.entity);
|
active!.attach(result.entity);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -304,19 +328,18 @@ class GizmoInputHandler extends InputHandler {
|
|||||||
if (!_initialized.isCompleted) {
|
if (!_initialized.isCompleted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
active.checkHover(
|
active?.checkHover(localPosition.x.floor(), localPosition.y.floor());
|
||||||
localPosition.x.floor(), localPosition.y.floor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> onPointerMove(
|
Future<void> onPointerMove(
|
||||||
Vector2 localPosition, Vector2 delta, bool isMiddle) async {
|
Vector2 localPosition, Vector2 delta, bool isMiddle) async {
|
||||||
if (!isMiddle && active._active != null) {
|
if (!isMiddle && active?._active != null) {
|
||||||
final scaledDelta = Vector2(
|
final scaledDelta = Vector2(
|
||||||
delta.x,
|
delta.x,
|
||||||
delta.y,
|
delta.y,
|
||||||
);
|
);
|
||||||
active._updateTransform(localPosition, scaledDelta);
|
active!._updateTransform(localPosition, scaledDelta);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return wrapped.onPointerMove(localPosition, delta, isMiddle);
|
return wrapped.onPointerMove(localPosition, delta, isMiddle);
|
||||||
@@ -364,14 +387,14 @@ class GizmoInputHandler extends InputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future detach(ThermionAsset asset) async {
|
Future detach(ThermionAsset asset) async {
|
||||||
if (active._attachedTo == asset.entity) {
|
if (active?._attachedTo == asset.entity) {
|
||||||
await active.detach();
|
await active!.detach();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final childEntities = await asset.getChildEntities();
|
final childEntities = await asset.getChildEntities();
|
||||||
for (final childEntity in childEntities) {
|
for (final childEntity in childEntities) {
|
||||||
if (active._attachedTo == childEntity) {
|
if (active?._attachedTo == childEntity) {
|
||||||
await active.detach();
|
await active!.detach();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ ROTATION_GIZMO_GLB_PACKAGE:
|
|||||||
ROTATION_GIZMO_GLB_ROTATION_GIZMO_OFFSET:
|
ROTATION_GIZMO_GLB_ROTATION_GIZMO_OFFSET:
|
||||||
.int 0
|
.int 0
|
||||||
ROTATION_GIZMO_GLB_ROTATION_GIZMO_SIZE:
|
ROTATION_GIZMO_GLB_ROTATION_GIZMO_SIZE:
|
||||||
.int 163152
|
.int 156056
|
||||||
|
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ _ROTATION_GIZMO_GLB_PACKAGE:
|
|||||||
_ROTATION_GIZMO_GLB_ROTATION_GIZMO_OFFSET:
|
_ROTATION_GIZMO_GLB_ROTATION_GIZMO_OFFSET:
|
||||||
.int 0
|
.int 0
|
||||||
_ROTATION_GIZMO_GLB_ROTATION_GIZMO_SIZE:
|
_ROTATION_GIZMO_GLB_ROTATION_GIZMO_SIZE:
|
||||||
.int 163152
|
.int 156056
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -201,10 +201,13 @@ namespace thermion
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(entity == axis->getEntity()) {
|
if (entity == axis->getEntity())
|
||||||
|
{
|
||||||
TRACE("MATCHED AXIS HEAD ENTITY");
|
TRACE("MATCHED AXIS HEAD ENTITY");
|
||||||
result = GizmoPickResultType(axisIndex);
|
result = GizmoPickResultType(axisIndex);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
for (int entityIndex = 0; entityIndex < axis->getChildEntityCount(); entityIndex++)
|
for (int entityIndex = 0; entityIndex < axis->getChildEntityCount(); entityIndex++)
|
||||||
{
|
{
|
||||||
auto childEntity = axis->getChildEntities()[entityIndex];
|
auto childEntity = axis->getChildEntities()[entityIndex];
|
||||||
|
|||||||
@@ -25,14 +25,25 @@ namespace thermion
|
|||||||
View *view,
|
View *view,
|
||||||
Scene *scene,
|
Scene *scene,
|
||||||
Material *material) noexcept : _source(sceneAsset),
|
Material *material) noexcept : _source(sceneAsset),
|
||||||
_engine(engine),
|
_engine(engine),
|
||||||
_view(view),
|
_view(view),
|
||||||
_scene(scene),
|
_scene(scene),
|
||||||
_material(material)
|
_material(material)
|
||||||
{
|
{
|
||||||
auto &entityManager = _engine->getEntityManager();
|
auto &entityManager = _engine->getEntityManager();
|
||||||
|
|
||||||
_parent = entityManager.create();
|
_parent = entityManager.create();
|
||||||
|
RenderableManager::Builder(1) // 1 primitive
|
||||||
|
.boundingBox({{-1, -1, -1}, {1, 1, 1}}) // Set a basic bounding box
|
||||||
|
.culling(false) // Disable culling since this is a UI element
|
||||||
|
.castShadows(false) // UI elements typically don't cast shadows
|
||||||
|
.receiveShadows(false)
|
||||||
|
|
||||||
|
.build(*_engine, _parent); // Bu
|
||||||
|
auto &tm = _engine->getTransformManager();
|
||||||
|
auto parentTransformInstance = tm.getInstance(_parent);
|
||||||
|
tm.setTransform(parentTransformInstance, math::mat4f());
|
||||||
|
|
||||||
TRACE("Created Gizmo parent entity %d", _parent);
|
TRACE("Created Gizmo parent entity %d", _parent);
|
||||||
_entities.push_back(_parent);
|
_entities.push_back(_parent);
|
||||||
|
|
||||||
@@ -71,7 +82,6 @@ namespace thermion
|
|||||||
auto instance = _source->createInstance(&materialInstance, 1);
|
auto instance = _source->createInstance(&materialInstance, 1);
|
||||||
|
|
||||||
TRACE("Created Gizmo axis glTF instance with head entity %d", instance->getEntity());
|
TRACE("Created Gizmo axis glTF instance with head entity %d", instance->getEntity());
|
||||||
|
|
||||||
materialInstance->setParameter("baseColorFactor", inactiveColors[axis]);
|
materialInstance->setParameter("baseColorFactor", inactiveColors[axis]);
|
||||||
materialInstance->setParameter("scale", _scale);
|
materialInstance->setParameter("scale", _scale);
|
||||||
|
|
||||||
@@ -109,7 +119,15 @@ namespace thermion
|
|||||||
tm.setTransform(transformInstance, transform);
|
tm.setTransform(transformInstance, transform);
|
||||||
|
|
||||||
// parent this entity's transform to the Gizmo _parent entity
|
// parent this entity's transform to the Gizmo _parent entity
|
||||||
tm.setParent(transformInstance, tm.getInstance(_parent));
|
auto parentTransformInstance = tm.getInstance(_parent);
|
||||||
|
if (parentTransformInstance.isValid())
|
||||||
|
{
|
||||||
|
tm.setParent(transformInstance, parentTransformInstance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACE("WARNING: parent transform instance not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
_entities.push_back(instance->getEntity());
|
_entities.push_back(instance->getEntity());
|
||||||
|
|
||||||
@@ -120,6 +138,11 @@ namespace thermion
|
|||||||
auto entity = instance->getChildEntities()[i];
|
auto entity = instance->getChildEntities()[i];
|
||||||
_entities.push_back(entity);
|
_entities.push_back(entity);
|
||||||
TRACE("Added entity %d for axis %d", entity, axis);
|
TRACE("Added entity %d for axis %d", entity, axis);
|
||||||
|
auto renderable = rm.getInstance(entity);
|
||||||
|
if (renderable.isValid())
|
||||||
|
{
|
||||||
|
rm.setPriority(renderable, 7);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_axes.push_back(instance);
|
_axes.push_back(instance);
|
||||||
|
|||||||
@@ -9,27 +9,81 @@ void main() async {
|
|||||||
final testHelper = TestHelper("gizmo");
|
final testHelper = TestHelper("gizmo");
|
||||||
|
|
||||||
group("gizmo tests", () {
|
group("gizmo tests", () {
|
||||||
test('add gizmo', () async {
|
test('add/remove translation gizmo', () async {
|
||||||
await testHelper.withViewer((viewer) async {
|
await testHelper.withViewer((viewer) async {
|
||||||
|
var cameraPos = Vector3(1.5, 1.5, 3);
|
||||||
var modelMatrix =
|
var modelMatrix =
|
||||||
makeViewMatrix(Vector3(0.5, 0.5, 0.5), Vector3.zero(), Vector3(0, 1, 0));
|
makeViewMatrix(cameraPos, Vector3.zero(), Vector3(0, 1, 0));
|
||||||
modelMatrix.invert();
|
modelMatrix.invert();
|
||||||
await viewer.setCameraModelMatrix4(modelMatrix);
|
await viewer.setCameraModelMatrix4(modelMatrix);
|
||||||
|
|
||||||
final view = await viewer.getViewAt(0);
|
final view = await viewer.getViewAt(0);
|
||||||
|
await viewer.showGridOverlay();
|
||||||
final gizmo = await viewer.createGizmo(view, GizmoType.translation);
|
final gizmo = await viewer.createGizmo(view, GizmoType.translation);
|
||||||
await viewer.setLayerVisibility(VisibilityLayers.OVERLAY, true);
|
await viewer.setLayerVisibility(VisibilityLayers.OVERLAY, true);
|
||||||
await gizmo.addToScene();
|
await gizmo.addToScene();
|
||||||
await testHelper.capture(
|
await testHelper.capture(viewer, "translation_gizmo_near");
|
||||||
viewer, "gizmo_added_to_scene_unattached_close");
|
|
||||||
|
|
||||||
modelMatrix =
|
modelMatrix = makeViewMatrix(
|
||||||
makeViewMatrix(Vector3(0.5, 0.5, 0.5).scaled(10), Vector3.zero(), Vector3(0, 1, 0));
|
cameraPos.scaled(10), Vector3.zero(), Vector3(0, 1, 0));
|
||||||
modelMatrix.invert();
|
modelMatrix.invert();
|
||||||
await viewer.setCameraModelMatrix4(modelMatrix);
|
await viewer.setCameraModelMatrix4(modelMatrix);
|
||||||
|
|
||||||
// gizmo occupies same viewport size no matter the camera position
|
// gizmo occupies same viewport size no matter the camera position
|
||||||
await testHelper.capture(viewer, "gizmo_added_to_scene_unattached_far");
|
await testHelper.capture(viewer, "translation_gizmo_far");
|
||||||
|
|
||||||
|
await gizmo.removeFromScene();
|
||||||
|
|
||||||
|
await testHelper.capture(viewer, "translation_gizmo_removed");
|
||||||
|
}, postProcessing: true, bg: kWhite);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('add/remove rotation gizmo', () async {
|
||||||
|
await testHelper.withViewer((viewer) async {
|
||||||
|
var cameraPos = Vector3(1.5, 1.5, 3);
|
||||||
|
var modelMatrix =
|
||||||
|
makeViewMatrix(cameraPos, Vector3.zero(), Vector3(0, 1, 0));
|
||||||
|
modelMatrix.invert();
|
||||||
|
await viewer.setCameraModelMatrix4(modelMatrix);
|
||||||
|
|
||||||
|
final view = await viewer.getViewAt(0);
|
||||||
|
await viewer.showGridOverlay();
|
||||||
|
final gizmo = await viewer.createGizmo(view, GizmoType.rotation);
|
||||||
|
await viewer.setLayerVisibility(VisibilityLayers.OVERLAY, true);
|
||||||
|
await gizmo.addToScene();
|
||||||
|
await testHelper.capture(viewer, "rotation_gizmo_near");
|
||||||
|
|
||||||
|
modelMatrix = makeViewMatrix(
|
||||||
|
cameraPos.scaled(10), Vector3.zero(), Vector3(0, 1, 0));
|
||||||
|
modelMatrix.invert();
|
||||||
|
await viewer.setCameraModelMatrix4(modelMatrix);
|
||||||
|
|
||||||
|
// gizmo occupies same viewport size no matter the camera position
|
||||||
|
await testHelper.capture(viewer, "rotation_gizmo_far");
|
||||||
|
|
||||||
|
await gizmo.removeFromScene();
|
||||||
|
|
||||||
|
await testHelper.capture(viewer, "rotation_gizmo_removed");
|
||||||
|
}, postProcessing: true, bg: kWhite);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('set gizmo transform', () async {
|
||||||
|
await testHelper.withViewer((viewer) async {
|
||||||
|
var cameraPos = Vector3(1.5, 1.5, 3);
|
||||||
|
var modelMatrix =
|
||||||
|
makeViewMatrix(cameraPos, Vector3.zero(), Vector3(0, 1, 0));
|
||||||
|
modelMatrix.invert();
|
||||||
|
await viewer.setCameraModelMatrix4(modelMatrix);
|
||||||
|
|
||||||
|
final view = await viewer.getViewAt(0);
|
||||||
|
await viewer.showGridOverlay();
|
||||||
|
final gizmo = await viewer.createGizmo(view, GizmoType.translation);
|
||||||
|
await viewer.setLayerVisibility(VisibilityLayers.OVERLAY, true);
|
||||||
|
await gizmo.addToScene();
|
||||||
|
|
||||||
|
await viewer.setTransform(gizmo.entity, Matrix4.translation(Vector3(0,2,0)));
|
||||||
|
|
||||||
|
await testHelper.capture(viewer, "translation_gizmo_transformed");
|
||||||
}, postProcessing: true, bg: kWhite);
|
}, postProcessing: true, bg: kWhite);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -60,7 +114,7 @@ void main() async {
|
|||||||
}, postProcessing: true, bg: kWhite);
|
}, postProcessing: true, bg: kWhite);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('pick gizmo when added to scene', () async {
|
test('pick translation gizmo when added to scene', () async {
|
||||||
await testHelper.withViewer((viewer) async {
|
await testHelper.withViewer((viewer) async {
|
||||||
await viewer.setCameraPosition(0, 0, 1);
|
await viewer.setCameraPosition(0, 0, 1);
|
||||||
final view = await viewer.getViewAt(0);
|
final view = await viewer.getViewAt(0);
|
||||||
@@ -73,7 +127,7 @@ void main() async {
|
|||||||
|
|
||||||
await testHelper.capture(viewer, "gizmo_before_pick_no_highlight");
|
await testHelper.capture(viewer, "gizmo_before_pick_no_highlight");
|
||||||
|
|
||||||
await gizmo.pick(viewport.width ~/ 2, viewport.height ~/ 2 + 1,
|
await gizmo.pick(viewport.width ~/ 2 + 100, viewport.height ~/ 2,
|
||||||
handler: (resultType, coords) async {
|
handler: (resultType, coords) async {
|
||||||
completer.complete(resultType);
|
completer.complete(resultType);
|
||||||
});
|
});
|
||||||
@@ -86,17 +140,18 @@ void main() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(completer.isCompleted);
|
assert(completer.isCompleted);
|
||||||
|
expect(await completer.future, GizmoPickResultType.AxisX);
|
||||||
}, postProcessing: true, bg: kWhite);
|
}, postProcessing: true, bg: kWhite);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('highlight/unhighlight gizmo', () async {
|
test('highlight/unhighlight gizmo', () async {
|
||||||
await testHelper.withViewer((viewer) async {
|
await testHelper.withViewer((viewer) async {
|
||||||
final modelMatrix =
|
final modelMatrix = makeViewMatrix(
|
||||||
makeViewMatrix(Vector3(0.5, 0.5, 0.5), Vector3.zero(), Vector3(0, 1, 0));
|
Vector3(0.5, 0.5, 0.5), Vector3.zero(), Vector3(0, 1, 0));
|
||||||
modelMatrix.invert();
|
modelMatrix.invert();
|
||||||
await viewer.setCameraModelMatrix4(modelMatrix);
|
await viewer.setCameraModelMatrix4(modelMatrix);
|
||||||
final view = await viewer.getViewAt(0);
|
final view = await viewer.getViewAt(0);
|
||||||
final viewport = await view.getViewport();
|
|
||||||
final gizmo = await viewer.createGizmo(view, GizmoType.translation);
|
final gizmo = await viewer.createGizmo(view, GizmoType.translation);
|
||||||
await gizmo.addToScene();
|
await gizmo.addToScene();
|
||||||
await viewer.setLayerVisibility(VisibilityLayers.OVERLAY, true);
|
await viewer.setLayerVisibility(VisibilityLayers.OVERLAY, true);
|
||||||
|
|||||||
Reference in New Issue
Block a user