SpatialCursor.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using System;
  2. using Urho.Actions;
  3. namespace Urho.SharpReality
  4. {
  5. public class SpatialCursor : Component
  6. {
  7. public SpatialCursor(IntPtr handle) : base(handle)
  8. {
  9. ReceiveSceneUpdates = true;
  10. }
  11. public SpatialCursor()
  12. {
  13. ReceiveSceneUpdates = true;
  14. }
  15. public Node CursorNode { get; private set; }
  16. public Node CursorModelNode { get; private set; }
  17. public bool CursorEnabled { get; set; } = true;
  18. public event Action<RayQueryResult?> Raycasted;
  19. public override void OnAttachedToNode(Node node)
  20. {
  21. CursorNode = node.CreateChild("SpatialCursor");
  22. CursorModelNode = CursorNode.CreateChild("SpatialCursorModel");
  23. CursorModelNode.SetScale(0.05f);
  24. var staticModel = CursorModelNode.CreateComponent<StaticModel>();
  25. staticModel.Model = CoreAssets.Models.Torus;
  26. Material mat = new Material();
  27. mat.SetTechnique(0, CoreAssets.Techniques.NoTextureOverlay, 1, 1);
  28. mat.SetShaderParameter("MatDiffColor", Color.Cyan);
  29. RunIdleAnimation();
  30. staticModel.SetMaterial(mat);
  31. staticModel.ViewMask = 0x80000000; //hide from raycasts
  32. base.OnAttachedToNode(node);
  33. ReceiveSceneUpdates = true;
  34. }
  35. public void RunIdleAnimation()
  36. {
  37. CursorModelNode.RemoveAllActions();
  38. CursorModelNode.RunActions(new RepeatForever(new ScaleTo(0.3f, 0.05f), new ScaleTo(0.3f, 0.03f)));
  39. }
  40. public async void ClickAnimation()
  41. {
  42. Color originalColor = Color.Cyan;
  43. Color clickColor = Color.Yellow;
  44. CursorModelNode.RemoveAllActions();
  45. var staticModel = CursorModelNode.GetComponent<StaticModel>();
  46. if (staticModel != null)
  47. {
  48. var specColorAnimation = new ValueAnimation();
  49. specColorAnimation.SetKeyFrame(0.0f, originalColor);
  50. specColorAnimation.SetKeyFrame(0.2f, clickColor);
  51. specColorAnimation.SetKeyFrame(0.4f, originalColor);
  52. var mat = staticModel.GetMaterial(0);
  53. mat?.SetShaderParameterAnimation("MatDiffColor", specColorAnimation, WrapMode.Once, 1.0f);
  54. }
  55. await CursorModelNode.RunActionsAsync(new ScaleTo(0.2f, 0.07f), new ScaleTo(0.4f, 0.04f));
  56. RunIdleAnimation();
  57. }
  58. Camera camera;
  59. private Camera Camera
  60. {
  61. get
  62. {
  63. if (camera == null)
  64. {
  65. var cc = this.Scene.GetComponent(Camera.TypeStatic, true);
  66. camera = this.Scene.GetComponent<Camera>(true);
  67. if (camera == null)
  68. throw new InvalidOperationException("Scene doesn't have a camera");
  69. }
  70. return camera;
  71. }
  72. }
  73. Octree octree;
  74. Octree Octree
  75. {
  76. get
  77. {
  78. if (octree == null)
  79. {
  80. octree = this.Scene.GetComponent<Octree>(true);
  81. if (octree == null)
  82. throw new InvalidOperationException("Scene doesn't have an octree");
  83. }
  84. return octree;
  85. }
  86. }
  87. protected override void OnUpdate(float timeStep)
  88. {
  89. base.OnUpdate(timeStep);
  90. Ray cameraRay = Camera.GetScreenRay(0.5f, 0.5f);
  91. var result = Octree.RaycastSingle(cameraRay, RayQueryLevel.Triangle, 100, DrawableFlags.Geometry, 0x70000000);
  92. Raycasted?.Invoke(result);
  93. if (!CursorEnabled)
  94. return;
  95. if (result != null)
  96. {
  97. CursorNode.Position = result.Value.Position;
  98. CursorNode.Rotation = FromLookRotation(new Vector3(0, 1, 0), result.Value.Normal);
  99. }
  100. else
  101. CursorNode.Position = Camera.Node.Rotation * new Vector3(0, 0, 5f);
  102. }
  103. static Quaternion FromLookRotation(Vector3 direction, Vector3 upDirection)
  104. {
  105. Vector3 v = Vector3.Cross(direction, upDirection);
  106. if (v.LengthSquared >= 0.1f)
  107. {
  108. v.Normalize();
  109. Vector3 y = Vector3.Cross(v, direction);
  110. Vector3 x = Vector3.Cross(y, direction);
  111. Matrix3 m3 = new Matrix3(
  112. x.X, y.X, direction.X,
  113. x.Y, y.Y, direction.Y,
  114. x.Z, y.Z, direction.Z);
  115. return new Quaternion(ref m3);
  116. }
  117. return Quaternion.Identity;
  118. }
  119. }
  120. }