From f78c907c976583f8c6e6f74d272bf90b04f346a8 Mon Sep 17 00:00:00 2001
From: salahchafai <64394387+salahchafai@users.noreply.github.com>
Date: Thu, 1 Jul 2021 02:24:45 +0100
Subject: [PATCH 1/3] Improve the editor gizmos
---
.../AssetEditors/Gizmos/AxialGizmo.cs | 54 +++-
.../AssetEditors/Gizmos/CameraGizmo.cs | 2 +-
.../Gizmos/CameraOrientationGizmo.cs | 42 +--
.../Gizmos/GizmoEmissiveColorMaterial.cs | 12 +-
.../Gizmos/GizmoShaderMaterial.cs | 27 ++
.../Gizmos/GizmoUniformColorMaterial.cs | 17 +-
.../Gizmos/LightDirectionalGizmo.cs | 4 +-
.../AssetEditors/Gizmos/LightPointGizmo.cs | 4 +-
.../AssetEditors/Gizmos/LightSpotGizmo.cs | 4 +-
.../Gizmos/NavigationBoundingBoxGizmo.cs | 2 +-
.../AssetEditors/Gizmos/RotationGizmo.cs | 63 +++--
.../AssetEditors/Gizmos/ScaleGizmo.cs | 255 +++++++++++++++---
.../Gizmos/TransformationGizmo.cs | 20 +-
.../AssetEditors/Gizmos/TranslationGizmo.cs | 46 ++--
.../AssetEditors/Gizmos/VoxelVolumeGizmo.cs | 2 +-
.../SceneEditor/SceneEditorSettings.cs | 6 +
.../Editor/CameraOrientationGizmoShader.sdsl | 11 +
17 files changed, 427 insertions(+), 144 deletions(-)
create mode 100644 sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoShaderMaterial.cs
create mode 100644 sources/engine/Stride.Rendering/Rendering/Editor/CameraOrientationGizmoShader.sdsl
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/AxialGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/AxialGizmo.cs
index a6c7848ce7..9b6da57648 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/AxialGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/AxialGizmo.cs
@@ -45,12 +45,32 @@ protected AxialGizmo()
protected override Entity Create()
{
- RedUniformMaterial = CreateUniformColorMaterial(RedUniformColor);
- GreenUniformMaterial = CreateUniformColorMaterial(GreenUniformColor);
- BlueUniformMaterial = CreateUniformColorMaterial(BlueUniformColor);
+ RedUniformMaterial = CreateEmissiveColorMaterial(RedUniformColor);
+ GreenUniformMaterial = CreateEmissiveColorMaterial(GreenUniformColor);
+ BlueUniformMaterial = CreateEmissiveColorMaterial(BlueUniformColor);
return null;
}
+ ///
+ /// Gets the default color associated to the provided axis index.
+ ///
+ /// The index of the axis
+ /// The default color associated
+ protected Color GetAxisDefaultColor(int axisIndex)
+ {
+ switch (axisIndex)
+ {
+ case 0:
+ return RedUniformColor;
+ case 1:
+ return GreenUniformColor;
+ case 2:
+ return BlueUniformColor;
+ default:
+ throw new ArgumentOutOfRangeException("axisIndex");
+ }
+ }
+
///
/// Gets the default material associated to the provided axis index.
///
@@ -78,16 +98,36 @@ protected Material GetAxisDefaultMaterial(int axisIndex)
/// the material
protected Material CreateUniformColorMaterial(Color color)
{
- return GizmoUniformColorMaterial.Create(GraphicsDevice, color, false);
+ return GizmoUniformColorMaterial.Create(GraphicsDevice, color);
+ }
+
+ ///
+ /// Creates an emissive color material.
+ ///
+ /// The color of the material
+ /// the material
+ protected Material CreateEmissiveColorMaterial(Color color)
+ {
+ return GizmoEmissiveColorMaterial.Create(GraphicsDevice, color, 0.75f);
+ }
+
+ ///
+ /// Creates a material from a shader.
+ ///
+ /// the shader's name
+ /// the material
+ protected Material CreateShaderMaterial(string shaderName)
+ {
+ return GizmoShaderMaterial.Create(GraphicsDevice, shaderName);
}
protected virtual void UpdateColors()
{
if (IsEnabled && RedUniformMaterial != null)
{
- GizmoUniformColorMaterial.UpdateColor(GraphicsDevice, RedUniformMaterial, RedUniformColor);
- GizmoUniformColorMaterial.UpdateColor(GraphicsDevice, GreenUniformMaterial, GreenUniformColor);
- GizmoUniformColorMaterial.UpdateColor(GraphicsDevice, BlueUniformMaterial, BlueUniformColor);
+ GizmoEmissiveColorMaterial.UpdateColor(GraphicsDevice, RedUniformMaterial, RedUniformColor);
+ GizmoEmissiveColorMaterial.UpdateColor(GraphicsDevice, GreenUniformMaterial, GreenUniformColor);
+ GizmoEmissiveColorMaterial.UpdateColor(GraphicsDevice, BlueUniformMaterial, BlueUniformColor);
}
}
}
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/CameraGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/CameraGizmo.cs
index 2b3ec6ffc4..9d3c7e23dc 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/CameraGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/CameraGizmo.cs
@@ -63,7 +63,7 @@ protected override Entity Create()
frustumMesh = new CameraFrustumMesh(GraphicsDevice);
frustumMesh.Build(GraphicsCommandList, cameraParameters);
- var frustumMaterial = GizmoUniformColorMaterial.Create(GraphicsDevice, new Color(0.75f, 0.75f, 1f, 1f));
+ var frustumMaterial = GizmoEmissiveColorMaterial.Create(GraphicsDevice, new Color(0.75f, 0.75f, 1f, 1f));
frustum = new Entity("Camera frustumMesh of {0}".ToFormat(root.Id))
{
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/CameraOrientationGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/CameraOrientationGizmo.cs
index ca11744931..d87439f18c 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/CameraOrientationGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/CameraOrientationGizmo.cs
@@ -16,6 +16,7 @@
using Stride.Graphics.GeometricPrimitives;
using Stride.Rendering;
using Stride.Rendering.Compositing;
+using Stride.Assets.Presentation.SceneEditor;
namespace Stride.Assets.Presentation.AssetEditors.Gizmos
{
@@ -36,12 +37,12 @@ public class CameraOrientationGizmo : AxialGizmo
private static readonly FaceData[] Faces =
{
- new FaceData("Right", new Vector3(0, MathUtil.PiOverTwo, 0)),
- new FaceData("Left", new Vector3(0, -MathUtil.PiOverTwo, 0)),
- new FaceData("Top", new Vector3(-MathUtil.PiOverTwo, 0, 0)),
- new FaceData("Bottom", new Vector3(MathUtil.PiOverTwo, 0, 0)),
- new FaceData("Back", Vector3.Zero),
- new FaceData("Front", new Vector3(0, MathUtil.Pi, 0))
+ new FaceData("Right", "X", new Vector3(0, MathUtil.PiOverTwo, 0)),
+ new FaceData("Left", "-X", new Vector3(0, -MathUtil.PiOverTwo, 0)),
+ new FaceData("Top", "Y", new Vector3(-MathUtil.PiOverTwo, 0, 0)),
+ new FaceData("Bottom", "-Y", new Vector3(MathUtil.PiOverTwo, 0, 0)),
+ new FaceData("Back", "-Z", Vector3.Zero),
+ new FaceData("Front", "Z", new Vector3(0, MathUtil.Pi, 0))
};
///
@@ -58,9 +59,11 @@ public class CameraOrientationGizmo : AxialGizmo
///
private const int DefaultSize = 25;
- private const float FontSize = 7;
+ private const float FontSize = 25;
- private const float TextScale = 0.08f;
+ private const float NameIndicatorScale = 0.08f;
+
+ private const float XYZIndicatorScale = 0.18f;
private const float OuterExtent = 0.25f;
@@ -227,8 +230,8 @@ protected override Entity Create()
{
base.Create();
- DefaultMaterial = CreateUniformColorMaterial(Color.White);
- ElementSelectedMaterial = CreateUniformColorMaterial(Color.Gold);
+ DefaultMaterial = CreateShaderMaterial("CameraOrientationGizmoShader");
+ ElementSelectedMaterial = CreateEmissiveColorMaterial(Color.Gray);
var entity = new Entity("View Gizmo");
cameraComponent = new CameraComponent
@@ -250,7 +253,7 @@ protected override Entity Create()
// create the sprite batch use to draw text
spriteBatch = new SpriteBatch(GraphicsDevice) { DefaultDepth = 1 };
- // Add a renderer on the top right size
+ // Add a renderer on the top right side
var cameraOrientationGizmoRenderStage = new RenderStage("CameraOrientationGizmo", "Main");
game.EditorSceneSystem.GraphicsCompositor.RenderStages.Add(cameraOrientationGizmoRenderStage);
@@ -320,13 +323,17 @@ private void RenderFaceNames(RenderDrawContext context)
var textureToWorldSpace = Matrix.RotationX(MathUtil.Pi) * Matrix.Translation(0, 0, OuterExtent);
- foreach (var face in Faces)
+ var displayDirectionNames = SceneEditorSettings.DisplayDirectionNames.GetValue();
+
+ var textScale = displayDirectionNames ? NameIndicatorScale : XYZIndicatorScale;
+
+ for (int i = 0; i < Faces.Count(); i++)
{
- var text = face.Name.ToUpperInvariant();
+ var text = displayDirectionNames ? Faces[i].Name.ToUpperInvariant() : Faces[i].XYZComponent;
- spriteBatch.Begin(context.GraphicsContext, textureToWorldSpace * face.Rotation * viewMatrix, projectionMatrix, SpriteSortMode.BackToFront, BlendStates.AlphaBlend, context.GraphicsDevice.SamplerStates.LinearClamp, DepthStencilStates.None);
+ spriteBatch.Begin(context.GraphicsContext, textureToWorldSpace * Faces[i].Rotation * viewMatrix, projectionMatrix, SpriteSortMode.BackToFront, BlendStates.AlphaBlend, context.GraphicsDevice.SamplerStates.LinearClamp, DepthStencilStates.None);
var textSize = spriteBatch.MeasureString(defaultFont, text, viewPortSize);
- spriteBatch.DrawString(defaultFont, text, Vector2.One * 0.5f, new Color(0, 0, 0, 0.8f), 0, textSize / 2, Vector2.One / FontSize * TextScale, SpriteEffects.None, 0, TextAlignment.Center);
+ spriteBatch.DrawString(defaultFont, text, Vector2.One * 0.5f, GetAxisDefaultColor(i / 2), 0, textSize / 2, Vector2.One / FontSize * textScale, SpriteEffects.None, 0, TextAlignment.Center);
spriteBatch.End();
}
@@ -336,11 +343,14 @@ struct FaceData
{
public readonly string Name;
+ public readonly string XYZComponent;
+
public readonly Matrix Rotation;
- public FaceData(string name, Vector3 angles)
+ public FaceData(string name, string xyzComponent, Vector3 angles)
{
Name = name;
+ XYZComponent = xyzComponent;
Rotation = Matrix.RotationYawPitchRoll(angles.Y, angles.X, angles.Z);
}
}
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoEmissiveColorMaterial.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoEmissiveColorMaterial.cs
index d632f398a2..9d8e927658 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoEmissiveColorMaterial.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoEmissiveColorMaterial.cs
@@ -10,7 +10,7 @@ namespace Stride.Assets.Presentation.AssetEditors.Gizmos
{
public static class GizmoEmissiveColorMaterial
{
- public static Material Create(GraphicsDevice device, Color color, float intensity)
+ public static Material Create(GraphicsDevice device, Color color, float intensity = 1f)
{
var material = Material.New(device, new MaterialDescriptor
{
@@ -22,13 +22,19 @@ public static Material Create(GraphicsDevice device, Color color, float intensit
}
});
+ // set the color to the material
+ UpdateColor(device, material, color, intensity);
+
+ return material;
+ }
+
+ public static void UpdateColor(GraphicsDevice device, Material material, Color color, float intensity = 1f)
+ {
// set the color to the material
material.Passes[0].Parameters.Set(MaterialKeys.DiffuseValue, new Color4(color).ToColorSpace(device.ColorSpace));
material.Passes[0].Parameters.Set(MaterialKeys.EmissiveIntensity, intensity);
material.Passes[0].Parameters.Set(MaterialKeys.EmissiveValue, new Color4(color).ToColorSpace(device.ColorSpace));
-
- return material;
}
}
}
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoShaderMaterial.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoShaderMaterial.cs
new file mode 100644
index 0000000000..c2bf73d3e3
--- /dev/null
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoShaderMaterial.cs
@@ -0,0 +1,27 @@
+// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
+// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
+using Stride.Graphics;
+using Stride.Rendering;
+using Stride.Rendering.Materials;
+using Stride.Rendering.Materials.ComputeColors;
+
+namespace Stride.Assets.Presentation.AssetEditors.Gizmos
+{
+ public static class GizmoShaderMaterial
+ {
+ public static Material Create(GraphicsDevice device, string shaderName)
+ {
+ var material = Material.New(device, new MaterialDescriptor
+ {
+ Attributes =
+ {
+ Diffuse = new MaterialDiffuseMapFeature(new ComputeShaderClassColor() { MixinReference = shaderName }),
+ DiffuseModel = new MaterialDiffuseLambertModelFeature(),
+ Emissive = new MaterialEmissiveMapFeature(new ComputeShaderClassColor() { MixinReference = shaderName })
+ }
+ });
+
+ return material;
+ }
+ }
+}
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoUniformColorMaterial.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoUniformColorMaterial.cs
index 707fe14fec..a7d5644b8f 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoUniformColorMaterial.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/GizmoUniformColorMaterial.cs
@@ -11,20 +11,11 @@ namespace Stride.Assets.Presentation.AssetEditors.Gizmos
{
public static class GizmoUniformColorMaterial
{
- public static readonly ValueParameterKey GizmoColorKey = ParameterKeys.NewValue();
-
- public static Material Create(GraphicsDevice device, Color color, bool emissive = true)
+ public static Material Create(GraphicsDevice device, Color color)
{
var desc = new MaterialDescriptor();
- if (emissive)
- {
- desc.Attributes.Emissive = new MaterialEmissiveMapFeature(new ComputeColor() { Key = GizmoColorKey });
- }
- else
- {
- desc.Attributes.Diffuse = new MaterialDiffuseMapFeature(new ComputeColor() { Key = GizmoColorKey });
- desc.Attributes.DiffuseModel = new MaterialDiffuseLambertModelFeature();
- }
+ desc.Attributes.Diffuse = new MaterialDiffuseMapFeature(new ComputeColor());
+ desc.Attributes.DiffuseModel = new MaterialDiffuseLambertModelFeature();
var material = Material.New(device, desc);
@@ -46,7 +37,7 @@ public static Material Create(GraphicsDevice device, Color color, bool emissive
public static void UpdateColor(GraphicsDevice device, Material material, Color color)
{
// set the color to the material
- material.Passes[0].Parameters.Set(GizmoColorKey, new Color4(color).ToColorSpace(device.ColorSpace));
+ material.Passes[0].Parameters.Set(MaterialKeys.DiffuseValue, new Color4(color).ToColorSpace(device.ColorSpace));
}
}
}
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightDirectionalGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightDirectionalGizmo.cs
index 8d4adfcbf4..b514e2eb26 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightDirectionalGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightDirectionalGizmo.cs
@@ -33,7 +33,7 @@ protected override Entity Create()
var root = base.Create();
lightRay = new Entity($"Light ray for light gizmo {root.Id}");
- rayMaterial = GizmoUniformColorMaterial.Create(GraphicsDevice, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
+ rayMaterial = GizmoEmissiveColorMaterial.Create(GraphicsDevice, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
// build the ray mesh
var coneMesh = GeometricPrimitive.Cone.New(GraphicsDevice, ConeRadius, ConeHeight, GizmoTessellation).ToMeshDraw();
@@ -57,7 +57,7 @@ public override void Update()
base.Update();
// update the color of the ray
- GizmoUniformColorMaterial.UpdateColor(GraphicsDevice, rayMaterial, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
+ GizmoEmissiveColorMaterial.UpdateColor(GraphicsDevice, rayMaterial, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
}
public override bool IsSelected
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightPointGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightPointGizmo.cs
index d8f4feb4c5..ee78c59c64 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightPointGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightPointGizmo.cs
@@ -45,7 +45,7 @@ protected override Entity Create()
pointMesh= new LightPointMesh(GraphicsDevice);
pointMesh.Build();
- pointMaterial = GizmoUniformColorMaterial.Create(GraphicsDevice, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
+ pointMaterial = GizmoEmissiveColorMaterial.Create(GraphicsDevice, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
pointEntity = new Entity("Point Mesh of {0}".ToFormat(root.Id))
{
@@ -71,7 +71,7 @@ public override void Update()
pointEntity.Transform.Scale = new Vector3(LightPoint.Radius);
// update the spot color
- GizmoUniformColorMaterial.UpdateColor(GraphicsDevice, pointMaterial, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
+ GizmoEmissiveColorMaterial.UpdateColor(GraphicsDevice, pointMaterial, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
}
public override bool IsSelected
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightSpotGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightSpotGizmo.cs
index 043560ad53..17d9e12697 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightSpotGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/LightSpotGizmo.cs
@@ -57,7 +57,7 @@ protected override Entity Create()
spotMesh = new LightSpotMesh(GraphicsDevice);
spotMesh.Build(GraphicsCommandList, LightSpot);
- spotMaterial = GizmoUniformColorMaterial.Create(GraphicsDevice, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
+ spotMaterial = GizmoEmissiveColorMaterial.Create(GraphicsDevice, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
spotEntity = new Entity("Spot Mesh of {0}".ToFormat(root.Id))
{
@@ -113,7 +113,7 @@ public override void Update()
}
// update the spot color
- GizmoUniformColorMaterial.UpdateColor(GraphicsDevice, spotMaterial, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
+ GizmoEmissiveColorMaterial.UpdateColor(GraphicsDevice, spotMaterial, (Color)new Color4(GetLightColor(GraphicsDevice), 1f));
}
public override bool IsSelected
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/NavigationBoundingBoxGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/NavigationBoundingBoxGizmo.cs
index 0f8bc2ddba..f79735e501 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/NavigationBoundingBoxGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/NavigationBoundingBoxGizmo.cs
@@ -29,7 +29,7 @@ public NavigationBoundingBoxGizmo(EntityComponent component) : base(component)
protected override Entity Create()
{
- material = GizmoUniformColorMaterial.Create(GraphicsDevice, Color.CornflowerBlue);
+ material = GizmoEmissiveColorMaterial.Create(GraphicsDevice, Color.CornflowerBlue);
box = new BoxMesh(GraphicsDevice);
box.Build();
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs
index 222feeef77..e75338d0a0 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs
@@ -13,18 +13,25 @@ namespace Stride.Assets.Presentation.AssetEditors.Gizmos
public class RotationGizmo : TransformationGizmo
{
private const float RotationGizmoRadius = 1f; // the size of the radius of the torus used to rotate the objects
-
private const float RotationGizmoThickness = 0.02f; // the size of the inner radius torus used to rotate the objects
+ private const float OriginRadius = GizmoOriginScale * 0.05f;
private readonly Entity[] rotationAxes = new Entity[3];
+ private Material overlaySphereDefaultMaterial;
+ private Material overlaySphereSelectedMaterial;
+
+ private Entity overlaySphere;
+
protected override Entity Create()
{
base.Create();
+ overlaySphereDefaultMaterial = CreateUniformColorMaterial(new Color(0.3f, 0.3f, 0.3f, 0.025f));
+ overlaySphereSelectedMaterial = CreateUniformColorMaterial(new Color(0.4f, 0.4f, 0.4f, 0.025f));
+
var entity = new Entity("Rotation Gizmo");
- const float OriginSize = GizmoOriginScale * GizmoExtremitySize;
- var rotations = new[] { new Vector3(0, 0, MathUtil.Pi / 2), new Vector3(), new Vector3(MathUtil.Pi / 2, 0, 0) };
+ var rotations = new[] { new Vector3(0, 0, -MathUtil.Pi / 2), new Vector3(), new Vector3(MathUtil.Pi / 2, 0, 0) };
var bodyMesh = GeometricPrimitive.Torus.New(GraphicsDevice, RotationGizmoRadius, RotationGizmoThickness, GizmoTessellation).ToMeshDraw();
for (int axis = 0; axis < 3; ++axis)
@@ -35,10 +42,15 @@ protected override Entity Create()
entity.AddChild(rotationAxes[axis]);
}
+ // Add overlay sphere
+ var overlayMeshDraw = GeometricPrimitive.Sphere.New(GraphicsDevice, RotationGizmoRadius, GizmoTessellation).ToMeshDraw();
+ overlaySphere = new Entity("OverlaySphere") { new ModelComponent { Model = new Model { overlaySphereDefaultMaterial, new Mesh { Draw = overlayMeshDraw } }, RenderGroup = RenderGroup } };
+ entity.AddChild(overlaySphere);
+
// Add middle sphere
- var sphereMeshDraw = GeometricPrimitive.Sphere.New(GraphicsDevice, 0.25f * OriginSize, GizmoTessellation).ToMeshDraw();
- var sphereEntity = new Entity("OriginCube") { new ModelComponent { Model = new Model { DefaultOriginMaterial, new Mesh { Draw = sphereMeshDraw } }, RenderGroup = RenderGroup } };
- entity.AddChild(sphereEntity);
+ var sphereMeshDraw = GeometricPrimitive.Sphere.New(GraphicsDevice, OriginRadius, GizmoTessellation).ToMeshDraw();
+ var rotationOrigin = new Entity("OriginSphere") { new ModelComponent { Model = new Model { DefaultOriginMaterial, new Mesh { Draw = sphereMeshDraw } }, RenderGroup = RenderGroup } };
+ entity.Transform.Children.Add(rotationOrigin.Transform);
return entity;
}
@@ -125,6 +137,7 @@ protected override void UpdateTransformationAxis()
protected override void UpdateColors()
{
base.UpdateColors();
+
for (int axis = 0; axis < 3; axis++)
{
var axisMaterial = GetAxisDefaultMaterial(axis);
@@ -132,6 +145,8 @@ protected override void UpdateColors()
bool isSelected = (TransformationAxes & transformationAxis) == transformationAxis;
rotationAxes[axis].Get().Model.Materials[0] = isSelected ? ElementSelectedMaterial : axisMaterial;
}
+
+ overlaySphere.Get().Model.Materials[0] = TransformationStarted ? overlaySphereSelectedMaterial : overlaySphereDefaultMaterial;
}
///
@@ -140,11 +155,29 @@ protected override void UpdateColors()
///
protected override InitialTransformation CalculateTransformation()
{
- var mouseDrag = Input.MousePosition - StartMousePosition;
+ // TODO: use cameraComponent.WorldToScreenPosition instead once implemented
+ // determine the anchor entity's screen position
+ var anchorEntityWorldPosition = AnchorEntity.Transform.WorldMatrix.TranslationVector;
+ var cameraComponent = Game.EditorServices.Get().Component;
+ Vector3.TransformCoordinate(ref anchorEntityWorldPosition, ref cameraComponent.ViewProjectionMatrix, out var clipSpace);
+ Vector3.TransformCoordinate(ref anchorEntityWorldPosition, ref cameraComponent.ViewMatrix, out var viewSpace);
+ var anchorEntityScreenPosition = new Vector2
+ {
+ X = (clipSpace.X + 1f) / 2f,
+ Y = (clipSpace.Y + 1f) / 2f - 1f,
+ };
+
+ // determine the vectors going from the anchor entity's position to the start and current mouse positions
+ var anchorEntityToMouse = new Vector2(Input.MousePosition.X, -Input.MousePosition.Y) - anchorEntityScreenPosition;
+ var anchorEntityToStartMouse = new Vector2(StartMousePosition.X, -StartMousePosition.Y) - anchorEntityScreenPosition;
+
+ anchorEntityToMouse.X *= cameraComponent.AspectRatio;
+ anchorEntityToStartMouse.X *= cameraComponent.AspectRatio;
+
var transformation = new InitialTransformation { Rotation = Quaternion.Identity, Scale = Vector3.One };
// determine the rotation angle
- var rotationAngle = Vector2.Dot(new Vector2(mouseDrag.X, -mouseDrag.Y), TransformationDirection) * 2.1f * MathUtil.Pi; // half screen size if little bit more Pi
+ var rotationAngle = MathF.Atan2(anchorEntityToMouse.X * anchorEntityToStartMouse.Y - anchorEntityToMouse.Y * anchorEntityToStartMouse.X, Vector2.Dot(anchorEntityToStartMouse, anchorEntityToMouse));
// snap the rotation angle if necessary
if (UseSnap)
@@ -154,16 +187,14 @@ protected override InitialTransformation CalculateTransformation()
}
// determine the rotation axis in the Gizmo
- var rotationAxisGizmo = Vector3.Zero;
- for (int i = 0; i < 3; i++)
- {
- if ((TransformationAxes & ((GizmoTransformationAxes)(1 << i))) != 0)
- rotationAxisGizmo[i] = 1;
- }
- rotationAxisGizmo.Normalize();
+
+ var rotationAxisWorldUp = rotationAxes[(int)TransformationAxes / 2].Transform.WorldMatrix.Up;
+ var anchorEntityToCamera = AnchorEntity.Transform.WorldMatrix.TranslationVector - Game.EditorServices.Get().Position;
+ var rotationAxis = new Vector3(0) { [(int)TransformationAxes / 2] = MathF.Sign(Vector3.Dot(anchorEntityToCamera, rotationAxisWorldUp)) };
+ rotationAxis.Normalize();
// set the rotation to apply in the gizmo space
- transformation.Rotation = Quaternion.RotationAxis(rotationAxisGizmo, rotationAngle);
+ transformation.Rotation = Quaternion.RotationAxis(rotationAxis, rotationAngle);
return transformation;
}
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/ScaleGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/ScaleGizmo.cs
index 75b659b560..16c96f0722 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/ScaleGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/ScaleGizmo.cs
@@ -2,10 +2,13 @@
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using System.Collections.Generic;
+using System.Threading.Tasks;
using Stride.Core.Mathematics;
+using Stride.Assets.Presentation.AssetEditors.EntityHierarchyEditor.Game;
using Stride.Assets.Presentation.AssetEditors.GameEditor.Game;
using Stride.Engine;
using Stride.Extensions;
+using Stride.Graphics;
using Stride.Graphics.GeometricPrimitives;
using Stride.Rendering;
@@ -13,53 +16,174 @@ namespace Stride.Assets.Presentation.AssetEditors.Gizmos
{
public class ScaleGizmo : AxisTransformationGizmo
{
+ private class EntitySortInfo : IComparer
+ {
+ public Entity Entity;
+
+ public float Depth;
+
+ public int Compare(EntitySortInfo x, EntitySortInfo y)
+ {
+ return Math.Sign(x.Depth - y.Depth);
+ }
+ };
+
+ private const float AxisExtremitySize = GizmoExtremitySize / 2f;
+ private const float AxisBodyRadius = GizmoExtremitySize / 9f;
+ private const float AxisBodyLength = 1f - AxisExtremitySize;
+ private const float OriginSize = GizmoOriginScale * AxisExtremitySize;
+
+ private readonly Material[] planeMaterials = new Material[3];
+ private readonly List sortedEntities = new List();
private readonly List[] scaleAxes = { new List(), new List(), new List() };
+ private readonly List[] scalePlanes = { new List(), new List(), new List() };
+ private readonly List[] scalePlaneEdges = { new List(), new List(), new List() };
+
+ private readonly List scalePlaneRoots = new List();
+ private readonly List[] scaleOpositeAxes = { new List(), new List(), new List(), };
private Entity scaleOrigin;
protected override Entity Create()
{
base.Create();
- const float ExtremitySize = GizmoExtremitySize / 1.5f;
- const float BodyRadius = GizmoExtremitySize / 7.5f;
- const float OriginSize = GizmoOriginScale * ExtremitySize;
- const float BodyLength = 1f - ExtremitySize;
+ planeMaterials[0] = CreateUniformColorMaterial(Color.Red.WithAlpha(86));
+ planeMaterials[1] = CreateUniformColorMaterial(Color.Green.WithAlpha(86));
+ planeMaterials[2] = CreateUniformColorMaterial(Color.Blue.WithAlpha(86));
var entity = new Entity("Scale gizmo");
- var rotations = new[] { Vector3.Zero, new Vector3(0, 0, MathUtil.Pi / 2), new Vector3(0, -MathUtil.Pi / 2f, 0) };
- var extremityMesh = GeometricPrimitive.Cube.New(GraphicsDevice, ExtremitySize).ToMeshDraw();
- var bodyMesh = GeometricPrimitive.Cylinder.New(GraphicsDevice, BodyLength, BodyRadius, GizmoTessellation).ToMeshDraw();
+ var axisRootEntities = new[] { new Entity("Root X axis"), new Entity("Root Y axis"), new Entity("Root Z axis") };
+ var cubeMesh = GeometricPrimitive.Cube.New(GraphicsDevice, AxisExtremitySize).ToMeshDraw();
+ var bodyMesh = GeometricPrimitive.Cylinder.New(GraphicsDevice, AxisBodyLength, AxisBodyRadius, GizmoTessellation).ToMeshDraw();
+ // create the axis arrows
for (int axis = 0; axis < 3; ++axis)
{
- var axisMaterial = GetAxisDefaultMaterial(axis);
- var extremity = new Entity("ArrowExtremity" + axis) { new ModelComponent { Model = new Model { axisMaterial, new Mesh { Draw = extremityMesh } }, RenderGroup = RenderGroup } };
- extremity.Transform.Position.X = BodyLength;
- scaleAxes[axis].Add(extremity);
-
- var body = new Entity("ArrowBody" + axis) { new ModelComponent { Model = new Model { axisMaterial, new Mesh { Draw = bodyMesh } }, RenderGroup = RenderGroup } };
- body.Transform.Position.X = BodyLength / 2;
- body.Transform.RotationEulerXYZ = -MathUtil.Pi / 2 * Vector3.UnitZ;
- scaleAxes[axis].Add(body);
-
- // create the arrow entity composed of the cone and body
+ var material = GetAxisDefaultMaterial(axis);
+
+ // the end cube
+ var extremityEntity = new Entity("ArrowExtremity" + axis) { new ModelComponent { Model = new Model { material, new Mesh { Draw = cubeMesh } }, RenderGroup = RenderGroup } };
+ extremityEntity.Transform.Position.X = AxisBodyLength + AxisExtremitySize * 0.5f;
+ scaleAxes[axis].Add(extremityEntity);
+
+ // the main body
+ var bodyEntity = new Entity("ArrowBody" + axis) { new ModelComponent { Model = new Model { material, new Mesh { Draw = bodyMesh } }, RenderGroup = RenderGroup } };
+ bodyEntity.Transform.Position.X = AxisBodyLength / 2;
+ bodyEntity.Transform.RotationEulerXYZ = -MathUtil.Pi / 2 * Vector3.UnitZ;
+ scaleAxes[axis].Add(bodyEntity);
+
+ // oposite side part (cylinder shown when camera is looking oposite direction to the axis)
+ var frameMesh = GeometricPrimitive.Cylinder.New(GraphicsDevice, GizmoPlaneLength, AxisBodyRadius, GizmoTessellation).ToMeshDraw();
+ var opositeFrameEntity = new Entity("Oposite Frame" + axis) { new ModelComponent { Model = new Model { material, new Mesh { Draw = frameMesh } }, RenderGroup = RenderGroup } };
+ opositeFrameEntity.Transform.Position.X = -GizmoPlaneLength / 2;
+ opositeFrameEntity.Transform.RotationEulerXYZ = -MathUtil.Pi / 2 * Vector3.UnitZ;
+ scaleAxes[axis].Add(opositeFrameEntity);
+ scaleOpositeAxes[axis].Add(opositeFrameEntity.Get());
+
+ // create the arrow entity composed of the cube and body
var arrowEntity = new Entity("ArrowEntity" + axis);
- arrowEntity.Transform.Children.Add(extremity.Transform);
- arrowEntity.Transform.Children.Add(body.Transform);
- arrowEntity.Transform.RotationEulerXYZ = rotations[axis];
+ arrowEntity.Transform.Children.Add(extremityEntity.Transform);
+ arrowEntity.Transform.Children.Add(bodyEntity.Transform);
+ arrowEntity.Transform.Children.Add(opositeFrameEntity.Transform);
// Add the arrow entity to the gizmo entity
- entity.Transform.Children.Add(arrowEntity.Transform);
+ axisRootEntities[axis].Transform.Children.Add(arrowEntity.Transform);
}
- // Add middle sphere
- var sphereMeshDraw = GeometricPrimitive.Cube.New(GraphicsDevice, OriginSize).ToMeshDraw();
- scaleOrigin = new Entity("OriginCube") { new ModelComponent { Model = new Model { DefaultOriginMaterial, new Mesh { Draw = sphereMeshDraw } }, RenderGroup = RenderGroup } };
+ // create the scaling planes
+ for (int axis = 0; axis < 3; ++axis)
+ {
+ // The skeleton material
+ var axisMaterial = GetAxisDefaultMaterial(axis);
+
+ // The 2 frame rectangles
+ var frameMesh = GeometricPrimitive.Cube.New(GraphicsDevice, new Vector3(AxisBodyRadius / 2f, GizmoPlaneLength / 3f, AxisBodyRadius / 2f)).ToMeshDraw();
+ var topFrameEntity = new Entity("TopFrame" + axis) { new ModelComponent { Model = new Model { axisMaterial, new Mesh { Draw = frameMesh } }, RenderGroup = RenderGroup } };
+ var leftFrameEntity = new Entity("LeftFrame" + axis) { new ModelComponent { Model = new Model { axisMaterial, new Mesh { Draw = frameMesh } }, RenderGroup = RenderGroup } };
+ topFrameEntity.Transform.Position = new Vector3(0, GizmoPlaneLength, GizmoPlaneLength - (GizmoPlaneLength / 6));
+ topFrameEntity.Transform.RotationEulerXYZ = new Vector3(MathUtil.Pi / 2f, 0, 0);
+ leftFrameEntity.Transform.Position = new Vector3(0, GizmoPlaneLength - (GizmoPlaneLength / 6), GizmoPlaneLength);
+ scalePlaneEdges[axis].Add(topFrameEntity);
+ scalePlaneEdges[axis].Add(leftFrameEntity);
+
+ // The transparent planes (2 for correct lighting)
+ var materialPlane = planeMaterials[axis];
+ var planeMesh = GeometricPrimitive.Plane.New(GraphicsDevice, GizmoPlaneLength, GizmoPlaneLength).ToMeshDraw();
+ var planeFrameEntityFront = new Entity("FramePlaneFront" + axis) { new ModelComponent { Model = new Model { materialPlane, new Mesh { Draw = planeMesh } }, RenderGroup = RenderGroup } };
+ var planeFrameEntityBack = new Entity("FramePlaneBack" + axis) { new ModelComponent { Model = new Model { materialPlane, new Mesh { Draw = planeMesh } }, RenderGroup = RenderGroup } };
+ planeFrameEntityFront.Transform.Position = new Vector3(0, GizmoPlaneLength / 2, GizmoPlaneLength / 2);
+ planeFrameEntityFront.Transform.RotationEulerXYZ = new Vector3(0, MathUtil.Pi / 2f, 0);
+ planeFrameEntityBack.Transform.Position = new Vector3(0, GizmoPlaneLength / 2, GizmoPlaneLength / 2);
+ planeFrameEntityBack.Transform.RotationEulerXYZ = new Vector3(0, -MathUtil.Pi / 2f, 0);
+ scalePlanes[axis].Add(planeFrameEntityFront);
+ scalePlanes[axis].Add(planeFrameEntityBack);
+ sortedEntities.Add(new EntitySortInfo { Entity = planeFrameEntityFront });
+ sortedEntities.Add(new EntitySortInfo { Entity = planeFrameEntityBack });
+
+ // Add the different parts of the plane to the plane entity
+ var planeEntity = new Entity("GizmoPlane" + axis);
+ planeEntity.Transform.Children.Add(topFrameEntity.Transform);
+ planeEntity.Transform.Children.Add(leftFrameEntity.Transform);
+ planeEntity.Transform.Children.Add(planeFrameEntityFront.Transform);
+ planeEntity.Transform.Children.Add(planeFrameEntityBack.Transform);
+ scalePlaneRoots.Add(planeEntity);
+
+ // Add the plane entity to the gizmo entity
+ axisRootEntities[axis].Transform.Children.Add(planeEntity.Transform);
+ }
+
+ // set the axis root entities rotation and add them to the main entity
+ var axisRotations = new[] { Vector3.Zero, new Vector3(MathUtil.PiOverTwo, 0, MathUtil.PiOverTwo), new Vector3(-MathUtil.PiOverTwo, -MathUtil.PiOverTwo, 0) };
+ for (int axis = 0; axis < 3; axis++)
+ {
+ axisRootEntities[axis].TransformValue.RotationEulerXYZ = axisRotations[axis];
+ entity.TransformValue.Children.Add(axisRootEntities[axis].TransformValue);
+ }
+
+ // Add middle cube
+ var cubeMeshDraw = GeometricPrimitive.Cube.New(GraphicsDevice, OriginSize).ToMeshDraw();
+ scaleOrigin = new Entity("OriginCube") { new ModelComponent { Model = new Model { DefaultOriginMaterial, new Mesh { Draw = cubeMeshDraw } }, RenderGroup = RenderGroup } };
entity.Transform.Children.Add(scaleOrigin.Transform);
return entity;
}
-
+
+ public override async Task Update()
+ {
+ await base.Update();
+
+ UpdateDrawOrder();
+ }
+
+ protected override void UpdateShape()
+ {
+ base.UpdateShape();
+
+ var cameraService = Game.EditorServices.Get();
+ if (cameraService == null)
+ return;
+
+ var gizmoInverse = Matrix.Invert(WorldMatrix);
+ var viewInverse = Matrix.Invert(cameraService.ViewMatrix);
+ var cameraInGizmoSpace = (viewInverse * gizmoInverse).TranslationVector;
+
+ // reset the plane rotations
+ for (int axis = 0; axis < 3; axis++)
+ scalePlaneRoots[axis].TransformValue.Rotation = Quaternion.Identity;
+
+ for (int axis = 0; axis < 3; axis++)
+ {
+ var isCameraBackfacing = cameraInGizmoSpace[axis] < 0;
+ scaleOpositeAxes[axis].ForEach(x => x.Enabled = isCameraBackfacing);
+
+ if (isCameraBackfacing)
+ {
+ scalePlaneRoots[(axis + 1) % 3].TransformValue.Rotation *= Quaternion.RotationY(MathUtil.Pi);
+ scalePlaneRoots[(axis + 2) % 3].TransformValue.Rotation *= Quaternion.RotationZ(MathUtil.Pi);
+ }
+ }
+ }
+
protected override void UpdateTransformationAxis()
{
var newSelection = GizmoTransformationAxes.None;
@@ -68,29 +192,55 @@ protected override void UpdateTransformationAxis()
// calculate the ray in the gizmo space
var gizmoMatrix = WorldMatrix;
var gizmoViewInverse = Matrix.Invert(gizmoMatrix * cameraService.ViewMatrix);
- var clickRay = EditorGameHelper.CalculateRayFromMousePosition(cameraService.Component, Input.MousePosition, gizmoViewInverse);
- // determine gizmo world matrix and scale
- var gizmoScale = gizmoMatrix.Row1.Length();
+ // Check if the inverted View Matrix is valid (since it will be use for mouse picking, check the translation vector only)
+ if (float.IsNaN(gizmoViewInverse.TranslationVector.X)
+ || float.IsNaN(gizmoViewInverse.TranslationVector.Y)
+ || float.IsNaN(gizmoViewInverse.TranslationVector.Z))
+ {
+ return;
+ }
+
+ var clickRay = EditorGameHelper.CalculateRayFromMousePosition(cameraService.Component, Input.MousePosition, gizmoViewInverse);
- float hitDistance;
var minHitDistance = float.PositiveInfinity;
- // select the axis whose intersection is the closest
+ // Select the closest intersecting translation plane
+ foreach (var pair in EditorGameComponentGizmoService.PlaneToIndex)
+ {
+ var minimum = new Vector3(0) { [pair.Value] = -AxisBodyRadius };
+ var maximum = new Vector3(GizmoPlaneLength);
+
+ for (int axis = 0; axis < 3; axis++)
+ maximum[axis] *= Math.Sign(gizmoViewInverse[3, axis]); // translation planes move to always face the camera.
+
+ maximum[pair.Value] = AxisBodyRadius;
+
+ UpdateSelectionOnCloserIntersection(new BoundingBox(minimum, maximum), clickRay, pair.Key, ref minHitDistance, ref newSelection);
+ }
+
+ // Overrides selection with the closest intersecting axis if any
for (int i = 0; i < 3; i++)
{
- var minimum = new Vector3(-GizmoExtremitySize / 2);
- minimum[i] = 0;
- var maximum = new Vector3(+GizmoExtremitySize / 2);
- maximum[i] = 1;
+ // the extremity
+ var minimum = new Vector3(-AxisExtremitySize) { [i] = AxisBodyLength };
+ var maximum = new Vector3(+AxisExtremitySize) { [i] = 1 };
+
+ UpdateSelectionOnCloserIntersection(new BoundingBox(minimum, maximum), clickRay, (GizmoTransformationAxes)(1 << i), ref minHitDistance, ref newSelection);
+
+ // the body
+ minimum = new Vector3(-AxisBodyRadius) { [i] = 0 };
+ maximum = new Vector3(+AxisBodyRadius) { [i] = AxisBodyLength };
+ if (gizmoViewInverse[3, i] < 0)
+ minimum[i] = -GizmoPlaneLength; // camera is backfacing the axis we should compute intersection with the oposite showing part too
UpdateSelectionOnCloserIntersection(new BoundingBox(minimum, maximum), clickRay, (GizmoTransformationAxes)(1 << i), ref minHitDistance, ref newSelection);
}
- // overrides the current selection with the origin if the intersection distance are similar
- var minimumOrigin = new Vector3(-GizmoOriginScale * GizmoExtremitySize / 2);
- var maximumOrigin = new Vector3(+GizmoOriginScale * GizmoExtremitySize / 2);
- if (new BoundingBox(minimumOrigin, maximumOrigin).Intersects(ref clickRay, out hitDistance) && hitDistance - minHitDistance < gizmoScale * 0.5f)
+ // overrides the current selection with the origin if intersecting
+ var minimumOrigin = new Vector3(-OriginSize / 2f);
+ var maximumOrigin = new Vector3(+OriginSize / 2f);
+ if (new BoundingBox(minimumOrigin, maximumOrigin).Intersects(ref clickRay))
{
newSelection = GizmoTransformationAxes.XYZ;
}
@@ -141,12 +291,35 @@ protected override void UpdateColors()
for (int axis = 0; axis < 3; axis++)
{
var axisMaterial = GetAxisDefaultMaterial(axis);
+ var planeMaterial = planeMaterials[axis];
var transformationAxis = (GizmoTransformationAxes)(1 << axis);
- bool isSelected = (TransformationAxes & transformationAxis) == transformationAxis;
- scaleAxes[axis].ForEach(x => x.Get().Model.Materials[0] = isSelected ? ElementSelectedMaterial: axisMaterial);
+ bool isAxisSelected = (TransformationAxes & transformationAxis) == transformationAxis;
+ scaleAxes[axis].ForEach(x => x.Get().Model.Materials[0] = isAxisSelected ? ElementSelectedMaterial : axisMaterial);
+ bool isPlaneSelected = (TransformationAxes ^ transformationAxis) == GizmoTransformationAxes.XYZ;
+ scalePlaneEdges[axis].ForEach(x => x.Get().Model.Materials[0] = isPlaneSelected ? ElementSelectedMaterial : axisMaterial);
+ scalePlanes[axis].ForEach(x => x.Get().Model.Materials[0] = isPlaneSelected ? TransparentElementSelectedMaterial : planeMaterial);
}
var originSelected = TransformationAxes == GizmoTransformationAxes.XYZ;
scaleOrigin.Get().Model.Materials[0] = originSelected ? ElementSelectedMaterial : DefaultOriginMaterial;
}
+
+ private void UpdateDrawOrder()
+ {
+ var cameraService = Game.EditorServices.Get();
+ // calculate the depth of the entities
+ var viewProjection = cameraService.ViewMatrix * cameraService.ProjectionMatrix;
+ foreach (EntitySortInfo sortInfo in sortedEntities)
+ {
+ var worldViewProjection = sortInfo.Entity.Transform.WorldMatrix * viewProjection;
+ sortInfo.Depth = worldViewProjection.M43;
+ // protects against exception thrown by Sort's internals
+ // TODO: investigate the actual source of the presence of nans which must come from one of the matrices. c.f. XK-4627
+ if (float.IsNaN(sortInfo.Depth))
+ sortInfo.Depth = float.MaxValue;
+ }
+
+ // sort the entities by decreasing depth
+ sortedEntities.Sort(sortedEntities[0]);
+ }
}
}
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/TransformationGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/TransformationGizmo.cs
index 0149034294..61bd9fa5b0 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/TransformationGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/TransformationGizmo.cs
@@ -43,7 +43,6 @@ public bool IsIdentity()
public const RenderGroupMask TransformationGizmoGroupMask = RenderGroupMask.Group4;
private bool transformationInitialized;
- private bool transformationStarted;
private bool duplicationDone;
///
@@ -56,6 +55,11 @@ public bool IsIdentity()
///
public float DefaultScale => GizmoDefaultSize / GraphicsDevice.Presenter.BackBuffer.Height;
+ ///
+ /// Returns whether the transformation has started or not
+ ///
+ protected bool TransformationStarted { get; private set; }
+
///
/// The default material for the origin elements
///
@@ -135,9 +139,9 @@ protected override Entity Create()
{
base.Create();
- DefaultOriginMaterial = CreateUniformColorMaterial(Color.White);
- ElementSelectedMaterial = CreateUniformColorMaterial(Color.Gold);
- TransparentElementSelectedMaterial = CreateUniformColorMaterial(Color.Gold.WithAlpha(86));
+ DefaultOriginMaterial = CreateEmissiveColorMaterial(Color.White);
+ ElementSelectedMaterial = CreateEmissiveColorMaterial(Color.Gold);
+ TransparentElementSelectedMaterial = CreateEmissiveColorMaterial(Color.Gold.WithAlpha(86));
return null;
}
@@ -186,7 +190,7 @@ private Matrix GetWorldMatrix(IEditorGameCameraService cameraService)
if (AnchorEntity.GetParent() != null)
parentMatrix = AnchorEntity.TransformValue.Parent.WorldMatrix;
- // We don't use the entity's "WorldMatrix" because it's scale could be zero, which would break the gizmo.
+ // We don't use the entity's "WorldMatrix" because its scale could be zero, which would break the gizmo.
worldMatrix = Matrix.RotationQuaternion(AnchorEntity.Transform.Rotation) *
Matrix.Translation(AnchorEntity.Transform.Position) *
parentMatrix;
@@ -316,7 +320,7 @@ protected virtual void InitializeTransformation()
protected virtual void OnTransformationStarted(Vector2 mouseDragPixel)
{
- transformationStarted = true;
+ TransformationStarted = true;
// keep in memory all initial transformation states
InitialTransformations.Clear();
@@ -353,7 +357,7 @@ private async Task TransformSceneEntityBase()
OnTransformationFinished();
transformationInitialized = false;
- transformationStarted = false;
+ TransformationStarted = false;
return;
}
@@ -368,7 +372,7 @@ private async Task TransformSceneEntityBase()
var mouseDrag = mousePosition - StartMousePosition;
// start the transformation only if user has dragged from a given amount of pixel. Determine direction of the transformation.
- if (!transformationStarted)
+ if (!TransformationStarted)
{
// ensure that the mouse cursor has been moved enough
var screenSize = new Vector2(GraphicsDevice.Presenter.BackBuffer.Width, GraphicsDevice.Presenter.BackBuffer.Height);
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/TranslationGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/TranslationGizmo.cs
index b053f22a97..8eaa695926 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/TranslationGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/TranslationGizmo.cs
@@ -2,7 +2,6 @@
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Stride.Core.Mathematics;
using Stride.Assets.Presentation.AssetEditors.EntityHierarchyEditor.Game;
@@ -29,9 +28,9 @@ public int Compare(EntitySortInfo x, EntitySortInfo y)
}
};
- private const float AxisConeRadius = GizmoExtremitySize / 2f;
- private const float AxisConeHeight = 2f * AxisConeRadius;
- private const float AxisBodyRadius = GizmoExtremitySize / 7.5f;
+ private const float AxisConeRadius = GizmoExtremitySize / 3f;
+ private const float AxisConeHeight = GizmoExtremitySize;
+ private const float AxisBodyRadius = GizmoExtremitySize / 9f;
private const float AxisBodyLength = 1f - AxisConeHeight;
private const float OriginRadius = GizmoOriginScale * AxisConeRadius;
@@ -75,25 +74,19 @@ protected override Entity Create()
bodyEntity.Transform.RotationEulerXYZ = -MathUtil.Pi / 2 * Vector3.UnitZ;
translationAxes[axis].Add(bodyEntity);
- // oposite side part (cylinder + end sphere shown when camera is looking oposite direction to the axis)
+ // oposite side part (cylinder shown when camera is looking oposite direction to the axis)
var frameMesh = GeometricPrimitive.Cylinder.New(GraphicsDevice, GizmoPlaneLength, AxisBodyRadius, GizmoTessellation).ToMeshDraw();
var opositeFrameEntity = new Entity("Oposite Frame" + axis) { new ModelComponent { Model = new Model { material, new Mesh { Draw = frameMesh } }, RenderGroup = RenderGroup } };
opositeFrameEntity.Transform.Position.X = - GizmoPlaneLength / 2;
opositeFrameEntity.Transform.RotationEulerXYZ = -MathUtil.Pi / 2 * Vector3.UnitZ;
- var articulationMesh = GeometricPrimitive.Sphere.New(GraphicsDevice, AxisBodyRadius, GizmoTessellation).ToMeshDraw();
- var opositeSphereEntity = new Entity("FrameSphere" + axis) { new ModelComponent { Model = new Model { material, new Mesh { Draw = articulationMesh } }, RenderGroup = RenderGroup } };
- opositeSphereEntity.Transform.Position = new Vector3(-GizmoPlaneLength, 0, 0);
translationAxes[axis].Add(opositeFrameEntity);
- translationAxes[axis].Add(opositeSphereEntity);
translationOpositeAxes[axis].Add(opositeFrameEntity.Get());
- translationOpositeAxes[axis].Add(opositeSphereEntity.Get());
- // create the arrow entity composed of the cone and bode
+ // create the arrow entity composed of the cone and body
var arrowEntity = new Entity("ArrowEntity" + axis);
arrowEntity.Transform.Children.Add(coneEntity.Transform);
arrowEntity.Transform.Children.Add(bodyEntity.Transform);
arrowEntity.Transform.Children.Add(opositeFrameEntity.Transform);
- arrowEntity.Transform.Children.Add(opositeSphereEntity.Transform);
// Add the arrow entity to the gizmo entity
axisRootEntities[axis].Transform.Children.Add(arrowEntity.Transform);
@@ -104,23 +97,17 @@ protected override Entity Create()
{
// The skeleton material
var axisMaterial = GetAxisDefaultMaterial(axis);
-
- // The 2 frame cylinders
- var frameMesh = GeometricPrimitive.Cylinder.New(GraphicsDevice, GizmoPlaneLength, AxisBodyRadius, GizmoTessellation).ToMeshDraw();
+
+ // The 2 frame rectangles
+ var frameMesh = GeometricPrimitive.Cube.New(GraphicsDevice, new Vector3(AxisBodyRadius / 2f, GizmoPlaneLength / 3f, AxisBodyRadius / 2f)).ToMeshDraw();
var topFrameEntity = new Entity("TopFrame" + axis) { new ModelComponent { Model = new Model { axisMaterial, new Mesh { Draw = frameMesh } }, RenderGroup = RenderGroup } };
var leftFrameEntity = new Entity("LeftFrame" + axis) { new ModelComponent { Model = new Model { axisMaterial, new Mesh { Draw = frameMesh } }, RenderGroup = RenderGroup } };
- topFrameEntity.Transform.Position = new Vector3(0, GizmoPlaneLength, GizmoPlaneLength / 2);
+ topFrameEntity.Transform.Position = new Vector3(0, GizmoPlaneLength, GizmoPlaneLength - (GizmoPlaneLength / 6));
topFrameEntity.Transform.RotationEulerXYZ = new Vector3(MathUtil.Pi / 2f, 0, 0);
- leftFrameEntity.Transform.Position = new Vector3(0, GizmoPlaneLength / 2, GizmoPlaneLength);
+ leftFrameEntity.Transform.Position = new Vector3(0, GizmoPlaneLength - (GizmoPlaneLength / 6), GizmoPlaneLength);
translationPlaneEdges[axis].Add(topFrameEntity);
translationPlaneEdges[axis].Add(leftFrameEntity);
- // The articulation sphere
- var articulationMesh = GeometricPrimitive.Sphere.New(GraphicsDevice, AxisBodyRadius, GizmoTessellation).ToMeshDraw();
- var articulationEntity = new Entity("FrameSphere" + axis) { new ModelComponent { Model = new Model { axisMaterial, new Mesh { Draw = articulationMesh } }, RenderGroup = RenderGroup } };
- articulationEntity.Transform.Position = new Vector3(0, GizmoPlaneLength, GizmoPlaneLength);
- translationPlaneEdges[axis].Add(articulationEntity);
-
// The transparent planes (2 for correct lighting)
var materialPlane = planeMaterials[axis];
var planeMesh = GeometricPrimitive.Plane.New(GraphicsDevice, GizmoPlaneLength, GizmoPlaneLength).ToMeshDraw();
@@ -139,7 +126,6 @@ protected override Entity Create()
var planeEntity = new Entity("GizmoPlane" + axis);
planeEntity.Transform.Children.Add(topFrameEntity.Transform);
planeEntity.Transform.Children.Add(leftFrameEntity.Transform);
- planeEntity.Transform.Children.Add(articulationEntity.Transform);
planeEntity.Transform.Children.Add(planeFrameEntityFront.Transform);
planeEntity.Transform.Children.Add(planeFrameEntityBack.Transform);
translationPlaneRoots.Add(planeEntity);
@@ -148,7 +134,7 @@ protected override Entity Create()
axisRootEntities[axis].Transform.Children.Add(planeEntity.Transform);
}
- // set the axis root entities rotation and add them to the main entityaxisRootEntities[axis]
+ // set the axis root entities rotation and add them to the main entity
var axisRotations = new [] { Vector3.Zero, new Vector3(MathUtil.PiOverTwo, 0, MathUtil.PiOverTwo), new Vector3(-MathUtil.PiOverTwo, -MathUtil.PiOverTwo, 0) };
for (int axis = 0; axis < 3; axis++)
{
@@ -157,9 +143,8 @@ protected override Entity Create()
}
// Add middle sphere
- var materialSphere = DefaultOriginMaterial;
var sphereMeshDraw = GeometricPrimitive.Sphere.New(GraphicsDevice, OriginRadius, GizmoTessellation).ToMeshDraw();
- translationOrigin = new Entity("OriginCube") { new ModelComponent { Model = new Model { materialSphere, new Mesh { Draw = sphereMeshDraw } }, RenderGroup = RenderGroup } };
+ translationOrigin = new Entity("OriginSphere") { new ModelComponent { Model = new Model { DefaultOriginMaterial, new Mesh { Draw = sphereMeshDraw } }, RenderGroup = RenderGroup } };
entity.Transform.Children.Add(translationOrigin.Transform);
return entity;
@@ -191,7 +176,7 @@ protected override void UpdateShape()
for (int axis = 0; axis < 3; axis++)
{
var isCameraBackfacing = cameraInGizmoSpace[axis] < 0;
- translationOpositeAxes[axis].ForEach(x=>x.Enabled = isCameraBackfacing);
+ translationOpositeAxes[axis].ForEach(x => x.Enabled = isCameraBackfacing);
if (isCameraBackfacing)
{
@@ -220,7 +205,6 @@ protected override void UpdateTransformationAxis()
var clickRay = EditorGameHelper.CalculateRayFromMousePosition(cameraService.Component, Input.MousePosition, gizmoViewInverse);
- float hitDistance;
var minHitDistance = float.PositiveInfinity;
// Select the closest intersecting translation plane
@@ -237,7 +221,7 @@ protected override void UpdateTransformationAxis()
UpdateSelectionOnCloserIntersection(new BoundingBox(minimum, maximum), clickRay, pair.Key, ref minHitDistance, ref newSelection);
}
- // Overrides selection with the closed intersecting axis if any
+ // Overrides selection with the closest intersecting axis if any
minHitDistance = float.PositiveInfinity;
for (int i = 0; i < 3; i++)
{
@@ -257,7 +241,7 @@ protected override void UpdateTransformationAxis()
}
// overrides the current selection with the origin if intersecting
- if (new BoundingSphere(Vector3.Zero, OriginRadius).Intersects(ref clickRay, out hitDistance))
+ if (new BoundingSphere(Vector3.Zero, OriginRadius).Intersects(ref clickRay))
newSelection = GizmoTransformationAxes.XYZ;
TransformationAxes = newSelection;
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/VoxelVolumeGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/VoxelVolumeGizmo.cs
index 47bedc5abb..3ed6a5bf53 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/VoxelVolumeGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/VoxelVolumeGizmo.cs
@@ -32,7 +32,7 @@ protected override Entity Create()
{
debugRootEntity = new Entity($"Voxel volume of {Component.Entity.Name}");
- material = GizmoUniformColorMaterial.Create(GraphicsDevice, Color.CornflowerBlue);
+ material = GizmoEmissiveColorMaterial.Create(GraphicsDevice, Color.CornflowerBlue);
box = new BoxMesh(GraphicsDevice);
box.Build();
diff --git a/sources/editor/Stride.Assets.Presentation/SceneEditor/SceneEditorSettings.cs b/sources/editor/Stride.Assets.Presentation/SceneEditor/SceneEditorSettings.cs
index 739df5a565..27a237aa76 100644
--- a/sources/editor/Stride.Assets.Presentation/SceneEditor/SceneEditorSettings.cs
+++ b/sources/editor/Stride.Assets.Presentation/SceneEditor/SceneEditorSettings.cs
@@ -80,6 +80,10 @@ static SceneEditorSettings()
{
DisplayName = $"{SceneEditor}/{ViewportSettings}/{Tr._p("Settings", "Default snap factor for scale")}"
};
+ DisplayDirectionNames = new SettingsKey("SceneEditor/ViewportSettings/DisplayDirectionNames", Stride.Core.Assets.Editor.Settings.EditorSettings.SettingsContainer, false)
+ {
+ DisplayName = $"{SceneEditor}/{ViewportSettings}/{Tr._p("Settings", "Display direction names instead of XYZ components")}"
+ };
AskBeforeDeletingEntities = new SettingsKey("SceneEditor/AskBeforeDeletingEntities", Stride.Core.Assets.Editor.Settings.EditorSettings.SettingsContainer, true)
{
DisplayName = $"{SceneEditor}/{Tr._p("Settings", "Ask before deleting entities")}"
@@ -118,6 +122,8 @@ static SceneEditorSettings()
public static SettingsKey DefaultScaleSnap { get; }
+ public static SettingsKey DisplayDirectionNames { get; }
+
public static SettingsKey AskBeforeDeletingEntities { get; }
public static void Save()
diff --git a/sources/engine/Stride.Rendering/Rendering/Editor/CameraOrientationGizmoShader.sdsl b/sources/engine/Stride.Rendering/Rendering/Editor/CameraOrientationGizmoShader.sdsl
new file mode 100644
index 0000000000..461f20ab9b
--- /dev/null
+++ b/sources/engine/Stride.Rendering/Rendering/Editor/CameraOrientationGizmoShader.sdsl
@@ -0,0 +1,11 @@
+// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
+// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
+
+shader CameraOrientationGizmoShader : ComputeColor, PositionStream4
+{
+ override float4 Compute()
+ {
+ float yPosRemapped = pow((streams.PositionWS.y + 1) / 2, 3.5f);
+ return float4(0.6f, 0.6f, 0.6f, 1.0f) * yPosRemapped;
+ }
+};
From a01ab21bdfd658e79d0083641b274eda5a1cd9c3 Mon Sep 17 00:00:00 2001
From: salahchafai <64394387+salahchafai@users.noreply.github.com>
Date: Thu, 1 Jul 2021 10:51:36 +0100
Subject: [PATCH 2/3] small fix
---
.../AssetEditors/Gizmos/RotationGizmo.cs | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs
index e75338d0a0..4a1cb9d6ef 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs
@@ -186,12 +186,10 @@ protected override InitialTransformation CalculateTransformation()
rotationAngle = MathUtil.Snap(rotationAngle, snapValue);
}
- // determine the rotation axis in the Gizmo
-
+ // determine the rotation axis
var rotationAxisWorldUp = rotationAxes[(int)TransformationAxes / 2].Transform.WorldMatrix.Up;
- var anchorEntityToCamera = AnchorEntity.Transform.WorldMatrix.TranslationVector - Game.EditorServices.Get().Position;
- var rotationAxis = new Vector3(0) { [(int)TransformationAxes / 2] = MathF.Sign(Vector3.Dot(anchorEntityToCamera, rotationAxisWorldUp)) };
- rotationAxis.Normalize();
+ var cameraToAnchorEntity = AnchorEntity.Transform.WorldMatrix.TranslationVector - Game.EditorServices.Get().Position;
+ var rotationAxis = new Vector3(0) { [(int)TransformationAxes / 2] = MathF.Sign(Vector3.Dot(cameraToAnchorEntity, rotationAxisWorldUp)) };
// set the rotation to apply in the gizmo space
transformation.Rotation = Quaternion.RotationAxis(rotationAxis, rotationAngle);
From 68714907b6519a56eb1b236f2cf707d1a4c8713c Mon Sep 17 00:00:00 2001
From: salahchafai <64394387+salahchafai@users.noreply.github.com>
Date: Thu, 1 Jul 2021 14:17:25 +0100
Subject: [PATCH 3/3] added the option to use linear movement for rotating
---
.../AssetEditors/Gizmos/RotationGizmo.cs | 38 ++++++++++++++++---
.../SceneEditor/SceneEditorSettings.cs | 6 +++
2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs
index 4a1cb9d6ef..62b5fac951 100644
--- a/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs
+++ b/sources/editor/Stride.Assets.Presentation/AssetEditors/Gizmos/RotationGizmo.cs
@@ -7,6 +7,7 @@
using Stride.Extensions;
using Stride.Graphics.GeometricPrimitives;
using Stride.Rendering;
+using Stride.Assets.Presentation.SceneEditor;
namespace Stride.Assets.Presentation.AssetEditors.Gizmos
{
@@ -154,6 +155,16 @@ protected override void UpdateColors()
///
///
protected override InitialTransformation CalculateTransformation()
+ {
+ var transformation = new InitialTransformation { Rotation = Quaternion.Identity, Scale = Vector3.One };
+
+ // set the rotation to apply in the gizmo space
+ transformation.Rotation = SceneEditorSettings.UseLinearMovementForRotation.GetValue() ? GetRotationFromLinearMovement() : GetRotationFromCircularMovement();
+
+ return transformation;
+ }
+
+ private Quaternion GetRotationFromCircularMovement()
{
// TODO: use cameraComponent.WorldToScreenPosition instead once implemented
// determine the anchor entity's screen position
@@ -173,8 +184,6 @@ protected override InitialTransformation CalculateTransformation()
anchorEntityToMouse.X *= cameraComponent.AspectRatio;
anchorEntityToStartMouse.X *= cameraComponent.AspectRatio;
-
- var transformation = new InitialTransformation { Rotation = Quaternion.Identity, Scale = Vector3.One };
// determine the rotation angle
var rotationAngle = MathF.Atan2(anchorEntityToMouse.X * anchorEntityToStartMouse.Y - anchorEntityToMouse.Y * anchorEntityToStartMouse.X, Vector2.Dot(anchorEntityToStartMouse, anchorEntityToMouse));
@@ -187,14 +196,31 @@ protected override InitialTransformation CalculateTransformation()
}
// determine the rotation axis
- var rotationAxisWorldUp = rotationAxes[(int)TransformationAxes / 2].Transform.WorldMatrix.Up;
+ var rotationAxisWorldUp = rotationAxes[(int)TransformationAxes / 2].Transform.WorldMatrix.Up;
var cameraToAnchorEntity = AnchorEntity.Transform.WorldMatrix.TranslationVector - Game.EditorServices.Get().Position;
var rotationAxis = new Vector3(0) { [(int)TransformationAxes / 2] = MathF.Sign(Vector3.Dot(cameraToAnchorEntity, rotationAxisWorldUp)) };
- // set the rotation to apply in the gizmo space
- transformation.Rotation = Quaternion.RotationAxis(rotationAxis, rotationAngle);
+ return Quaternion.RotationAxis(rotationAxis, rotationAngle);
+ }
- return transformation;
+ private Quaternion GetRotationFromLinearMovement()
+ {
+ var mouseDrag = Input.MousePosition - StartMousePosition;
+
+ // determine the rotation angle
+ var rotationAngle = Vector2.Dot(new Vector2(mouseDrag.X, -mouseDrag.Y), TransformationDirection) * 2.1f * MathUtil.Pi; // half screen size if little bit more Pi
+
+ // snap the rotation angle if necessary
+ if (UseSnap)
+ {
+ var snapValue = MathUtil.DegreesToRadians(SnapValue);
+ rotationAngle = MathUtil.Snap(rotationAngle, snapValue);
+ }
+
+ // determine the rotation axis
+ var rotationAxis = new Vector3(0) { [(int)TransformationAxes / 2] = 1 };
+
+ return Quaternion.RotationAxis(rotationAxis, rotationAngle);
}
protected override void OnTransformationFinished()
diff --git a/sources/editor/Stride.Assets.Presentation/SceneEditor/SceneEditorSettings.cs b/sources/editor/Stride.Assets.Presentation/SceneEditor/SceneEditorSettings.cs
index 27a237aa76..e1e5459a99 100644
--- a/sources/editor/Stride.Assets.Presentation/SceneEditor/SceneEditorSettings.cs
+++ b/sources/editor/Stride.Assets.Presentation/SceneEditor/SceneEditorSettings.cs
@@ -84,6 +84,10 @@ static SceneEditorSettings()
{
DisplayName = $"{SceneEditor}/{ViewportSettings}/{Tr._p("Settings", "Display direction names instead of XYZ components")}"
};
+ UseLinearMovementForRotation = new SettingsKey("SceneEditor/ViewportSettings/UseLinearMovementForRotation", Stride.Core.Assets.Editor.Settings.EditorSettings.SettingsContainer, false)
+ {
+ DisplayName = $"{SceneEditor}/{ViewportSettings}/{Tr._p("Settings", "Use linear movement for the rotation gizmo")}"
+ };
AskBeforeDeletingEntities = new SettingsKey("SceneEditor/AskBeforeDeletingEntities", Stride.Core.Assets.Editor.Settings.EditorSettings.SettingsContainer, true)
{
DisplayName = $"{SceneEditor}/{Tr._p("Settings", "Ask before deleting entities")}"
@@ -124,6 +128,8 @@ static SceneEditorSettings()
public static SettingsKey DisplayDirectionNames { get; }
+ public static SettingsKey UseLinearMovementForRotation { get; }
+
public static SettingsKey AskBeforeDeletingEntities { get; }
public static void Save()