public static void RegisterIndirectInstancedAsset(IndirectInstancedAsset assetToRegister) { if (!m_registeredInstancedAssets.Contains(assetToRegister)) { m_assetsToRegister.Add(assetToRegister); } }
private static bool DetectInstancedAssets() { if (m_pickingColorRT != null && m_pickingColorTex != null && IsInSceneBounds(m_mousePosition, m_trueScreenDimensions)) { RenderTexture currentRT = RenderTexture.active; //Graphics.Blit(m_pickingColorRT, m_debugRT); RenderTexture.active = m_pickingColorRT; m_pickingColorTex.ReadPixels(new Rect(m_mousePosition.x, m_trueScreenDimensions.y - m_mousePosition.y, 1, 1), 0, 0, false); RenderTexture.active = currentRT; Vector2 decoded = Vector2.zero; bool instancedAssetDetected = DecodeInstanceFromColor(m_pickingColorTex.GetPixel(0, 0), ref decoded); if (instancedAssetDetected) { int objectID = (int)decoded.x; int instanceID = (int)decoded.y; //Debug.Log("Object ID is: " + objectID + " and Instance ID is: " + instanceID); IndirectInstancedAsset selectedAsset = m_registeredInstancedAssets[objectID]; Vector3 position = selectedAsset.m_instanceData.m_positions[instanceID]; //Debug.Log("Position of selected asset is: " + position.ToString("f3")); } return(instancedAssetDetected); } return(false); }
private static void OnUnregisterIndirectInstancedAsset(IndirectInstancedAsset assetToUnregister) { Debug.Log("Unregistered an indirect instanced asset"); //successfully unregistering an asset implies the indexes of assets in the registered list might change, which will change objectIDs //the shaders global objectID parameter must be updated to reflect this change DeselectInstancedAssets(); IndirectInstancedAsset asset; Material[][] toUpdate; for (int objectID = 0; objectID < m_registeredInstancedAssets.Count; objectID++) { asset = m_registeredInstancedAssets[objectID]; toUpdate = m_registeredMaterialArrays[asset]; for (int i = 0; i < toUpdate.Length; i++) { for (int j = 0; j < toUpdate[i].Length; j++) { toUpdate[i][j].SetFloat("_ObjectID", objectID); } } } if (m_registeredCommandBuffers != null && m_registeredCommandBuffers.ContainsKey(assetToUnregister)) { CommandBuffer toClear = m_registeredCommandBuffers[assetToUnregister]; if (toClear != null && m_sceneWindowInstance.m_debugCamera != null) { m_sceneWindowInstance.m_debugCamera.RemoveCommandBuffer(CameraEvent.BeforeImageEffects, toClear); toClear.Clear(); } m_registeredCommandBuffers.Remove(assetToUnregister); } if (m_registeredMaterialArrays != null && m_registeredMaterialArrays.ContainsKey(assetToUnregister)) { Material[][] toClear = m_registeredMaterialArrays[assetToUnregister]; if (toClear != null) { ClearObjectArray <Material>(toClear, x => { DestroyImmediate(x, false); Debug.Log("Destroying Material"); }); } m_registeredMaterialArrays.Remove(assetToUnregister); } if (m_registeredEditorComputeBuffers != null && m_registeredEditorComputeBuffers.ContainsKey(assetToUnregister)) { ComputeBuffer[] toClear = m_registeredEditorComputeBuffers[assetToUnregister]; if (toClear != null) { ClearObjectArray <ComputeBuffer>(toClear, x => { if (x != null) { x.Release(); x = null; } }); } m_registeredEditorComputeBuffers.Remove(assetToUnregister); } }
public static void UnregisterIndirectInstancedAsset(IndirectInstancedAsset assetToUnregister) { m_assetsToRegister.Remove(assetToUnregister); if (m_registeredInstancedAssets.Remove(assetToUnregister)) { OnUnregisterIndirectInstancedAsset(assetToUnregister); } }
private static void OnRegisterIndirectInstancedAsset(IndirectInstancedAsset assetToRegister) { m_registeredInstancedAssets.Add(assetToRegister); Debug.Log("Registered an indirect instanced asset"); int objectID = m_registeredInstancedAssets.IndexOf(assetToRegister); int numLods = assetToRegister.m_LodSettings.Length; //initialize materials and gpu buffers, and bind the gpu buffers to their respective materials Material[][] colorPickingMatArray = new Material[numLods][]; ComputeBuffer[] editorAppendBuffer = new ComputeBuffer[numLods]; for (int i = 0; i < numLods; i++) { editorAppendBuffer[i] = new ComputeBuffer(assetToRegister.m_instanceCount, sizeof(float), ComputeBufferType.Counter); assetToRegister.SetComputeBuffer(editorAppendBuffer[i], "lod" + i + "IDBuffer"); colorPickingMatArray[i] = new Material[assetToRegister.m_LodSettings[i].materialReferences.Length]; for (int j = 0; j < colorPickingMatArray[i].Length; j++) { colorPickingMatArray[i][j] = new Material(Shader.Find("JacksInstancing/ColorPickerShader")); colorPickingMatArray[i][j].SetBuffer("batchDataBuffer", assetToRegister.m_appendBuffers[i]); colorPickingMatArray[i][j].SetBuffer("instanceIDBuffer", editorAppendBuffer[i]); int cullMode = (int)assetToRegister.m_LodSettings[i].materialReferences[j].editorFaceCulling; colorPickingMatArray[i][j].SetInt("_CullMode", cullMode); colorPickingMatArray[i][j].SetFloat("_ObjectID", objectID); Debug.Log("Pass count is: " + assetToRegister.m_LodSettings[i].materialReferences[j].material.passCount); for (int k = 0; k < assetToRegister.m_LodSettings[i].materialReferences[j].material.passCount; k++) { Debug.Log(assetToRegister.m_LodSettings[i].materialReferences[j].material.GetPassName(k)); } } } m_registeredMaterialArrays.Add(assetToRegister, colorPickingMatArray); m_registeredEditorComputeBuffers.Add(assetToRegister, editorAppendBuffer); //initialize the command buffer to draw this instanced asset CommandBuffer pickingColorCommand = new CommandBuffer(); pickingColorCommand.name = assetToRegister.name + " Color Picking Draw"; pickingColorCommand.SetRenderTarget(m_pickingColorRT); for (int i = 0; i < numLods; i++) { for (int j = 0; j < assetToRegister.m_LodSettings[i].mesh.subMeshCount; j++) { if (colorPickingMatArray[i][j] != null) { pickingColorCommand.DrawMeshInstancedIndirect(assetToRegister.m_LodSettings[i].mesh, j, colorPickingMatArray[i][j], 0, assetToRegister.m_argsBuffersArray[i][j], 0); } } } m_sceneWindowInstance.m_debugCamera.AddCommandBuffer(CameraEvent.BeforeImageEffects, pickingColorCommand); m_registeredCommandBuffers.Add(assetToRegister, pickingColorCommand); }
void OnGUI() { if (m_thisWindow == null) { m_thisWindow = (ObjectSpawner)EditorWindow.GetWindow(typeof(ObjectSpawner)); } if (m_thisWindow != null) { m_thisWindow.minSize = m_minWindowSize; } //selectedStyle = EditorStyles.miniButton; //selectedStyle.normal.background = Texture2D.blackTexture; GUILayout.Label("Jack's Custom Instancing Manager", EditorStyles.boldLabel); EditorGUILayout.Space(); int registeredCount = SceneViewInstancing.m_registeredInstancedAssets.Count; for (int i = 0; i < registeredCount; i++) { IndirectInstancedAsset asset = SceneViewInstancing.m_registeredInstancedAssets[i]; if (!m_activeIcons.Exists(x => x.asset == asset)) { SelectableIcon newIcon = new SelectableIcon(); newIcon.asset = asset; newIcon.icon = null; newIcon.isSelected = false; m_activeIcons.Add(newIcon); } } //repaint unloaded icons and remove icons of assets that are no longer active in the scene for (int i = 0; i < m_activeIcons.Count; i++) { Mesh instancedObject = m_activeIcons[i].asset.m_LodSettings[0].mesh; if (instancedObject != null) { bool isLoadingAssetPreview = AssetPreview.IsLoadingAssetPreview(instancedObject.GetInstanceID()); SelectableIcon icon = m_activeIcons[i]; icon.icon = AssetPreview.GetAssetPreview(instancedObject); if (!icon.icon) { // We have a static preview it just hasn't been loaded yet. Repaint until we have it loaded. if (isLoadingAssetPreview) { Repaint(); } icon.icon = AssetPreview.GetMiniThumbnail(instancedObject); } m_activeIcons[i] = icon; //we cannot modify 1 part of a struct, we need to make a copy, modify it, then set the original to the copy } IndirectInstancedAsset asset = m_activeIcons[i].asset; if (!SceneViewInstancing.m_registeredInstancedAssets.Contains(asset)) { m_activeIcons.RemoveAt(i); } } int windowWidth = (int)EditorGUIUtility.currentViewWidth; int numColumns = Mathf.FloorToInt(windowWidth / m_buttonDimension); int numRows = Mathf.CeilToInt((float)registeredCount / numColumns); GUILayout.BeginArea(new Rect(10, 40, numColumns * m_buttonDimension, numRows * m_buttonDimension), Texture2D.whiteTexture, EditorStyles.helpBox); for (int i = 0; i < m_activeIcons.Count; i++) { if (i % numColumns == 0) { GUILayout.BeginHorizontal(); } SelectableIcon icon = m_activeIcons[i]; if (icon.isSelected) { GUI.backgroundColor = Color.blue; } else { GUI.backgroundColor = Color.white; } if (GUILayout.Button(icon.icon, GUILayout.Width(64), GUILayout.Height(64))) { icon.isSelected = !icon.isSelected; m_activeIcons[i] = icon; Debug.Log(icon.isSelected); } if (i % numColumns == (numColumns - 1)) { GUILayout.EndHorizontal(); } } GUILayout.EndArea(); }
private static void DrawHandle() { Tools.hidden = false; if (m_selectedInstancedAssets.Count > 0) { Tools.hidden = true; Vector2 lastSelectedInstance = m_lastSelectedInstancedObject; IndirectInstancedAsset asset = m_registeredInstancedAssets[(int)lastSelectedInstance.x]; Vector3 lastSelectedInstancePosition = asset.m_instanceData.m_positions[(int)lastSelectedInstance.y]; Vector4 vec4Rotation = asset.m_instanceData.m_rotations[(int)lastSelectedInstance.y]; Quaternion lastSelectedInstanceRotation = InstancingUtilities.QuaternionFromVector(vec4Rotation); if (Tools.pivotMode == PivotMode.Center) { Bounds selectedObjectsBounds = new Bounds(lastSelectedInstancePosition, Vector3.zero); for (int i = 0; i < m_selectedInstancedAssets.Count; i++) { lastSelectedInstance = m_selectedInstancedAssets[i]; asset = m_registeredInstancedAssets[(int)lastSelectedInstance.x]; lastSelectedInstancePosition = asset.m_instanceData.m_positions[(int)lastSelectedInstance.y]; selectedObjectsBounds.Encapsulate(lastSelectedInstancePosition); } for (int i = 0; i < Selection.transforms.Length; i++) { selectedObjectsBounds.Encapsulate(Selection.transforms[i].position); } lastSelectedInstancePosition = selectedObjectsBounds.center; } float handleSize = HandleUtility.GetHandleSize(lastSelectedInstancePosition); Quaternion previousRotation; if (Tools.pivotRotation == PivotRotation.Global) { previousRotation = Tools.handleRotation; } else { previousRotation = lastSelectedInstanceRotation; } EditorGUI.BeginChangeCheck(); Transform[] selectedGameObjects = Selection.transforms; switch (Tools.current) { case Tool.Move: if (m_currentEvent.type == EventType.MouseDown) { Debug.Log("Rebuilding initial lists."); //build a list of initial sizes of selected instances m_selectedInitialInstances.Clear(); for (int i = 0; i < m_selectedInstancedAssets.Count; i++) { Debug.Log("adding"); Vector2 currentInstance = m_selectedInstancedAssets[i]; Vector3 position = m_registeredInstancedAssets[(int)currentInstance.x].m_instanceData.m_positions[(int)currentInstance.y]; m_selectedInitialInstances.Add(position); Debug.Log("Count is: " + m_selectedInitialInstances.Count); } //build a list of initial sizes of selected game objects m_selectedInitialGameObjects.Clear(); for (int i = 0; i < selectedGameObjects.Length; i++) { Vector3 position = selectedGameObjects[i].localPosition; m_selectedInitialGameObjects.Add(position); } } Vector3 newPosition; if (Tools.pivotRotation == PivotRotation.Global) { newPosition = Handles.PositionHandle(lastSelectedInstancePosition, Quaternion.identity); } else { newPosition = Handles.PositionHandle(lastSelectedInstancePosition, lastSelectedInstanceRotation); } float xAxisMovement = newPosition.x - lastSelectedInstancePosition.x; float yAxisMovement = newPosition.y - lastSelectedInstancePosition.y; float zAxisMovement = newPosition.z - lastSelectedInstancePosition.z; if (EditorGUI.EndChangeCheck()) { UndoStateInstance.m_instance.m_lastUsedTool = Tool.Move; //set undo state here, else last used tool will change on mouse down and cause incorrect undo history based on tool swapping UndoStateInstance.m_instance.SetUndoState(m_selectedInitialInstances, m_selectedInstancedAssets); for (int i = 0; i < m_selectedInstancedAssets.Count; i++) { Vector2 currentInstance = m_selectedInstancedAssets[i]; IndirectInstancedAsset currentAsset = m_registeredInstancedAssets[(int)currentInstance.x]; Undo.RegisterCompleteObjectUndo(UndoStateInstance.m_instance, "Undo instanced move"); UndoStateInstance.m_instance.IncrementModifiedCounter(); if (Mathf.Abs(xAxisMovement) > 0.01f) { currentAsset.m_instanceData.m_positions[(int)currentInstance.y].x += xAxisMovement; } if (Mathf.Abs(yAxisMovement) > 0.01f) { currentAsset.m_instanceData.m_positions[(int)currentInstance.y].y += yAxisMovement; } if (Mathf.Abs(zAxisMovement) > 0.01f) { currentAsset.m_instanceData.m_positions[(int)currentInstance.y].z += zAxisMovement; } if (Mathf.Abs(xAxisMovement) > 0.01f || Mathf.Abs(yAxisMovement) > 0.01f || Mathf.Abs(zAxisMovement) > 0.01f) { currentAsset.AddDirtyPosition((int)currentInstance.y); } } Undo.RecordObjects(selectedGameObjects, "Undo game object move"); for (int i = 0; i < selectedGameObjects.Length; i++) { Vector3 displacedPosition = selectedGameObjects[i].position; if (Mathf.Abs(xAxisMovement) > 0.01f) { displacedPosition.x += xAxisMovement; } if (Mathf.Abs(yAxisMovement) > 0.01f) { displacedPosition.y += yAxisMovement; } if (Mathf.Abs(zAxisMovement) > 0.01f) { displacedPosition.z += zAxisMovement; } selectedGameObjects[i].position = displacedPosition; } } break; case Tool.Rotate: //allows rotation back to (0,0,0) with shift + n if (m_currentEvent.keyCode == KeyCode.N && m_currentEvent.shift) { for (int i = 0; i < m_selectedInstancedAssets.Count; i++) { Vector2 currentInstance = m_selectedInstancedAssets[i]; IndirectInstancedAsset currentAsset = m_registeredInstancedAssets[(int)currentInstance.x]; currentAsset.m_instanceData.m_rotations[(int)currentInstance.y] = new Vector4(0, 0, 0, 1); //The identity quaternion currentAsset.AddDirtyRotation((int)currentInstance.y); } //also reset the gizmo, this isnt really needed as the next frame will already be correct and 1 frame is not noticeable, but added for consistency Tools.handleRotation = Quaternion.identity; previousRotation = Quaternion.identity; } if (m_currentEvent.type == EventType.MouseDown) { Debug.Log("Rebuilding initial lists."); //build a list of initial sizes of selected instances m_selectedInitialInstances.Clear(); for (int i = 0; i < m_selectedInstancedAssets.Count; i++) { Vector2 currentInstance = m_selectedInstancedAssets[i]; Vector4 rotation = m_registeredInstancedAssets[(int)currentInstance.x].m_instanceData.m_rotations[(int)currentInstance.y]; m_selectedInitialInstances.Add(rotation); } //build a list of initial sizes of selected game objects m_selectedInitialGameObjects.Clear(); for (int i = 0; i < selectedGameObjects.Length; i++) { Vector4 rotation = InstancingUtilities.VectorFromQuaternion(selectedGameObjects[i].rotation); m_selectedInitialGameObjects.Add(rotation); } } Quaternion newRotation = Handles.RotationHandle(previousRotation, lastSelectedInstancePosition); //The new rotation value modified by the user's interaction with the handle. if (EditorGUI.EndChangeCheck()) { UndoStateInstance.m_instance.m_lastUsedTool = Tool.Rotate; UndoStateInstance.m_instance.SetUndoState(m_selectedInitialInstances, m_selectedInstancedAssets); Quaternion delta = Quaternion.Inverse(previousRotation) * newRotation; for (int i = 0; i < m_selectedInstancedAssets.Count; i++) { Vector2 currentInstance = m_selectedInstancedAssets[i]; IndirectInstancedAsset currentAsset = m_registeredInstancedAssets[(int)currentInstance.x]; Quaternion instancedObjectRotation = InstancingUtilities.QuaternionFromVector(currentAsset.m_instanceData.m_rotations[(int)currentInstance.y]); Undo.RegisterCompleteObjectUndo(UndoStateInstance.m_instance, "Undo instanced rotation"); UndoStateInstance.m_instance.IncrementModifiedCounter(); //lhs happens first, so if we want a local space rotation, we do a delta rotation in the objects frame of reference by object quaternion on lhs //if we want a world space rotation, then lhs is the delta, and the objects rotation happens after, in the world space frame of reference if (Tools.pivotRotation == PivotRotation.Local) { instancedObjectRotation = instancedObjectRotation * delta; } else { instancedObjectRotation = delta * instancedObjectRotation; } currentAsset.m_instanceData.m_rotations[(int)currentInstance.y] = InstancingUtilities.VectorFromQuaternion(instancedObjectRotation); currentAsset.AddDirtyRotation((int)currentInstance.y); } Undo.RecordObjects(selectedGameObjects, "Undo game object rotation"); for (int i = 0; i < selectedGameObjects.Length; i++) { Quaternion gameObjectRotation = selectedGameObjects[i].rotation; if (Tools.pivotRotation == PivotRotation.Local) { gameObjectRotation = gameObjectRotation * delta; } else { gameObjectRotation = delta * gameObjectRotation; } selectedGameObjects[i].rotation = gameObjectRotation; } //https://math.stackexchange.com/questions/40164/how-do-you-rotate-a-vector-by-a-unit-quaternion Tools.handleRotation = newRotation; } break; case Tool.Scale: //allows scaling back to (1,1,1) with shift + n if (m_currentEvent.keyCode == KeyCode.N && m_currentEvent.shift) { for (int i = 0; i < m_selectedInstancedAssets.Count; i++) { Vector2 currentInstance = m_selectedInstancedAssets[i]; IndirectInstancedAsset currentAsset = m_registeredInstancedAssets[(int)currentInstance.x]; currentAsset.m_instanceData.m_positions[(int)currentInstance.y].w = InstancingUtilities.PackScaleVectorToFloat(Vector3.one); currentAsset.AddDirtyScale((int)currentInstance.y); } } if (m_currentEvent.type == EventType.MouseDown) { m_currentScale = Vector3.one; Debug.Log("Rebuilding initial lists."); //build a list of initial sizes of selected instances m_selectedInitialInstances.Clear(); for (int i = 0; i < m_selectedInstancedAssets.Count; i++) { Vector2 currentInstance = m_selectedInstancedAssets[i]; float scale = m_registeredInstancedAssets[(int)currentInstance.x].m_instanceData.m_positions[(int)currentInstance.y].w; m_selectedInitialInstances.Add(new Vector4(scale, 0, 0, 0)); } //build a list of initial sizes of selected game objects m_selectedInitialGameObjects.Clear(); for (int i = 0; i < selectedGameObjects.Length; i++) { Vector3 scale = selectedGameObjects[i].localScale; m_selectedInitialGameObjects.Add(scale); } } Vector3 newScale = Handles.ScaleHandle(m_currentScale, lastSelectedInstancePosition, lastSelectedInstanceRotation, handleSize); if (EditorGUI.EndChangeCheck()) { UndoStateInstance.m_instance.m_lastUsedTool = Tool.Scale; UndoStateInstance.m_instance.SetUndoState(m_selectedInitialInstances, m_selectedInstancedAssets); m_currentScale = newScale; for (int i = 0; i < m_selectedInstancedAssets.Count; i++) { Vector2 currentInstance = m_selectedInstancedAssets[i]; IndirectInstancedAsset currentAsset = m_registeredInstancedAssets[(int)currentInstance.x]; Undo.RegisterCompleteObjectUndo(UndoStateInstance.m_instance, "Undo instanced scaling"); UndoStateInstance.m_instance.IncrementModifiedCounter(); currentAsset.m_instanceData.ModifyScale((int)currentInstance.y, m_currentScale, m_selectedInitialInstances[i].x); currentAsset.AddDirtyScale((int)currentInstance.y); } Undo.RecordObjects(selectedGameObjects, "Undo game object scaling"); for (int i = 0; i < selectedGameObjects.Length; i++) { Vector3 objectScale = InstancingUtilities.MultiplyVector3(m_selectedInitialGameObjects[i], m_currentScale); selectedGameObjects[i].localScale = objectScale; } } break; } } }