오브젝트 스냅 기능 #200
@@ -4991,12 +4991,12 @@ MonoBehaviour:
|
||||
_scaleSensitivity: 1
|
||||
_moveGizmoSettings3D:
|
||||
_canBeDisplayed: 1
|
||||
_isExpanded: 0
|
||||
_isExpanded: 1
|
||||
_vertexSnapSettings:
|
||||
_canBeDisplayed: 1
|
||||
_isExpanded: 1
|
||||
_snapDestinationLayers: -1
|
||||
_canSnapToGrid: 1
|
||||
_snapDestinationLayers: -4095
|
||||
_canSnapToGrid: 0
|
||||
_canSnapToObjectVerts: 1
|
||||
_sglSliderSettings:
|
||||
- _lineHoverEps: 0.7
|
||||
@@ -5663,7 +5663,7 @@ MonoBehaviour:
|
||||
_staticData:
|
||||
CanHaveMouseButtons: 0
|
||||
_enableVertexSnapping:
|
||||
_isEnabled: 0
|
||||
_isEnabled: 1
|
||||
_key: 118
|
||||
_lCtrl: 0
|
||||
_lCmd: 0
|
||||
@@ -9801,7 +9801,7 @@ GameObject:
|
||||
- component: {fileID: 1833346087}
|
||||
- component: {fileID: 1833346086}
|
||||
- component: {fileID: 1833346090}
|
||||
m_Layer: 0
|
||||
m_Layer: 6
|
||||
m_Name: Plane
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
@@ -10136,7 +10136,7 @@ MonoBehaviour:
|
||||
_settings:
|
||||
_canBeDisplayed: 1
|
||||
_isExpanded: 1
|
||||
_physicsMode: 1
|
||||
_physicsMode: 2
|
||||
--- !u!224 &1959729457 stripped
|
||||
RectTransform:
|
||||
m_CorrespondingSourceObject: {fileID: 5526574206638406261, guid: ea83f56b6eed48b4d98d8ee2b8f4b6e9, type: 3}
|
||||
|
||||
@@ -4,6 +4,7 @@ using UnityEngine;
|
||||
using Studio.Command;
|
||||
using Studio.Core;
|
||||
using Studio.Manage;
|
||||
using Studio.AssetTool;
|
||||
|
||||
namespace Studio.RuntimeGizmo
|
||||
{
|
||||
@@ -114,6 +115,21 @@ namespace Studio.RuntimeGizmo
|
||||
objectUniversalGizmo.SetTargetObjects(selectedObjects);
|
||||
|
||||
workGizmo.Gizmo.SetEnabled(selectedObjects.Count != 0);
|
||||
|
||||
List<GameObject> meshObjects = new List<GameObject>();
|
||||
|
||||
foreach (GameObject go in selectedObjects)
|
||||
{
|
||||
CustomAssetRenderObject assetObj = go.GetComponent<CustomAssetRenderObject>();
|
||||
if (assetObj == null) continue;
|
||||
MeshRenderer[] renderer = assetObj.RenderObject.GetComponentsInChildren<MeshRenderer>(true);
|
||||
foreach (var r in renderer)
|
||||
{
|
||||
meshObjects.Add(r.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
objectMoveGizmo.Gizmo.MoveGizmo.SetVertexSnapTargetObjects(meshObjects);
|
||||
}
|
||||
public void ResetGizmo()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace RTG
|
||||
{
|
||||
@@ -57,33 +58,37 @@ namespace RTG
|
||||
_destinationObjects.Clear();
|
||||
}
|
||||
|
||||
List<Vector3> centersAndCorners = new List<Vector3>();
|
||||
protected override void CalculateDragValues()
|
||||
{
|
||||
Camera focusCamera = RTFocusCamera.Get.TargetCamera;
|
||||
_relativeDragOffset = Vector3.zero;
|
||||
|
||||
if (_destinationObjects.Count != 0 && _settings.CanSnapToObjectVerts)
|
||||
{
|
||||
Vector3 worldDestPos;
|
||||
if (GetWorldPointClosestToInputDevice(focusCamera, _destinationObjects, out worldDestPos))
|
||||
_relativeDragOffset = worldDestPos - _snapPivot;
|
||||
|
||||
return;
|
||||
if (GetWorldPointClosestToInputDevice(focusCamera, _destinationObjects, out worldDestPos)) _relativeDragOffset = worldDestPos - _snapPivot;
|
||||
}
|
||||
|
||||
if (_settings.CanSnapToGrid)
|
||||
else
|
||||
if(_settings.CanSnapToGrid)
|
||||
{
|
||||
Ray ray = RTInputDevice.Get.Device.GetRay(focusCamera);
|
||||
XZGridRayHit gridHit = RTScene.Get.RaycastSceneGridIfVisible(ray);
|
||||
if (gridHit != null)
|
||||
{
|
||||
XZGridCell gridCell = RTSceneGrid.Get.CellFromWorldPoint(gridHit.HitPoint);
|
||||
gridCell.GetCenterAndCorners(ref centersAndCorners);
|
||||
|
||||
List<Vector3> centersAndCorners = gridCell.GetCenterAndCorners();
|
||||
int closestPtIndex = Vector3Ex.GetPointClosestToPoint(centersAndCorners, gridHit.HitPoint);
|
||||
if (closestPtIndex >= 0)
|
||||
_relativeDragOffset = centersAndCorners[closestPtIndex] - _snapPivot;
|
||||
if (closestPtIndex >= 0) _relativeDragOffset = centersAndCorners[closestPtIndex] - _snapPivot;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Ray ray = RTInputDevice.Get.Device.GetRay(focusCamera);
|
||||
Plane dragPlane = new Plane(Vector3.up, _snapPivot);
|
||||
|
||||
if (dragPlane.Raycast(ray, out float enter))
|
||||
{
|
||||
Vector3 worldPoint = ray.GetPoint(enter);
|
||||
_relativeDragOffset = worldPoint - _snapPivot;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,11 +99,8 @@ namespace RTG
|
||||
protected bool GetWorldPointClosestToInputDevice(Camera focusCamera, IEnumerable<GameObject> gameObjects, out Vector3 point)
|
||||
{
|
||||
point = Vector3.zero;
|
||||
if (gameObjects == null)
|
||||
return false;
|
||||
|
||||
if (!RTInputDevice.Get.Device.HasPointer())
|
||||
return false;
|
||||
if (gameObjects == null) return false;
|
||||
if (!RTInputDevice.Get.Device.HasPointer()) return false;
|
||||
|
||||
Vector2 inputDeviceScreenPt = RTInputDevice.Get.Device.GetPositionYAxisUp();
|
||||
float minDistSqr = float.MaxValue;
|
||||
@@ -110,16 +112,14 @@ namespace RTG
|
||||
if (mesh != null)
|
||||
{
|
||||
MeshVertexChunkCollection meshVChunkCollection = MeshVertexChunkCollectionDb.Get[mesh];
|
||||
if (meshVChunkCollection == null)
|
||||
continue;
|
||||
if (meshVChunkCollection == null) continue;
|
||||
|
||||
Matrix4x4 worldMtx = srcObject.transform.localToWorldMatrix;
|
||||
List<MeshVertexChunk> testChunks = meshVChunkCollection.GetWorldChunksHoveredByPoint(inputDeviceScreenPt, worldMtx, focusCamera);
|
||||
if (testChunks.Count == 0)
|
||||
{
|
||||
MeshVertexChunk closestChunk = meshVChunkCollection.GetWorldVertChunkClosestToScreenPt(inputDeviceScreenPt, worldMtx, focusCamera);
|
||||
if (closestChunk != null && closestChunk.VertexCount != 0)
|
||||
testChunks.Add(closestChunk);
|
||||
if (closestChunk != null && closestChunk.VertexCount != 0) testChunks.Add(closestChunk);
|
||||
}
|
||||
|
||||
foreach (var chunk in testChunks)
|
||||
@@ -172,9 +172,7 @@ namespace RTG
|
||||
_destinationObjects.Clear();
|
||||
|
||||
IInputDevice inputDevice = RTInputDevice.Get.Device;
|
||||
if (!inputDevice.HasPointer())
|
||||
return;
|
||||
|
||||
if (!inputDevice.HasPointer()) return;
|
||||
Vector2 inputDevicePos = inputDevice.GetPositionYAxisUp();
|
||||
|
||||
var boundsQConfig = new ObjectBounds.QueryConfig();
|
||||
@@ -183,20 +181,17 @@ namespace RTG
|
||||
|
||||
RTFocusCamera.Get.GetVisibleObjects(_visibleObjectBuffer);
|
||||
List<GameObject> targetObjects = new List<GameObject>(_targetObjects);
|
||||
_visibleObjectBuffer
|
||||
.RemoveAll(a =>
|
||||
targetObjects.Contains(a) ||
|
||||
_visibleObjectBuffer.RemoveAll(a => targetObjects.Contains(a) ||
|
||||
!ObjectBounds.CalcScreenRect(a, focusCamera, boundsQConfig).Contains(inputDevicePos) ||
|
||||
targetObjects.FindAll(b => a.transform.IsChildOf(b.transform)).Count != 0);
|
||||
targetObjects.FindAll(b => a.transform.IsChildOf(b.transform)).Count != 0 ||
|
||||
a.GetComponent<MeshRenderer>()?.enabled == false);
|
||||
|
||||
foreach (var visibleObject in _visibleObjectBuffer)
|
||||
{
|
||||
if (!CanUseObjectAsSnapDestination(visibleObject))
|
||||
continue;
|
||||
if (!CanUseObjectAsSnapDestination(visibleObject)) continue;
|
||||
|
||||
GameObjectType objectType = visibleObject.GetGameObjectType();
|
||||
if (objectType == GameObjectType.Mesh || objectType == GameObjectType.Sprite)
|
||||
_destinationObjects.Add(visibleObject);
|
||||
if (objectType == GameObjectType.Mesh || objectType == GameObjectType.Sprite) _destinationObjects.Add(visibleObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,6 +215,25 @@ namespace RTG
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<(Mesh mesh, Transform transform)> GetAllMeshWithTransform(this GameObject root)
|
||||
{
|
||||
var result = new List<(Mesh, Transform)>();
|
||||
|
||||
foreach (var mf in root.GetComponentsInChildren<MeshFilter>(true))
|
||||
{
|
||||
if (mf.sharedMesh != null)
|
||||
result.Add((mf.sharedMesh, mf.transform));
|
||||
}
|
||||
|
||||
foreach (var smr in root.GetComponentsInChildren<SkinnedMeshRenderer>(true))
|
||||
{
|
||||
if (smr.sharedMesh != null)
|
||||
result.Add((smr.sharedMesh, smr.transform));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Renderer GetMeshRenderer(this GameObject gameObject)
|
||||
{
|
||||
MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer>();
|
||||
|
||||
@@ -44,9 +44,9 @@ namespace RTG
|
||||
return new XZGridCell(cellIndexX, cellIndexZ, cellMin, cellMax, parentGrid);
|
||||
}
|
||||
|
||||
public void GetCenterAndCorners(ref List<Vector3> centerAndCorners)
|
||||
public List<Vector3> GetCenterAndCorners()
|
||||
{
|
||||
centerAndCorners.Clear();
|
||||
var centerAndCorners = new List<Vector3>();
|
||||
centerAndCorners.Add(Center);
|
||||
|
||||
Vector3 minToMax = _max - _min;
|
||||
@@ -54,6 +54,8 @@ namespace RTG
|
||||
centerAndCorners.Add(_min + Vector3.forward * minToMax.z);
|
||||
centerAndCorners.Add(_max);
|
||||
centerAndCorners.Add(_min + Vector3.right * minToMax.x);
|
||||
|
||||
return centerAndCorners;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace Studio.AssetTool
|
||||
matCubeCollided = Resources.Load<Material>("Materials/Mat_CubeCollided");
|
||||
|
||||
boxCollider.gameObject.layer = LayerMask.NameToLayer("TwinObject");
|
||||
objectRenderer.gameObject.layer = LayerMask.NameToLayer("TwinObject");
|
||||
twinObjectMask = LayerMask.GetMask("TwinObject");
|
||||
}
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
|
||||
@@ -318,82 +318,6 @@ namespace Studio.AssetTool
|
||||
}
|
||||
CanvasManager.instance.GetCanvas<Canvas_Popup>().panel_dynamicobjectinfo.OnTransformChanged(objectsToAlign.Select(renderObject => renderObject.gameObject).ToList());
|
||||
}
|
||||
public void VertexSnap()
|
||||
{
|
||||
if (selectedRenderObjects.Count != 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//가장 가까운 오브젝트에 붙여준다.
|
||||
//Transform.position이 가깝다고 오브젝트 사이 기리가 꼭 가장 가까운 것은 아니기 때문에
|
||||
//오버랩 박스에 충돌되는 모든 오브젝트의 버텍스로 KDTree를 구성해 볼까 하다가 관두었다.
|
||||
float minDist = float.MaxValue;
|
||||
CustomAssetRenderObject fromObject = selectedRenderObjects[0];
|
||||
CustomAssetRenderObject toObject = null;
|
||||
Bounds fromBounds = fromObject.GetBounds();
|
||||
Collider[] colliders = Physics.OverlapBox(fromBounds.center, fromBounds.size * 2.0f);
|
||||
foreach (Collider collider in colliders)
|
||||
{
|
||||
if (collider.gameObject == fromObject.gameObject) continue;
|
||||
CustomAssetRenderObject otherObject = collider.gameObject.GetComponent<CustomAssetRenderObject>();
|
||||
if (otherObject != null)
|
||||
{
|
||||
float dist = Vector3.Magnitude(fromObject.transform.position - otherObject.transform.position);
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
toObject = otherObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toObject != null)
|
||||
{
|
||||
//선택된 오브젝트의 ConvexHull 버텍스 점을 계산해준다.
|
||||
//이는 iteration하는 버텍스 수를 줄이기 위해 해주며,
|
||||
//만약 선택된 오브젝트도 TDTree로 Nearest 포인트 탐지할 경우 toObject의 센터에 가장 가까운 포인트만 탐지되기 때문에 가장 가까운 버텍스 점이 골라지지 않는 경우가 있다.
|
||||
List<Vector3> verts = new List<Vector3>();
|
||||
List<int> tris = new List<int>();
|
||||
List<Vector3> normals = new List<Vector3>();
|
||||
convexHullCalculator.GenerateHull(fromObject.GetRenderObjectVertices(), false, ref verts, ref tris, ref normals);
|
||||
KDTree toTree = toObject.GetVertexPointKDTree();
|
||||
Vector3 nearestPoint = Vector3.zero;
|
||||
Vector3 snapPoint = Vector3.zero;
|
||||
float minDistance = float.MaxValue;
|
||||
for (int i = 0; i < verts.Count; i++)
|
||||
{
|
||||
Vector3 ptNearest = verts[i];
|
||||
Vector3 ptSnap = toTree.FindNearest(ptNearest);
|
||||
float tempDist = Vector3.Magnitude(ptSnap - ptNearest);
|
||||
if (tempDist < minDistance)
|
||||
{
|
||||
minDistance = tempDist;
|
||||
nearestPoint = ptNearest;
|
||||
snapPoint = ptSnap;
|
||||
}
|
||||
}
|
||||
//Vector3 direction = snapPoint - nearestPoint;
|
||||
//fromObject.transform.position += direction;
|
||||
List<Vector3> dir = new List<Vector3>() { snapPoint - nearestPoint };
|
||||
if (dir[0].magnitude < 0.5f)
|
||||
{
|
||||
fromObject.transform.position += dir[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
ActionCommand command = new ActionCommand(
|
||||
() =>
|
||||
{
|
||||
fromObject.transform.position += dir[0];
|
||||
},
|
||||
() =>
|
||||
{
|
||||
fromObject.transform.position -= dir[0];
|
||||
});
|
||||
CommandInvoker.instance.Invoke(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InputHandler myHandler;
|
||||
|
||||
public void StatusEnterEvent()
|
||||
@@ -422,7 +346,6 @@ namespace Studio.AssetTool
|
||||
downKeyActions.Add(KeyCode.E, () => SetGizmoChangedCommand(new ActivateScaleGizmoCommand()));
|
||||
downKeyActions.Add(KeyCode.R, () => SetGizmoChangedCommand(new ResetGizmoCommand()));
|
||||
downKeyActions.Add(KeyCode.Delete, () => CommandInvoker.instance.Invoke(new RemoveSelectObjectCommand()));
|
||||
getKeyActions.Add(KeyCode.V, VertexSnap);
|
||||
|
||||
var shortcutTable = new Dictionary<KeyCode, Dictionary<KeyCode, Action>>();
|
||||
#if UNITY_EDITOR
|
||||
|
||||
Reference in New Issue
Block a user