diff --git a/Source/Editor/SceneGraph/RootNode.cs b/Source/Editor/SceneGraph/RootNode.cs index 15b7a1945..abefb68ca 100644 --- a/Source/Editor/SceneGraph/RootNode.cs +++ b/Source/Editor/SceneGraph/RootNode.cs @@ -120,6 +120,16 @@ namespace FlaxEditor.SceneGraph return RayCast(ref data, out distance, out normal); } + internal static Quaternion RaycastNormalRotation(ref Vector3 normal) + { + Quaternion rotation; + if (normal == Vector3.Down) + rotation = Quaternion.RotationZ(Mathf.Pi); + else + rotation = Quaternion.LookRotation(Vector3.Cross(Vector3.Cross(normal, Vector3.Forward), normal), normal); + return rotation; + } + /// public override bool RayCastSelf(ref RayCastData ray, out float distance, out Vector3 normal) { diff --git a/Source/Editor/Tools/VertexPainting.cs b/Source/Editor/Tools/VertexPainting.cs index 715f075ca..875b690f5 100644 --- a/Source/Editor/Tools/VertexPainting.cs +++ b/Source/Editor/Tools/VertexPainting.cs @@ -634,11 +634,7 @@ namespace FlaxEditor.Tools { _brushMaterial.SetParameterValue("Color", new Color(1.0f, 0.85f, 0.0f)); // TODO: expose to editor options _brushMaterial.SetParameterValue("DepthBuffer", Owner.RenderTask.Buffers.DepthBuffer); - Quaternion rotation; - if (_hitNormal == Vector3.Down) - rotation = Quaternion.RotationZ(Mathf.Pi); - else - rotation = Quaternion.LookRotation(Vector3.Cross(Vector3.Cross(_hitNormal, Vector3.Forward), _hitNormal), _hitNormal); + Quaternion rotation = RootNode.RaycastNormalRotation(ref _hitNormal); Matrix transform = Matrix.Scaling(_gizmoMode.BrushSize * 0.01f) * Matrix.RotationQuaternion(rotation) * Matrix.Translation(_hitLocation); _brushModel.Draw(ref renderContext, _brushMaterial, ref transform); } diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 268d55492..0d4af67a5 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -770,28 +770,31 @@ namespace FlaxEditor.Viewport base.OnLeftMouseButtonUp(); } - private void GetHitLocation(ref Vector2 location, out SceneGraphNode hit, out Vector3 hitLocation) + private void GetHitLocation(ref Vector2 location, out SceneGraphNode hit, out Vector3 hitLocation, out Vector3 hitNormal) { // Get mouse ray and try to hit any object var ray = ConvertMouseToRay(ref location); var view = new Ray(ViewPosition, ViewDirection); var gridPlane = new Plane(Vector3.Zero, Vector3.Up); var flags = SceneGraphNode.RayCastData.FlagTypes.SkipColliders | SceneGraphNode.RayCastData.FlagTypes.SkipEditorPrimitives; - hit = Editor.Instance.Scene.Root.RayCast(ref ray, ref view, out var closest, flags); + hit = Editor.Instance.Scene.Root.RayCast(ref ray, ref view, out var closest, out var normal, flags); if (hit != null) { // Use hit location hitLocation = ray.Position + ray.Direction * closest; + hitNormal = normal; } else if (Grid.Enabled && CollisionsHelper.RayIntersectsPlane(ref ray, ref gridPlane, out closest) && closest < 4000.0f) { // Use grid location hitLocation = ray.Position + ray.Direction * closest; + hitNormal = Vector3.Up; } else { // Use area in front of the viewport hitLocation = ViewPosition + ViewDirection * 100; + hitNormal = Vector3.Up; } } @@ -799,8 +802,11 @@ namespace FlaxEditor.Viewport { if (_dragAssets.HasValidDrag && _dragAssets.Objects[0].IsOfType()) { - GetHitLocation(ref location, out var hit, out _); + GetHitLocation(ref location, out var hit, out _, out _); ClearDragEffects(); + var material = FlaxEngine.Content.LoadAsync(_dragAssets.Objects[0].ID); + if (material.IsDecal) + return; if (hit is StaticModelNode staticModelNode) { @@ -910,7 +916,7 @@ namespace FlaxEditor.Viewport return location; } - private void Spawn(Actor actor, ref Vector3 hitLocation) + private void Spawn(Actor actor, ref Vector3 hitLocation, ref Vector3 hitNormal) { actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); var parent = actor.Parent ?? Level.GetScene(0); @@ -919,24 +925,34 @@ namespace FlaxEditor.Viewport Focus(); } - private void Spawn(AssetItem item, SceneGraphNode hit, ref Vector2 location, ref Vector3 hitLocation) + private void Spawn(AssetItem item, SceneGraphNode hit, ref Vector2 location, ref Vector3 hitLocation, ref Vector3 hitNormal) { if (item.IsOfType()) { - if (hit is StaticModelNode staticModelNode) + var material = FlaxEngine.Content.LoadAsync(item.ID); + if (material && !material.WaitForLoaded(100) && material.IsDecal) + { + var actor = new Decal + { + Material = material, + LocalOrientation = RootNode.RaycastNormalRotation(ref hitNormal), + Name = item.ShortName + }; + DebugDraw.DrawWireArrow(PostProcessSpawnedActorLocation(actor, ref hitNormal), actor.LocalOrientation, 1.0f, Color.Red, 1000000); + Spawn(actor, ref hitLocation, ref hitNormal); + } + else if (hit is StaticModelNode staticModelNode) { var staticModel = (StaticModel)staticModelNode.Actor; var ray = ConvertMouseToRay(ref location); if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex)) { - var material = FlaxEngine.Content.LoadAsync(item.ID); using (new UndoBlock(Undo, staticModel, "Change material")) staticModel.SetMaterial(entryIndex, material); } } else if (hit is BoxBrushNode.SideLinkNode brushSurfaceNode) { - var material = FlaxEngine.Content.LoadAsync(item.ID); using (new UndoBlock(Undo, brushSurfaceNode.Brush, "Change material")) { var surface = brushSurfaceNode.Surface; @@ -954,11 +970,11 @@ namespace FlaxEditor.Viewport { var actor = item.OnEditorDrop(this); actor.Name = item.ShortName; - Spawn(actor, ref hitLocation); + Spawn(actor, ref hitLocation, ref hitNormal); } } - private void Spawn(ScriptType item, SceneGraphNode hit, ref Vector2 location, ref Vector3 hitLocation) + private void Spawn(ScriptType item, SceneGraphNode hit, ref Vector2 location, ref Vector3 hitLocation, ref Vector3 hitNormal) { var actor = item.CreateInstance() as Actor; if (actor == null) @@ -967,7 +983,7 @@ namespace FlaxEditor.Viewport return; } actor.Name = item.Name; - Spawn(actor, ref hitLocation); + Spawn(actor, ref hitLocation, ref hitNormal); } /// @@ -980,11 +996,11 @@ namespace FlaxEditor.Viewport return result; // Check if drag sth - Vector3 hitLocation = ViewPosition; + Vector3 hitLocation = ViewPosition, hitNormal = -ViewDirection; SceneGraphNode hit = null; if (DragHandlers.HasValidDrag) { - GetHitLocation(ref location, out hit, out hitLocation); + GetHitLocation(ref location, out hit, out hitLocation, out hitNormal); } // Drag assets @@ -996,7 +1012,7 @@ namespace FlaxEditor.Viewport for (int i = 0; i < _dragAssets.Objects.Count; i++) { var item = _dragAssets.Objects[i]; - Spawn(item, hit, ref location, ref hitLocation); + Spawn(item, hit, ref location, ref hitLocation, ref hitNormal); } } // Drag actor type @@ -1008,7 +1024,7 @@ namespace FlaxEditor.Viewport for (int i = 0; i < _dragActorType.Objects.Count; i++) { var item = _dragActorType.Objects[i]; - Spawn(item, hit, ref location, ref hitLocation); + Spawn(item, hit, ref location, ref hitLocation, ref hitNormal); } }