// Update is called once per frame void Update() { if (lastText == Text) { return; } lastText = Text; GameObjectUtil.DestroyAllChildren(this.transform); char[] chars = Text.ToCharArray(); Vector3 currentPos = transform.position; for (int i = 0; i < Text.Length; i++) { char c = chars[i]; NPVoxFont.Character character = Font.GetCharacter(c); if (!character.mesh || !character.material) { Debug.LogWarning("Character " + (int)c + " Not found in Font: " + c); continue; } NPVoxToUnity n2u = new NPVoxToUnity(character.Size, character.VoxelSize); GameObject go = GameObject.Instantiate(Font.CharacterPrefab, this.transform); go.transform.position = currentPos + n2u.ToUnityDirection(new Vector3(((float)character.Size.X) * 0.5f, 0.0f, 0.0f)); currentPos += n2u.ToUnityDirection(new NPVoxCoord(character.Size.X, 0, 0)); go.name = (int)c + ""; go.GetComponent <MeshFilter>().sharedMesh = character.mesh; go.GetComponent <MeshRenderer>().sharedMaterial = character.material; } }
private bool DrawBoxSelection() { if (viewModel.PreviousModelFactory == null) { return(false); } NPVoxModel previousTransformedModel = viewModel.PreviousModelFactory.GetProduct(); NPVoxToUnity npVoxToUnity = new NPVoxToUnity(previousTransformedModel, viewModel.Animation.MeshFactory.VoxelSize); List <NPVoxBox> boxes = viewModel.GetNonEditableBoxes(); if (boxes != null) { foreach (NPVoxBox b in boxes) { NPVoxHandles.DrawBoxSelection(npVoxToUnity, b, false); } } if (!viewModel.IsAreaSelectionActive()) { return(false); } NPVoxBox box = viewModel.GetAffectedBox(); if (Event.current.shift) { // affected area picker NPVoxCoord someCoord = box.RoundedCenter; NPVoxCoord someNewCoord = NPVoxHandles.VoxelPicker(new NPVoxToUnity(previousTransformedModel, viewModel.Animation.MeshFactory.VoxelSize), someCoord, 0, ((NPVoxAnimationEditorSession)target).previewFilter.transform); if (!someCoord.Equals(someNewCoord)) { viewModel.ChangeAffectedBox(new NPVoxBox(someNewCoord, someNewCoord)); } } else { // affected area box NPVoxBox newBox = NPVoxHandles.DrawBoxSelection(npVoxToUnity, box); if (!newBox.Equals(box)) { viewModel.ChangeAffectedBox(newBox); } } return(true); }
private bool DrawBoneSelection() { if (viewModel.PreviousModelFactory == null) { return(false); } NPVoxBoneModel previewModel = viewModel.EditorModelFactory.GetProduct() as NPVoxBoneModel; if (previewModel == null) { return(false); } if (!viewModel.IsBoneSelectionActive()) { return(false); } NPVoxToUnity npVoxToUnity = new NPVoxToUnity(previewModel, viewModel.Animation.MeshFactory.VoxelSize); // affected area picker if (Event.current.isMouse && Event.current.type == EventType.MouseDown && Event.current.button == 0) { // NPVoxCoord someCoord = NPVoxCoord.INVALID; float mouseScale = NPVoxHandles.GetMouseScale(SceneView.currentDrawingSceneView.camera); Camera cam = SceneView.currentDrawingSceneView.camera; Ray r = SceneView.currentDrawingSceneView.camera.ScreenPointToRay( new Vector3(Event.current.mousePosition.x * mouseScale, -Event.current.mousePosition.y * mouseScale + Camera.current.pixelHeight) ); NPVoxRayCastHit raycastHit = npVoxToUnity.Raycast(r, ((NPVoxAnimationEditorSession)target).previewFilter.transform, 20); if (raycastHit.IsHit) { uint boneMask = previewModel.GetBoneMask(raycastHit.Coord); if (boneMask != 0) { if (Event.current.control || Event.current.command) { viewModel.ToggleBoneMask(boneMask, Event.current.shift); } else { viewModel.SetBoneMask(boneMask, Event.current.shift); } } } } return(true); }
public void Set(NPVoxMeshOutput _meshOutput, NPVoxNormalProcessor _processor) { MeshOutput = _meshOutput; ViewedProcessor = _processor; PreviewObject = MeshOutput.Instatiate(); VoxToUnity = new NPVoxToUnity(MeshOutput.GetVoxModel(), MeshOutput.VoxelSize); MeshFilter mf = PreviewObject.GetComponent <MeshFilter>(); PreviewMesh = Mesh.Instantiate <Mesh>(mf.sharedMesh); mf.sharedMesh = PreviewMesh; PreviewObject.hideFlags = HideFlags.HideAndDontSave; PreviewObject.SetActive(false); IsValid = true; }
private void DrawSockets(bool isEditing) { NPVoxIModelFactory modelFactory = viewModel.EditorModelFactory; if (!viewModel.DrawSockets) { return; } if (modelFactory != null) { NPVoxModel model = modelFactory.GetProduct(); NPVoxToUnity npVoxToUnity = new NPVoxToUnity(model, viewModel.Animation.MeshFactory.VoxelSize); if (model) { foreach (NPVoxSocket socket in model.Sockets) { Vector3 anchorPos = npVoxToUnity.ToUnityPosition(socket.Anchor); Quaternion rotation = Quaternion.Euler(socket.EulerAngles); Vector3 anchorRight = npVoxToUnity.ToUnityDirection(rotation * Vector3.right); Vector3 anchorUp = npVoxToUnity.ToUnityDirection(rotation * Vector3.up); Vector3 anchorForward = npVoxToUnity.ToUnityDirection(rotation * Vector3.forward); Vector3 position = Vector3.zero; float size = 2.5f; if (!isEditing) { Handles.color = new Color(0.5f, 1.0f, 0.1f, 0.5f); Handles.CubeCap(0, position + anchorPos, rotation, 0.125f); size = 10.0f; } Handles.color = Color.red; Handles.DrawLine(position + anchorPos, position + anchorPos + anchorRight * size); Handles.color = Color.green; Handles.DrawLine(position + anchorPos, position + anchorPos + anchorUp * size); Handles.color = Color.blue; Handles.DrawLine(position + anchorPos, position + anchorPos + anchorForward * size); } } } }
public static NPVoxModel SocketTransform(NPVoxModel sourceModel, NPVoxModel targetModel, NPVoxSocket sourceSocket, NPVoxSocket targetSocket, ResolveConflictMethodType resolveConflictMethod = ResolveConflictMethodType.CLOSEST, NPVoxModel reuse = null) { NPVoxToUnity sourceVox2Unity = new NPVoxToUnity(sourceModel, Vector3.one); NPVoxToUnity targetVox2Unity = new NPVoxToUnity(targetModel, Vector3.one); Vector3 sourceAnchorPos = sourceVox2Unity.ToUnityPosition(sourceSocket.Anchor); Quaternion sourceRotation = Quaternion.Euler(sourceSocket.EulerAngles); Vector3 targetAnchorPos = targetVox2Unity.ToUnityPosition(targetSocket.Anchor); Quaternion targetRotation = Quaternion.Euler(targetSocket.EulerAngles); Vector3 diff = sourceVox2Unity.ToSaveVoxDirection(targetAnchorPos - sourceAnchorPos); Matrix4x4 A = Matrix4x4.TRS(sourceVox2Unity.ToSaveVoxCoord(sourceAnchorPos), Quaternion.identity, Vector3.one); Matrix4x4 B = Matrix4x4.TRS(Vector3.zero, sourceRotation, Vector3.one).inverse *Matrix4x4.TRS(Vector3.zero, targetRotation, Vector3.one); Matrix4x4 C = Matrix4x4.TRS(-sourceVox2Unity.ToSaveVoxCoord(sourceAnchorPos), Quaternion.identity, Vector3.one); Matrix4x4 D = Matrix4x4.TRS(diff, Quaternion.identity, Vector3.one); Matrix4x4 transformMatrix = D * A * B * C; return(Transform(sourceModel, sourceModel.BoundingBox, transformMatrix, resolveConflictMethod, reuse)); }
public System.Func <NPVoxISceneEditable, bool> DrawSceneTool(NPVoxToUnity npVoxToUnity, UnityEngine.Transform transform, int tool) { // offset if (CurrentEditedBone == null) { return(null); } NPVoxBoneModel boneModel = GetProduct() as NPVoxBoneModel; if (boneModel == null) { return(null); } if (lastMask != 1u << (CurrentEditedBone.ID - 1)) { lastMask = 1u << (CurrentEditedBone.ID - 1); currentPivot = npVoxToUnity.ToUnityPosition(boneModel.GetAffectedArea(lastMask).SaveCenter); } Vector3 offset = npVoxToUnity.ToUnityDirection(CurrentEditedBone.Anchor); if (tool == 0) { offset = npVoxToUnity.ToSaveVoxDirection(Handles.PositionHandle(currentPivot + offset, Quaternion.identity) - currentPivot); if (offset != CurrentEditedBone.Anchor) { return((NPVoxISceneEditable t) => { NPVoxBone.GetBoneByID(ref ((NPVoxSkeletonBuilder)t).AllBones, CurrentEditedBone.ID).Anchor = offset; return true; }); } } return(null); }
private void DrawSceneEditTools() { if (!viewModel.IsSceneEditToolsActive()) { return; } NPVoxToUnity npVoxToUnity = new NPVoxToUnity(viewModel.PreviousModelFactory.GetProduct(), viewModel.Animation.MeshFactory.VoxelSize); if (!(viewModel.SelectedTransformer is NPVoxISceneEditable)) { return; } System.Func <NPVoxISceneEditable, bool> applyFunction = ((NPVoxISceneEditable)viewModel.SelectedTransformer).DrawSceneTool(npVoxToUnity, ((NPVoxAnimationEditorSession)target).previewFilter.transform, viewModel.CurrentCustomTool); if (applyFunction != null) { viewModel.ChangeTransformation(applyFunction); } }
public static Bounds DrawBoundsSelection(Bounds previous, Vector3 cellOffset, float cellSize) { NPVoxToUnity npVoxToUnity = new NPVoxToUnity(null, Vector3.one * cellSize, cellOffset - Vector3.one * 0.5f * cellSize); NPVoxBox previousBox = new NPVoxBox( npVoxToUnity.ToVoxCoord(previous.min + Vector3.one * cellSize / 2), npVoxToUnity.ToVoxCoord(previous.max - Vector3.one * cellSize / 2) ); NPVoxBox newBox = NPVoxHandles.DrawBoxSelection(npVoxToUnity, previousBox, true); if (!previousBox.Equals(newBox)) { Bounds bounds = new Bounds(Vector3.zero, Vector3.zero); bounds.SetMinMax( npVoxToUnity.ToUnityPosition(newBox.LeftDownBack) - Vector3.one * cellSize / 2, npVoxToUnity.ToUnityPosition(newBox.RightUpForward) + Vector3.one * cellSize / 2 ); return(bounds); } else { return(previous); } }
void OnDrawGizmos() { // if (Selection.activeGameObject != this.gameObject) // { // return; // } NPVoxMeshOutput MeshOutput = MeshFactory as NPVoxMeshOutput; if (MeshOutput) { NPVoxToUnity npVoxToUnity = MeshOutput.GetNPVoxToUnity(); NPVoxModel model = MeshOutput.GetVoxModel(); if (model) { foreach (NPVoxSocket socket in model.Sockets) { Vector3 anchorPos = npVoxToUnity.ToUnityPosition(socket.Anchor); Quaternion rotation = Quaternion.Euler(socket.EulerAngles); Vector3 anchorRight = npVoxToUnity.ToUnityDirection(rotation * Vector3.right); Vector3 anchorUp = npVoxToUnity.ToUnityDirection(rotation * Vector3.up); Vector3 anchorForward = npVoxToUnity.ToUnityDirection(rotation * Vector3.forward); Gizmos.color = new Color(0.5f, 1.0f, 0.1f, 0.75f); Gizmos.DrawCube(transform.position + anchorPos, Vector3.one * 0.4f); Gizmos.color = Color.red; Gizmos.DrawLine(transform.position + anchorPos, transform.position + anchorPos + anchorRight * 10.0f); Gizmos.color = Color.green; Gizmos.DrawLine(transform.position + anchorPos, transform.position + anchorPos + anchorUp * 10.0f); Gizmos.color = Color.blue; Gizmos.DrawLine(transform.position + anchorPos, transform.position + anchorPos + anchorForward * 10.0f); } } } }
public System.Func <NPVoxISceneEditable, bool> DrawSceneTool(NPVoxToUnity npVoxToUnity, Transform transform, int tool) { if (Input == null) { return(null); } NPVoxModel model = ((NPVoxIModelFactory)Input).GetProduct() as NPVoxModel; if (!model) { return(null); } // Start Coord 1 if (tool == 0) { NPVoxCoord someNewCoord = NPVoxHandles.VoxelPicker(npVoxToUnity, startCoord1, 0, transform); if (!startCoord1.Equals(someNewCoord)) { return((NPVoxISceneEditable t) => { (t as NPVoxTrailAttacher).startCoord1 = someNewCoord; return true; }); } } // Start Coord 2 if (tool == 1) { NPVoxCoord someNewCoord = NPVoxHandles.VoxelPicker(npVoxToUnity, startCoord2, 0, transform); if (!startCoord2.Equals(someNewCoord)) { return((NPVoxISceneEditable t) => { (t as NPVoxTrailAttacher).startCoord2 = someNewCoord; return true; }); } } // Direction 1 if (tool == 2) { Quaternion newQuaternion = Handles.RotationHandle(rotation1, npVoxToUnity.ToUnityPosition(startCoord1)); if (!newQuaternion.Equals(rotation1)) { return((NPVoxISceneEditable t) => { (t as NPVoxTrailAttacher).rotation1 = newQuaternion; return true; }); } } // Direction 2 if (tool == 3) { Quaternion newQuaternion = Handles.RotationHandle(rotation2, npVoxToUnity.ToUnityPosition(startCoord2)); if (!newQuaternion.Equals(rotation2)) { return((NPVoxISceneEditable t) => { (t as NPVoxTrailAttacher).rotation2 = newQuaternion; return true; }); } } return(null); }
override protected Mesh CreateProduct(Mesh mesh = null) { // Debug.Log("create product"); NPVoxMeshOutput meshOutput = (Input as NPVoxMeshOutput); if (meshOutput && meshOutput.GetProduct() && TextureAtlas) { TextureAtlas.GetMaterial(SourceMaterial); NPVoxFaces includedFaces = GetIncludedFaces(); NPVoxToUnity npVoxToUnity = InputMeshFactory.GetNPVoxToUnity(); int faceCount = GetFaceCount(); NPVoxBox originalBox = InputMeshFactory.GetVoxModel().BoundingBox; NPVoxBox cutoutBox = originalBox.Clone(); NPVoxFaces cutout = InputMeshFactory.Cutout; Vector3 cutoutOffset = Vector3.zero; if (cutout != null) { Vector3 originalCenter = cutoutBox.SaveCenter; cutoutBox.Left = (sbyte)Mathf.Abs(cutout.Left); cutoutBox.Down = (sbyte)Mathf.Abs(cutout.Down); cutoutBox.Back = (sbyte)Mathf.Abs(cutout.Back); cutoutBox.Right = (sbyte)(cutoutBox.Right - (sbyte)Mathf.Abs(cutout.Right)); cutoutBox.Up = (sbyte)(cutoutBox.Up - (sbyte)Mathf.Abs(cutout.Up)); cutoutBox.Forward = (sbyte)(cutoutBox.Forward - (sbyte)Mathf.Abs(cutout.Forward)); cutoutOffset = Vector3.Scale(originalCenter - cutoutBox.SaveCenter, InputMeshFactory.VoxelSize); } // we have to be careful. Unlike cutout, which is already removed from the mesh we want to render, the inset is not yet applied and // also won't result in a "move" of the object. So it's important that we calculate a correct offset for our final mesh. NPVoxBox insetBox = cutoutBox.Clone(); Vector3 insetOffset = Vector3.zero; if (inset != null) { Vector3 cutoutCenter = cutoutBox.SaveCenter; insetBox.Left += (sbyte)Mathf.Abs(inset.Left); insetBox.Right -= (sbyte)Mathf.Abs(inset.Right); insetBox.Down += (sbyte)Mathf.Abs(inset.Down); insetBox.Up -= (sbyte)Mathf.Abs(inset.Up); insetBox.Back += (sbyte)Mathf.Abs(inset.Back); insetBox.Forward -= (sbyte)Mathf.Abs(inset.Forward); insetOffset = Vector3.Scale(cutoutCenter - insetBox.SaveCenter, InputMeshFactory.VoxelSize); } Vector3 insetCenter = insetBox.SaveCenter; if (Baked45Angle) { backSlot = CreateTexture(backSlot, includedFaces.Back != 0, insetBox.Size.X, insetBox.Size.Y, Quaternion.Euler(-45, 0, 0), npVoxToUnity.ToUnityPosition(new Vector3(insetCenter.x, insetCenter.y, insetBox.Back)), npVoxToUnity.ToUnityDirection(new Vector2(insetBox.Size.X, ((float)insetBox.Size.Y) / Mathf.Sqrt(2))) * 0.5f, Quaternion.Euler(+45, 0, 0) ); downSlot = CreateTexture(downSlot, includedFaces.Down != 0, insetBox.Size.X, insetBox.Size.Z * 3, Quaternion.Euler(-45, 0, 0), npVoxToUnity.ToUnityPosition(new Vector3(insetCenter.x, insetBox.Down, insetCenter.z)), npVoxToUnity.ToUnityDirection(new Vector2(insetBox.Size.X, ((float)insetBox.Size.Z) / Mathf.Sqrt(2))) * 0.5f, Quaternion.Euler(-45, 0, 0) ); leftSlot = CreateTexture(leftSlot, false, 0, 0, Quaternion.identity, Vector3.zero, Vector2.zero, Quaternion.identity); rightSlot = CreateTexture(rightSlot, false, 0, 0, Quaternion.identity, Vector3.zero, Vector2.zero, Quaternion.identity); upSlot = CreateTexture(upSlot, false, 0, 0, Quaternion.identity, Vector3.zero, Vector2.zero, Quaternion.identity); forwardSlot = CreateTexture(forwardSlot, false, 0, 0, Quaternion.identity, Vector3.zero, Vector2.zero, Quaternion.identity); } else { leftSlot = CreateTexture(leftSlot, includedFaces.Left != 0, insetBox.Size.Z, insetBox.Size.Y, Quaternion.Euler(0, 90, 0), npVoxToUnity.ToUnityPosition(new Vector3(insetBox.Left, insetCenter.y, insetCenter.z)), npVoxToUnity.ToUnityDirection(new Vector2(insetBox.Size.Z, insetBox.Size.Y)) * 0.5f, Quaternion.identity ); rightSlot = CreateTexture(rightSlot, includedFaces.Right != 0, insetBox.Size.Z, insetBox.Size.Y, Quaternion.Euler(0, -90, 0), npVoxToUnity.ToUnityPosition(new Vector3(insetBox.Right, insetCenter.y, insetCenter.z)), npVoxToUnity.ToUnityDirection(new Vector2(insetBox.Size.Z, insetBox.Size.Y)) * 0.5f, Quaternion.identity ); downSlot = CreateTexture(downSlot, includedFaces.Down != 0, insetBox.Size.X, insetBox.Size.Z, Quaternion.Euler(-90, 0, 0), npVoxToUnity.ToUnityPosition(new Vector3(insetCenter.x, insetBox.Down, insetCenter.z)), npVoxToUnity.ToUnityDirection(new Vector2(insetBox.Size.X, insetBox.Size.Z)) * 0.5f, Quaternion.identity ); upSlot = CreateTexture(upSlot, includedFaces.Up != 0, insetBox.Size.X, insetBox.Size.Z, Quaternion.Euler(90, 0, 180), npVoxToUnity.ToUnityPosition(new Vector3(insetCenter.x, insetBox.Up, insetCenter.z)), npVoxToUnity.ToUnityDirection(new Vector2(insetBox.Size.X, insetBox.Size.Z)) * 0.5f, Quaternion.identity ); backSlot = CreateTexture(backSlot, includedFaces.Back != 0, insetBox.Size.X, insetBox.Size.Y, Quaternion.Euler(0, 0, 0), npVoxToUnity.ToUnityPosition(new Vector3(insetCenter.x, insetCenter.y, insetBox.Back)), npVoxToUnity.ToUnityDirection(new Vector2(insetBox.Size.X, insetBox.Size.Y)) * 0.5f, Quaternion.identity ); forwardSlot = CreateTexture(forwardSlot, includedFaces.Forward != 0, insetBox.Size.X, insetBox.Size.Y, Quaternion.Euler(-180, 0, 0), npVoxToUnity.ToUnityPosition(new Vector3(insetCenter.x, insetCenter.y, insetBox.Forward)), npVoxToUnity.ToUnityDirection(new Vector2(insetBox.Size.X, insetBox.Size.Y)) * 0.5f, Quaternion.identity ); } slotsAllocatedAtTA = TextureAtlas; if (mesh == null) { mesh = new Mesh(); } else { mesh.Clear(); } mesh.name = "zzz Cube Simplifier Mesh"; int border = 1; var vertices = new Vector3[faceCount * 4]; var uvs = new Vector2[faceCount * 4]; var tris = new int[faceCount * 3 * 2]; var normals = new Vector3[faceCount * 4]; int v = 0; int t = 0; int v0 = 0; System.Action <Vector3, NPVoxTextureAtlas.Slot> addQuad = (Vector3 dir, NPVoxTextureAtlas.Slot theSlot) => { normals[v0] = dir; normals[v0 + 1] = dir; normals[v0 + 2] = dir; normals[v0 + 3] = dir; tris[t++] = v0; tris[t++] = v0 + 1; tris[t++] = v0 + 2; tris[t++] = v0; tris[t++] = v0 + 2; tris[t++] = v0 + 3; Vector2 uvMax = theSlot.GetUVmax(border); Vector2 uvMin = theSlot.GetUVmin(border); uvs[v0].x = uvMin.x; uvs[v0].y = uvMax.y; uvs[v0 + 1].x = uvMax.x; uvs[v0 + 1].y = uvMax.y; uvs[v0 + 2].x = uvMax.x; uvs[v0 + 2].y = uvMin.y; uvs[v0 + 3].x = uvMin.x; uvs[v0 + 3].y = uvMin.y; }; NPVoxBox bounds = insetBox; Vector3 LDB = cutoutOffset + npVoxToUnity.ToUnityPosition(bounds.LeftDownBack) + (Vector3.left * npVoxToUnity.VoxeSize.x + Vector3.down * npVoxToUnity.VoxeSize.y + Vector3.back * npVoxToUnity.VoxeSize.z) * 0.5f; Vector3 RDB = cutoutOffset + npVoxToUnity.ToUnityPosition(bounds.RightDownBack) + (Vector3.right * npVoxToUnity.VoxeSize.x + Vector3.down * npVoxToUnity.VoxeSize.y + Vector3.back * npVoxToUnity.VoxeSize.z) * 0.5f; Vector3 LUB = cutoutOffset + npVoxToUnity.ToUnityPosition(bounds.LeftUpBack) + (Vector3.left * npVoxToUnity.VoxeSize.x + Vector3.up * npVoxToUnity.VoxeSize.y + Vector3.back * npVoxToUnity.VoxeSize.z) * 0.5f; Vector3 RUB = cutoutOffset + npVoxToUnity.ToUnityPosition(bounds.RightUpBack) + (Vector3.right * npVoxToUnity.VoxeSize.x + Vector3.up * npVoxToUnity.VoxeSize.y + Vector3.back * npVoxToUnity.VoxeSize.z) * 0.5f; Vector3 LDF = cutoutOffset + npVoxToUnity.ToUnityPosition(bounds.LeftDownForward) + (Vector3.left * npVoxToUnity.VoxeSize.x + Vector3.down * npVoxToUnity.VoxeSize.y + Vector3.forward * npVoxToUnity.VoxeSize.z) * 0.5f; Vector3 RDF = cutoutOffset + npVoxToUnity.ToUnityPosition(bounds.RightDownForward) + (Vector3.right * npVoxToUnity.VoxeSize.x + Vector3.down * npVoxToUnity.VoxeSize.y + Vector3.forward * npVoxToUnity.VoxeSize.z) * 0.5f; Vector3 LUF = cutoutOffset + npVoxToUnity.ToUnityPosition(bounds.LeftUpForward) + (Vector3.left * npVoxToUnity.VoxeSize.x + Vector3.up * npVoxToUnity.VoxeSize.y + Vector3.forward * npVoxToUnity.VoxeSize.z) * 0.5f; Vector3 RUF = cutoutOffset + npVoxToUnity.ToUnityPosition(bounds.RightUpForward) + (Vector3.right * npVoxToUnity.VoxeSize.x + Vector3.up * npVoxToUnity.VoxeSize.y + Vector3.forward * npVoxToUnity.VoxeSize.z) * 0.5f; if (downSlot != null) { v0 = v; vertices[v++] = LDB; vertices[v++] = RDB; vertices[v++] = RDF; vertices[v++] = LDF; addQuad(Vector3.down, downSlot); } if (upSlot != null) { v0 = v; vertices[v++] = RUB; vertices[v++] = LUB; vertices[v++] = LUF; vertices[v++] = RUF; addQuad(Vector3.up, upSlot); } if (forwardSlot != null) { v0 = v; vertices[v++] = LDF; vertices[v++] = RDF; vertices[v++] = RUF; vertices[v++] = LUF; addQuad(Vector3.forward, forwardSlot); } if (backSlot != null) { v0 = v; vertices[v++] = LUB; vertices[v++] = RUB; vertices[v++] = RDB; vertices[v++] = LDB; addQuad(Vector3.back, backSlot); } if (leftSlot != null) { v0 = v; vertices[v++] = LUF; vertices[v++] = LUB; vertices[v++] = LDB; vertices[v++] = LDF; addQuad(Vector3.left, leftSlot); } if (rightSlot != null) { v0 = v; vertices[v++] = RUB; vertices[v++] = RUF; vertices[v++] = RDF; vertices[v++] = RDB; addQuad(Vector3.right, rightSlot); } mesh.vertices = vertices; mesh.triangles = tris; mesh.uv = uvs; mesh.RecalculateBounds(); mesh.normals = normals; TangentSolver.Solve(mesh); // mesh.bounds = new Bounds( // insetOffset, // new Vector3( // bounds.Size.X * npVoxToUnity.VoxeSize.x, // bounds.Size.Y * npVoxToUnity.VoxeSize.y, // bounds.Size.Z * npVoxToUnity.VoxeSize.z // ) // ); Mesh sourceMesh = meshOutput.GetProduct(); mesh.bounds = sourceMesh.bounds; mesh.name = "zzz Cube Mesh "; return(mesh); } else { Debug.LogWarning("No Input set up"); if (mesh == null) { mesh = new Mesh(); } else { mesh.Clear(); } return(mesh); } }
public static sbyte DrawAxisHandle(Vector3 handlePosition, sbyte voxPosition, NPVoxToUnity npVoxToUnity, Vector3 axis) { int controlID = GUIUtility.GetControlID(FocusType.Passive); Handles.DotCap(controlID, handlePosition, Quaternion.identity, npVoxToUnity.VoxeSize.x * 0.25f); Vector3 screenPosition = Handles.matrix.MultiplyPoint(handlePosition); switch (Event.current.GetTypeForControl(controlID)) { case EventType.Layout: HandleUtility.AddControl( controlID, HandleUtility.DistanceToCircle(screenPosition, npVoxToUnity.VoxeSize.x * 0.25f * (1 + npVoxToUnity.UnityVoxModelSize.x)) ); break; case EventType.MouseDown: if (HandleUtility.nearestControl == controlID) { mouseStartPos = Event.current.mousePosition; startCoord = voxPosition; // Respond to a press on this handle. Drag starts automatically. GUIUtility.hotControl = controlID; Event.current.Use(); } break; case EventType.MouseUp: if (GUIUtility.hotControl == controlID) { // Respond to a release on this handle. Drag stops automatically. GUIUtility.hotControl = 0; Event.current.Use(); } break; case EventType.MouseDrag: if (GUIUtility.hotControl == controlID) { // Do whatever with mouse deltas here GUI.changed = true; float transl = HandleUtility.CalcLineTranslation(mouseStartPos, Event.current.mousePosition, handlePosition, axis); sbyte result; if (axis == Vector3.forward) { result = (sbyte)(startCoord + npVoxToUnity.ToVoxDirection(Vector3.forward * transl).Z); } else if (axis == Vector3.right) { result = (sbyte)(startCoord + npVoxToUnity.ToVoxDirection(Vector3.right * transl).X); } else { result = (sbyte)(startCoord + npVoxToUnity.ToVoxDirection(Vector3.up * transl).Y); } if (result != voxPosition) { SceneView.RepaintAll(); return(result); } } break; } return(voxPosition); }
public static NPVoxCoord VoxelPicker(NPVoxToUnity npVoxToUnity, NPVoxCoord previousSelectedCoord, int buttonNum, Transform transform) { if (npVoxToUnity == null) { return(NPVoxCoord.INVALID); } int controlID = GUIUtility.GetControlID(FocusType.Passive); EventType eventType = Event.current.GetTypeForControl(controlID); Vector3 voxelCenter = new Vector3(); NPVoxCoord impactCoord = NPVoxCoord.INVALID; // Vector3 offset = SceneView.currentDrawingSceneView.position; // Vector3 mp = Event.current.mousePosition - offset; float mouseScale = GetMouseScale(SceneView.currentDrawingSceneView.camera); Ray r = SceneView.currentDrawingSceneView.camera.ScreenPointToRay( new Vector3(Event.current.mousePosition.x * mouseScale, -Event.current.mousePosition.y * mouseScale + Camera.current.pixelHeight) ); NPVoxRayCastHit raycastHit = npVoxToUnity.Raycast(r, transform, 20); if (raycastHit.IsHit) { impactCoord = raycastHit.Coord; voxelCenter = npVoxToUnity.ToUnityPosition(impactCoord); // if (isMouseDown) { Handles.color = Color.yellow; Handles.CubeCap(controlID, voxelCenter, Quaternion.identity, npVoxToUnity.VoxeSize.x * 2.0f); // SceneView.currentDrawingSceneView.Repaint(); } } else { return(previousSelectedCoord); } switch (eventType) { case EventType.Layout: mouseStartPos = Event.current.mousePosition; // if (raycastHit.IsHit) { HandleUtility.AddControl( controlID, HandleUtility.DistanceToCircle(voxelCenter, npVoxToUnity.VoxeSize.x * 0.25f) ); } break; case EventType.MouseDown: if (HandleUtility.nearestControl == controlID && Event.current.button == buttonNum) { mouseStartPos = Event.current.mousePosition; GUIUtility.hotControl = controlID; Event.current.Use(); } break; case EventType.MouseUp: if (GUIUtility.hotControl == controlID) { GUI.changed = true; GUIUtility.hotControl = 0; Event.current.Use(); return(impactCoord); } break; case EventType.MouseDrag: if (GUIUtility.hotControl == controlID) { Event.current.Use(); } break; } return(previousSelectedCoord); }
public static void CreateMesh( NPVoxModel model, Mesh mesh, Vector3 cubeSize, Vector3 NormalVariance, int NormalVarianceSeed = 0, NPVoxOptimization optimization = NPVoxOptimization.OFF, NPVoxNormalMode NormalMode = NPVoxNormalMode.SMOOTH, int BloodColorIndex = 0, NPVoxFaces loop = null, NPVoxFaces cutout = null, NPVoxFaces include = null, int MinVertexGroups = 1, NPVoxNormalMode[] NormalModePerVoxelGroup = null, NPVoxNormalProcessorList normalProcessors = null ) { bool hasVoxelGroups = model.HasVoxelGroups(); var vertices = new Vector3[model.NumVoxels * 8]; byte vertexGroupCount = model.NumVoxelGroups; var triangles = new int[vertexGroupCount, model.NumVoxels * 36]; var normals = new Vector3[model.NumVoxels * 8]; var tangents = new Vector4[model.NumVoxels * 8]; var colors = new Color[model.NumVoxels * 8]; var tmp = new NPVoxMeshTempData[model.NumVoxels]; int currentVertexIndex = 0; var currentTriangleIndex = new int[vertexGroupCount]; for (int i = 0; i < vertexGroupCount; i++) { currentTriangleIndex[i] = 0; } UnityEngine.Random.InitState(NormalVarianceSeed); if (loop == null) { loop = new NPVoxFaces(); } if (include == null) { include = new NPVoxFaces(1, 1, 1, 1, 1, 1); } NPVoxBox voxelsToInclude = model.BoundingBox; Vector3 cutoutOffset = Vector3.zero; if (cutout != null) { Vector3 originalCenter = voxelsToInclude.SaveCenter; voxelsToInclude.Left = (sbyte)Mathf.Abs(cutout.Left); voxelsToInclude.Down = (sbyte)Mathf.Abs(cutout.Down); voxelsToInclude.Back = (sbyte)Mathf.Abs(cutout.Back); voxelsToInclude.Right = (sbyte)(voxelsToInclude.Right - (sbyte)Mathf.Abs(cutout.Right)); voxelsToInclude.Up = (sbyte)(voxelsToInclude.Up - (sbyte)Mathf.Abs(cutout.Up)); voxelsToInclude.Forward = (sbyte)(voxelsToInclude.Forward - (sbyte)Mathf.Abs(cutout.Forward)); cutoutOffset = Vector3.Scale(originalCenter - voxelsToInclude.SaveCenter, cubeSize); } NPVoxToUnity npVoxToUnity = new NPVoxToUnity(model, cubeSize); Vector3 size = new Vector3( voxelsToInclude.Size.X * cubeSize.x, voxelsToInclude.Size.Y * cubeSize.y, voxelsToInclude.Size.Z * cubeSize.z ); NPVoxBox voxelNormalNeighbours = new NPVoxBox(new NPVoxCoord(-1, -1, -1), new NPVoxCoord(1, 1, 1)); // Collect temporary data to use for model generation int voxIndex = 0; foreach (NPVoxCoord voxCoord in voxelsToInclude.Enumerate()) { if (model.HasVoxel(voxCoord)) { tmp[voxIndex] = new NPVoxMeshTempData(); tmp[voxIndex].loop = loop; tmp[voxIndex].cutout = cutout; tmp[voxIndex].include = include; // Compute voxel center tmp[voxIndex].voxelCenter = npVoxToUnity.ToUnityPosition(voxCoord) + cutoutOffset; tmp[voxIndex].voxCoord = voxCoord; tmp[voxIndex].voxToUnity = npVoxToUnity; // Determine vertex group index tmp[voxIndex].vertexGroupIndex = 0; if (hasVoxelGroups) { tmp[voxIndex].vertexGroupIndex = model.GetVoxelGroup(voxCoord); } // Determine normal Mode if (NormalModePerVoxelGroup != null && NormalModePerVoxelGroup.Length > tmp[voxIndex].vertexGroupIndex) { tmp[voxIndex].normalMode = NormalModePerVoxelGroup[tmp[voxIndex].vertexGroupIndex]; } else { tmp[voxIndex].normalMode = NormalMode; } // do we have this side tmp[voxIndex].hasLeft = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.LEFT, loop)); tmp[voxIndex].hasRight = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.RIGHT, loop)); tmp[voxIndex].hasDown = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.DOWN, loop)); tmp[voxIndex].hasUp = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.UP, loop)); tmp[voxIndex].hasForward = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.FORWARD, loop)); tmp[voxIndex].hasBack = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.BACK, loop)); // do we actually want to include this side in our mesh // NOTE: cutout < 0 means we still render the mesh even though it is cutout // cutout > 0 means we don't render the mesh when cutout tmp[voxIndex].includeLeft = (tmp[voxIndex].hasLeft || (cutout.Left < 0 && voxCoord.X == voxelsToInclude.Left)) && include.Left == 1; tmp[voxIndex].includeRight = (tmp[voxIndex].hasRight || (cutout.Right < 0 && voxCoord.X == voxelsToInclude.Right)) && include.Right == 1; tmp[voxIndex].includeUp = (tmp[voxIndex].hasUp || (cutout.Up < 0 && voxCoord.Y == voxelsToInclude.Up)) && include.Up == 1; tmp[voxIndex].includeDown = (tmp[voxIndex].hasDown || (cutout.Down < 0 && voxCoord.Y == voxelsToInclude.Down)) && include.Down == 1; tmp[voxIndex].includeBack = (tmp[voxIndex].hasBack || (cutout.Back < 0 && voxCoord.Z == voxelsToInclude.Back)) && include.Back == 1; tmp[voxIndex].includeForward = (tmp[voxIndex].hasForward || (cutout.Forward < 0 && voxCoord.Z == voxelsToInclude.Forward)) && include.Forward == 1; tmp[voxIndex].isHidden = !tmp[voxIndex].hasForward && !tmp[voxIndex].hasBack && !tmp[voxIndex].hasLeft && !tmp[voxIndex].hasRight && !tmp[voxIndex].hasUp && !tmp[voxIndex].hasDown; if (tmp[voxIndex].isHidden && optimization == NPVoxOptimization.PER_VOXEL) { continue; } if (tmp[voxIndex].isHidden && BloodColorIndex > 0) { model.SetVoxel(voxCoord, (byte)BloodColorIndex); // WTF WTF WTF?!? we should not modify the MODEL in here !!!! elfapo: AAAAHHH NOOOO!!!! :O j.k. ;) } Color color = model.GetColor(voxCoord); // prepare cube vertices tmp[voxIndex].numVertices = 0; tmp[voxIndex].vertexIndexOffsetBegin = currentVertexIndex; if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeBack || tmp[voxIndex].includeLeft || tmp[voxIndex].includeDown) { tmp[voxIndex].vertexIndexOffsets[0] = tmp[voxIndex].numVertices++; tmp[voxIndex].vertexPositionOffsets[tmp[voxIndex].vertexIndexOffsets[0]] = new Vector3(-0.5f, -0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeBack || tmp[voxIndex].includeRight || tmp[voxIndex].includeDown) { tmp[voxIndex].vertexIndexOffsets[1] = tmp[voxIndex].numVertices++; tmp[voxIndex].vertexPositionOffsets[tmp[voxIndex].vertexIndexOffsets[1]] = new Vector3(0.5f, -0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeBack || tmp[voxIndex].includeLeft || tmp[voxIndex].includeUp) { tmp[voxIndex].vertexIndexOffsets[2] = tmp[voxIndex].numVertices++; tmp[voxIndex].vertexPositionOffsets[tmp[voxIndex].vertexIndexOffsets[2]] = new Vector3(-0.5f, 0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeBack || tmp[voxIndex].includeRight || tmp[voxIndex].includeUp) { tmp[voxIndex].vertexIndexOffsets[3] = tmp[voxIndex].numVertices++; tmp[voxIndex].vertexPositionOffsets[tmp[voxIndex].vertexIndexOffsets[3]] = new Vector3(0.5f, 0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeForward || tmp[voxIndex].includeLeft || tmp[voxIndex].includeDown) { tmp[voxIndex].vertexIndexOffsets[4] = tmp[voxIndex].numVertices++; tmp[voxIndex].vertexPositionOffsets[tmp[voxIndex].vertexIndexOffsets[4]] = new Vector3(-0.5f, -0.5f, 0.5f); } if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeForward || tmp[voxIndex].includeRight || tmp[voxIndex].includeDown) { tmp[voxIndex].vertexIndexOffsets[5] = tmp[voxIndex].numVertices++; tmp[voxIndex].vertexPositionOffsets[tmp[voxIndex].vertexIndexOffsets[5]] = new Vector3(0.5f, -0.5f, 0.5f); } if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeForward || tmp[voxIndex].includeLeft || tmp[voxIndex].includeUp) { tmp[voxIndex].vertexIndexOffsets[6] = tmp[voxIndex].numVertices++; tmp[voxIndex].vertexPositionOffsets[tmp[voxIndex].vertexIndexOffsets[6]] = new Vector3(-0.5f, 0.5f, 0.5f); } if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeForward || tmp[voxIndex].includeRight || tmp[voxIndex].includeUp) { tmp[voxIndex].vertexIndexOffsets[7] = tmp[voxIndex].numVertices++; tmp[voxIndex].vertexPositionOffsets[tmp[voxIndex].vertexIndexOffsets[7]] = new Vector3(0.5f, 0.5f, 0.5f); } // add cube faces int i = currentTriangleIndex[tmp[voxIndex].vertexGroupIndex]; // back if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeBack) { triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[0]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[2]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[1]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[2]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[3]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[1]; } // Forward if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeForward) { triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[6]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[4]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[5]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[7]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[6]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[5]; } // right if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeRight) { triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[1]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[3]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[5]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[3]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[7]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[5]; } // left if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeLeft) { triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[0]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[4]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[2]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[2]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[4]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[6]; } // up if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeUp) { triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[2]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[6]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[3]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[3]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[6]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[7]; } // down if (optimization != NPVoxOptimization.PER_FACE || tmp[voxIndex].includeDown) { triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[0]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[1]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[4]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[1]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[5]; triangles[tmp[voxIndex].vertexGroupIndex, i++] = tmp[voxIndex].vertexIndexOffsetBegin + tmp[voxIndex].vertexIndexOffsets[4]; } // Tangents for (int t = 0; t < tmp[voxIndex].numVertices; t++) { // store voxel center for shader usage Vector4 tangent = new Vector4(); tangent.x = tmp[voxIndex].voxelCenter.x; tangent.y = tmp[voxIndex].voxelCenter.y; tangent.z = tmp[voxIndex].voxelCenter.z; // encode model size tangent.w = ((voxelsToInclude.Size.X & 0x7F) << 14) | ((voxelsToInclude.Size.Y & 0x7F) << 7) | (voxelsToInclude.Size.Z & 0x7F); tangents[tmp[voxIndex].vertexIndexOffsetBegin + t] = tangent; } // UVs for (int t = 0; t < tmp[voxIndex].numVertices; t++) { colors[tmp[voxIndex].vertexIndexOffsetBegin + t] = color; } // translate & scale vertices to voxel position for (int t = 0; t < tmp[voxIndex].numVertices; t++) { vertices[tmp[voxIndex].vertexIndexOffsetBegin + t] = tmp[voxIndex].voxelCenter + Vector3.Scale(tmp[voxIndex].vertexPositionOffsets[t], cubeSize); } currentTriangleIndex[tmp[voxIndex].vertexGroupIndex] = i; currentVertexIndex += tmp[voxIndex].numVertices; voxIndex++; } } // elfapo: Remove invalid voxel information Array.Resize(ref tmp, voxIndex); ////////////////////////////////////// NORMAL STAGES //////////////////////////////////////// // elfapo TODO: Test area 'Normal Processor' Move Normal Processor stages to Normal Processor Pipeline: //NPVoxNormalProcessor_Voxel generator = ScriptableObject.CreateInstance<NPVoxNormalProcessor_Voxel>(); //NPVoxNormalProcessor_Variance processor = ScriptableObject.CreateInstance<NPVoxNormalProcessor_Variance>(); //generator.InitOutputBuffer(normals); //processor.InitOutputBuffer(normals); //processor.NormalVariance = NormalVariance; //processor.NormalVarianceSeed = NormalVarianceSeed; //if (NormalModePerVoxelGroup != null && NormalModePerVoxelGroup.Length > 0) //{ // for (int i = 0; i < NormalModePerVoxelGroup.Length; i++) // { // generator.ClearVoxelGroupFilters(); // generator.AddVoxelGroupFilter(i); // generator.NormalMode = NormalModePerVoxelGroup[i]; // generator.Process(model, tmp, normals, normals); // } // processor.Process(model, tmp, normals, normals); //} //else //{ // generator.NormalMode = NormalMode; // generator.Process(model, tmp, normals, normals); // processor.Process(model, tmp, normals, normals); //} //ScriptableObject.DestroyImmediate(generator); //ScriptableObject.DestroyImmediate(processor); if (normalProcessors != null) { normalProcessors.Run(model, tmp, normals, normals); } ////////////////////////////////////////////////////////////////////////////////////////////// // shrink arrays as needed if (optimization != NPVoxOptimization.OFF) { Array.Resize(ref vertices, currentVertexIndex); Array.Resize(ref normals, currentVertexIndex); Array.Resize(ref tangents, currentVertexIndex); Array.Resize(ref colors, currentVertexIndex); } mesh.vertices = vertices; if (hasVoxelGroups) { mesh.subMeshCount = Math.Max(vertexGroupCount, MinVertexGroups); for (int i = 0; i < vertexGroupCount; i++) { int numberOfTrianglesForVertexGroup = currentTriangleIndex[i]; int[] trianglesForVertexGroup = new int[numberOfTrianglesForVertexGroup]; for (int j = 0; j < numberOfTrianglesForVertexGroup; j++) { trianglesForVertexGroup[j] = triangles[i, j]; } mesh.SetTriangles(trianglesForVertexGroup, i); } } else { int numberOfTrianglesForVertexGroup = currentTriangleIndex[0]; int[] trianglesForVertexGroup = new int[numberOfTrianglesForVertexGroup]; Buffer.BlockCopy(triangles, 0, trianglesForVertexGroup, 0, numberOfTrianglesForVertexGroup * sizeof(int)); if (MinVertexGroups < 2) { mesh.triangles = trianglesForVertexGroup; } else { mesh.subMeshCount = MinVertexGroups; mesh.SetTriangles(trianglesForVertexGroup, 0); } } mesh.normals = normals; mesh.tangents = tangents; mesh.colors = colors; mesh.bounds = new Bounds(Vector3.zero, size); if (NormalMode == NPVoxNormalMode.AUTO) { mesh.RecalculateNormals(); } }
public static NPVoxBox DrawBoxSelection(NPVoxToUnity npVoxToUnity, NPVoxBox box, bool editable = true) { Vector3 leftDownBack = npVoxToUnity.ToUnityPosition(box.LeftDownBack) - npVoxToUnity.VoxeSize * 0.5f; Vector3 rightUpForward = npVoxToUnity.ToUnityPosition(box.RightUpForward) + npVoxToUnity.VoxeSize * 0.5f; Vector3 rightDownBack = new Vector3(rightUpForward.x, leftDownBack.y, leftDownBack.z); Vector3 leftUpBack = new Vector3(leftDownBack.x, rightUpForward.y, leftDownBack.z); Vector3 rightUpBack = new Vector3(rightUpForward.x, rightUpForward.y, leftDownBack.z); Vector3 leftDownForward = new Vector3(leftDownBack.x, leftDownBack.y, rightUpForward.z); Vector3 rightDownForward = new Vector3(rightUpForward.x, leftDownBack.y, rightUpForward.z); Vector3 leftUpForward = new Vector3(leftDownBack.x, rightUpForward.y, rightUpForward.z); Handles.DrawDottedLine(leftDownBack, rightDownBack, 1f); Handles.DrawDottedLine(leftDownBack, leftUpBack, 1f); Handles.DrawDottedLine(leftUpBack, rightUpBack, 1f); Handles.DrawDottedLine(rightDownBack, rightUpBack, 1f); Handles.DrawDottedLine(leftDownForward, rightDownForward, 1f); Handles.DrawDottedLine(leftDownForward, leftUpForward, 1f); Handles.DrawDottedLine(leftUpForward, rightUpForward, 1f); Handles.DrawDottedLine(rightDownForward, rightUpForward, 1f); Handles.DrawDottedLine(leftDownBack, leftDownForward, 1f); Handles.DrawDottedLine(rightDownBack, rightDownForward, 1f); Handles.DrawDottedLine(leftUpBack, leftUpForward, 1f); Handles.DrawDottedLine(rightUpBack, rightUpForward, 1f); if (!editable) { return(box); } NPVoxBox newBox = new NPVoxBox(box.LeftDownBack, box.RightUpForward); if (SceneView.currentDrawingSceneView.camera.orthographic) { NPVoxCoord oldCoord; NPVoxCoord newCoord; oldCoord = box.LeftDownBack; newCoord = NPVoxHandles.DrawVoxelHandle(leftDownBack, oldCoord, npVoxToUnity); if (!newCoord.Equals(oldCoord)) { newBox.LeftDownBack = newCoord; } oldCoord = box.RightDownBack; newCoord = NPVoxHandles.DrawVoxelHandle(rightDownBack, oldCoord, npVoxToUnity); if (!newCoord.Equals(oldCoord)) { newBox.RightDownBack = newCoord; } oldCoord = box.LeftUpBack; newCoord = NPVoxHandles.DrawVoxelHandle(leftUpBack, oldCoord, npVoxToUnity); if (!newCoord.Equals(oldCoord)) { newBox.LeftUpBack = newCoord; } oldCoord = box.RightUpBack; newCoord = NPVoxHandles.DrawVoxelHandle(rightUpBack, oldCoord, npVoxToUnity); if (!newCoord.Equals(oldCoord)) { newBox.RightUpBack = newCoord; } oldCoord = box.LeftDownForward; newCoord = NPVoxHandles.DrawVoxelHandle(leftDownForward, oldCoord, npVoxToUnity); if (!newCoord.Equals(oldCoord)) { newBox.LeftDownForward = newCoord; } oldCoord = box.RightDownForward; newCoord = NPVoxHandles.DrawVoxelHandle(rightDownForward, oldCoord, npVoxToUnity); if (!newCoord.Equals(oldCoord)) { newBox.RightDownForward = newCoord; } oldCoord = box.LeftUpForward; newCoord = NPVoxHandles.DrawVoxelHandle(leftUpForward, oldCoord, npVoxToUnity); if (!newCoord.Equals(oldCoord)) { newBox.LeftUpForward = newCoord; } oldCoord = box.RightUpForward; newCoord = NPVoxHandles.DrawVoxelHandle(rightUpForward, oldCoord, npVoxToUnity); if (!newCoord.Equals(oldCoord)) { newBox.RightUpForward = newCoord; } // center mover oldCoord = box.LeftDownBack; newCoord = NPVoxHandles.DrawVoxelHandle(npVoxToUnity.ToUnityPosition(box.SaveCenter), oldCoord, npVoxToUnity); if (!newCoord.Equals(oldCoord)) { newBox.SaveCenter += NPVoxCoordUtil.ToVector(newCoord - oldCoord); } } else { sbyte oldPos; sbyte newPos; Vector3 handlePos; handlePos = new Vector3(leftDownBack.x + (rightUpForward.x - leftDownBack.x) / 2, leftDownBack.y + (rightUpForward.y - leftDownBack.y) / 2, leftDownBack.z); oldPos = box.Back; newPos = NPVoxHandles.DrawAxisHandle(handlePos, oldPos, npVoxToUnity, Vector3.forward); if (oldPos != newPos) { newBox.Back = newPos; } handlePos = new Vector3(leftDownBack.x + (rightUpForward.x - leftDownBack.x) / 2, leftDownBack.y + (rightUpForward.y - leftDownBack.y) / 2, rightUpForward.z); oldPos = box.Forward; newPos = NPVoxHandles.DrawAxisHandle(handlePos, oldPos, npVoxToUnity, Vector3.forward); if (oldPos != newPos) { newBox.Forward = newPos; } handlePos = new Vector3(leftDownBack.x + (rightUpForward.x - leftDownBack.x) / 2, leftDownBack.y, leftDownBack.z + (rightUpForward.z - leftDownBack.z) / 2); oldPos = box.Down; newPos = NPVoxHandles.DrawAxisHandle(handlePos, oldPos, npVoxToUnity, Vector3.up); if (oldPos != newPos) { newBox.Down = newPos; } handlePos = new Vector3(leftDownBack.x + (rightUpForward.x - leftDownBack.x) / 2, rightUpForward.y, leftDownBack.z + (rightUpForward.z - leftDownBack.z) / 2); oldPos = box.Up; newPos = NPVoxHandles.DrawAxisHandle(handlePos, oldPos, npVoxToUnity, Vector3.up); if (oldPos != newPos) { newBox.Up = newPos; } handlePos = new Vector3(leftDownBack.x, leftDownBack.y + (rightUpForward.y - leftDownBack.y) / 2, leftDownBack.z + (rightUpForward.z - leftDownBack.z) / 2); oldPos = box.Left; newPos = NPVoxHandles.DrawAxisHandle(handlePos, oldPos, npVoxToUnity, Vector3.right); if (oldPos != newPos) { newBox.Left = newPos; } handlePos = new Vector3(rightUpForward.x, leftDownBack.y + (rightUpForward.y - leftDownBack.y) / 2, leftDownBack.z + (rightUpForward.z - leftDownBack.z) / 2); oldPos = box.Right; newPos = NPVoxHandles.DrawAxisHandle(handlePos, oldPos, npVoxToUnity, Vector3.right); if (oldPos != newPos) { newBox.Right = newPos; } } return(newBox); }
public static void CreateMesh( NPVoxModel model, Mesh mesh, Vector3 cubeSize, Vector3 NormalVariance, int NormalVarianceSeed = 0, NPVoxOptimization optimization = NPVoxOptimization.OFF, NPVoxNormalMode NormalMode = NPVoxNormalMode.SMOOTH, int BloodColorIndex = 0, NPVoxFaces loop = null, NPVoxFaces cutout = null, NPVoxFaces include = null, int MinVertexGroups = 1, NPVoxNormalMode[] NormalModePerVoxelGroup = null ) { bool hasVoxelGroups = model.HasVoxelGroups(); var vertices = new Vector3[model.NumVoxels * 8]; byte vertexGroupCount = model.NumVoxelGroups; var triangles = new int[vertexGroupCount, model.NumVoxels * 36]; var normals = new Vector3[model.NumVoxels * 8]; var tangents = new Vector4[model.NumVoxels * 8]; var colors = new Color[model.NumVoxels * 8]; int currentVertexIndex = 0; var currentTriangleIndex = new int[vertexGroupCount]; for (int i = 0; i < vertexGroupCount; i++) { currentTriangleIndex[i] = 0; } UnityEngine.Random.InitState(NormalVarianceSeed); if (loop == null) { loop = new NPVoxFaces(); } if (include == null) { include = new NPVoxFaces(1, 1, 1, 1, 1, 1); } NPVoxBox voxelsToInclude = model.BoundingBox; Vector3 cutoutOffset = Vector3.zero; if (cutout != null) { Vector3 originalCenter = voxelsToInclude.SaveCenter; voxelsToInclude.Left = (sbyte)Mathf.Abs(cutout.Left); voxelsToInclude.Down = (sbyte)Mathf.Abs(cutout.Down); voxelsToInclude.Back = (sbyte)Mathf.Abs(cutout.Back); voxelsToInclude.Right = (sbyte)(voxelsToInclude.Right - (sbyte)Mathf.Abs(cutout.Right)); voxelsToInclude.Up = (sbyte)(voxelsToInclude.Up - (sbyte)Mathf.Abs(cutout.Up)); voxelsToInclude.Forward = (sbyte)(voxelsToInclude.Forward - (sbyte)Mathf.Abs(cutout.Forward)); cutoutOffset = Vector3.Scale(originalCenter - voxelsToInclude.SaveCenter, cubeSize); } NPVoxToUnity npVoxToUnity = new NPVoxToUnity(model, cubeSize); Vector3 size = new Vector3( voxelsToInclude.Size.X * cubeSize.x, voxelsToInclude.Size.Y * cubeSize.y, voxelsToInclude.Size.Z * cubeSize.z ); NPVoxBox voxelNormalNeighbours = new NPVoxBox(new NPVoxCoord(-1, -1, -1), new NPVoxCoord(1, 1, 1)); NPVoxNormalMode normalMode = NormalMode; foreach (NPVoxCoord voxCoord in voxelsToInclude.Enumerate()) { if (model.HasVoxel(voxCoord)) { Vector3 voxelCenter = npVoxToUnity.ToUnityPosition(voxCoord) + cutoutOffset; int vertexGroupIndex = 0; if (hasVoxelGroups) { vertexGroupIndex = model.GetVoxelGroup(voxCoord); } if (NormalModePerVoxelGroup != null && NormalModePerVoxelGroup.Length > vertexGroupIndex) { normalMode = NormalModePerVoxelGroup[vertexGroupIndex]; } else { normalMode = NormalMode; } // do we have this side bool hasLeft = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.LEFT, loop)); bool hasRight = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.RIGHT, loop)); bool hasDown = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.DOWN, loop)); bool hasUp = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.UP, loop)); bool hasForward = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.FORWARD, loop)); bool hasBack = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.BACK, loop)); // do we actually want to include this side in our mesh // NOTE: cutout < 0 means we still render the mesh even though it is cutout // cutout > 0 means we don't render the mesh when cutout bool includeLeft = (hasLeft || (cutout.Left < 0 && voxCoord.X == voxelsToInclude.Left)) && include.Left == 1; bool includeRight = (hasRight || (cutout.Right < 0 && voxCoord.X == voxelsToInclude.Right)) && include.Right == 1; bool includeUp = (hasUp || (cutout.Up < 0 && voxCoord.Y == voxelsToInclude.Up)) && include.Up == 1; bool includeDown = (hasDown || (cutout.Down < 0 && voxCoord.Y == voxelsToInclude.Down)) && include.Down == 1; bool includeBack = (hasBack || (cutout.Back < 0 && voxCoord.Z == voxelsToInclude.Back)) && include.Back == 1; bool includeForward = (hasForward || (cutout.Forward < 0 && voxCoord.Z == voxelsToInclude.Forward)) && include.Forward == 1; bool isHidden = !hasForward && !hasBack && !hasLeft && !hasRight && !hasUp && !hasDown; if (isHidden && optimization == NPVoxOptimization.PER_VOXEL) { continue; } if (isHidden && BloodColorIndex > 0) { model.SetVoxel(voxCoord, (byte)BloodColorIndex); // WTF WTF WTF?!? we should not modify the MODEL in here !!!! } Color color = model.GetColor(voxCoord); // prepare cube vertices int numVertices = 0; int[] vertexIndexOffsets = new int[8]; Vector3[] vertexPositionOffsets = new Vector3[8]; if (optimization != NPVoxOptimization.PER_FACE || includeBack || includeLeft || includeDown) { vertexIndexOffsets[0] = numVertices++; vertexPositionOffsets[vertexIndexOffsets[0]] = new Vector3(-0.5f, -0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || includeBack || includeRight || includeDown) { vertexIndexOffsets[1] = numVertices++; vertexPositionOffsets[vertexIndexOffsets[1]] = new Vector3(0.5f, -0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || includeBack || includeLeft || includeUp) { vertexIndexOffsets[2] = numVertices++; vertexPositionOffsets[vertexIndexOffsets[2]] = new Vector3(-0.5f, 0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || includeBack || includeRight || includeUp) { vertexIndexOffsets[3] = numVertices++; vertexPositionOffsets[vertexIndexOffsets[3]] = new Vector3(0.5f, 0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || includeForward || includeLeft || includeDown) { vertexIndexOffsets[4] = numVertices++; vertexPositionOffsets[vertexIndexOffsets[4]] = new Vector3(-0.5f, -0.5f, 0.5f); } if (optimization != NPVoxOptimization.PER_FACE || includeForward || includeRight || includeDown) { vertexIndexOffsets[5] = numVertices++; vertexPositionOffsets[vertexIndexOffsets[5]] = new Vector3(0.5f, -0.5f, 0.5f); } if (optimization != NPVoxOptimization.PER_FACE || includeForward || includeLeft || includeUp) { vertexIndexOffsets[6] = numVertices++; vertexPositionOffsets[vertexIndexOffsets[6]] = new Vector3(-0.5f, 0.5f, 0.5f); } if (optimization != NPVoxOptimization.PER_FACE || includeForward || includeRight || includeUp) { vertexIndexOffsets[7] = numVertices++; vertexPositionOffsets[vertexIndexOffsets[7]] = new Vector3(0.5f, 0.5f, 0.5f); } // add cube faces int i = currentTriangleIndex[vertexGroupIndex]; // back if (optimization != NPVoxOptimization.PER_FACE || includeBack) { triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[0]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1]; } // Forward if (optimization != NPVoxOptimization.PER_FACE || includeForward) { triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[7]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5]; } // right if (optimization != NPVoxOptimization.PER_FACE || includeRight) { triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[7]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5]; } // left if (optimization != NPVoxOptimization.PER_FACE || includeLeft) { triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[0]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6]; } // up if (optimization != NPVoxOptimization.PER_FACE || includeUp) { triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[7]; } // down if (optimization != NPVoxOptimization.PER_FACE || includeDown) { triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[0]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5]; triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4]; } // TODO create some kind of strategy pattern for the normal calculation, else this here is becomming a mess ... Vector3 variance = Vector3.zero; if (NormalVariance.x != 0 || NormalVariance.y != 0 || NormalVariance.z != 0) { variance.x = -NormalVariance.x * 0.5f + 2 * UnityEngine.Random.value * NormalVariance.x; variance.y = -NormalVariance.y * 0.5f + 2 * UnityEngine.Random.value * NormalVariance.y; variance.z = -NormalVariance.z * 0.5f + 2 * UnityEngine.Random.value * NormalVariance.z; } // calculate normals based on present neighbour voxels Vector3 voxelNormal = Vector3.zero; if (!isHidden) { foreach (NPVoxCoord offset in voxelNormalNeighbours.Enumerate()) { NPVoxCoord checkCoord = voxCoord + offset; checkCoord = model.LoopCoord(checkCoord, loop); if (!model.HasVoxel(checkCoord)) { voxelNormal += NPVoxCoordUtil.ToVector(offset); } } voxelNormal.Normalize(); } else { voxelNormal = voxelCenter.normalized; } // Normals for (int t = 0; t < numVertices; t++) { Vector3 normal = Vector3.zero; switch (normalMode) { case NPVoxNormalMode.VOXEL: normal = voxelNormal; normal = Vector3.zero; if (vertexPositionOffsets[t].x < 0.0f) { if (hasLeft && !hasForward && !hasBack && !hasUp && !hasDown) { normal.x = -1; } else { normal.x = voxelNormal.x; } } else if (vertexPositionOffsets[t].x > 0.0f) { if (hasRight && !hasForward && !hasBack && !hasUp && !hasDown) { normal.x = 1; } else { normal.x = voxelNormal.x; } } if (vertexPositionOffsets[t].y < 0.0f) { if (hasUp && !hasForward && !hasBack && !hasLeft && !hasRight) { normal.y = -1; } else { normal.y = voxelNormal.y; } } else if (vertexPositionOffsets[t].y > 0.0f) { if (hasDown && !hasForward && !hasBack && !hasLeft && !hasRight) { normal.y = +1; } else { normal.y = voxelNormal.y; } } if (vertexPositionOffsets[t].z < 0.0f) { if (hasBack && !hasLeft && !hasRight && !hasUp && !hasDown) { normal.z = -1; } else { normal.z = voxelNormal.z; } } else if (vertexPositionOffsets[t].z > 0.0f) { if (hasForward && !hasLeft && !hasRight && !hasUp && !hasDown) { normal.z = +1; } else { normal.z = voxelNormal.z; } } if (Mathf.Abs(normal.x) < 0.1f && Mathf.Abs(normal.y) < 0.1f && Mathf.Abs(normal.z) < 0.1f) { // we would like to have full color when we are a stand-alone voxel, however there is no way to do so right now, so we just // fallback to the centoid normal normal = voxelCenter; } normal.Normalize(); break; case NPVoxNormalMode.SMOOTH: normal = Vector3.zero; for (float xx = -0.5f; xx < 1.0f; xx += 1f) { for (float yy = -.5f; yy < 1; yy += 1) { for (float zz = -.5f; zz < 1; zz += 1) { sbyte xCoord = (sbyte)Mathf.Round(vertexPositionOffsets[t].x + xx); sbyte yCoord = (sbyte)Mathf.Round(vertexPositionOffsets[t].y + yy); sbyte zCoord = (sbyte)Mathf.Round(vertexPositionOffsets[t].z + zz); if (!model.HasVoxel(voxCoord + new NPVoxCoord((sbyte)xCoord, (sbyte)yCoord, (sbyte)zCoord))) { normal += new Vector3( xx, yy, zz ); } } } } normal.Normalize(); break; case NPVoxNormalMode.FORWARD: normal = Vector3.forward; break; case NPVoxNormalMode.BACK: normal = Vector3.back; break; case NPVoxNormalMode.UP: normal = Vector3.up; break; case NPVoxNormalMode.DOWN: normal = Vector3.down; break; case NPVoxNormalMode.LEFT: normal = Vector3.left; break; case NPVoxNormalMode.RIGHT: normal = Vector3.right; break; } normals[currentVertexIndex + t] = (normal + variance).normalized; // store voxel center for shader usage Vector4 tangent = new Vector4(); tangent.x = voxelCenter.x; tangent.y = voxelCenter.y; tangent.z = voxelCenter.z; // encode model size tangent.w = ((voxelsToInclude.Size.X & 0x7F) << 14) | ((voxelsToInclude.Size.Y & 0x7F) << 7) | (voxelsToInclude.Size.Z & 0x7F); tangents[currentVertexIndex + t] = tangent; } // UVs for (int t = 0; t < numVertices; t++) { colors[currentVertexIndex + t] = color; } // translate & scale vertices to voxel position for (int t = 0; t < numVertices; t++) { vertices[currentVertexIndex + t] = voxelCenter + Vector3.Scale(vertexPositionOffsets[t], cubeSize); } currentTriangleIndex[vertexGroupIndex] = i; currentVertexIndex += numVertices; } } // shrink arrays as needed if (optimization != NPVoxOptimization.OFF) { Array.Resize(ref vertices, currentVertexIndex); Array.Resize(ref normals, currentVertexIndex); Array.Resize(ref tangents, currentVertexIndex); Array.Resize(ref colors, currentVertexIndex); } mesh.vertices = vertices; if (hasVoxelGroups) { mesh.subMeshCount = Math.Max(vertexGroupCount, MinVertexGroups); for (int i = 0; i < vertexGroupCount; i++) { int numberOfTrianglesForVertexGroup = currentTriangleIndex[i]; int[] trianglesForVertexGroup = new int[numberOfTrianglesForVertexGroup]; for (int j = 0; j < numberOfTrianglesForVertexGroup; j++) { trianglesForVertexGroup[j] = triangles[i, j]; } mesh.SetTriangles(trianglesForVertexGroup, i); } } else { int numberOfTrianglesForVertexGroup = currentTriangleIndex[0]; int[] trianglesForVertexGroup = new int[numberOfTrianglesForVertexGroup]; Buffer.BlockCopy(triangles, 0, trianglesForVertexGroup, 0, numberOfTrianglesForVertexGroup * sizeof(int)); if (MinVertexGroups < 2) { mesh.triangles = trianglesForVertexGroup; } else { mesh.subMeshCount = MinVertexGroups; mesh.SetTriangles(trianglesForVertexGroup, 0); } } mesh.normals = normals; mesh.tangents = tangents; mesh.colors = colors; mesh.bounds = new Bounds(Vector3.zero, size); if (NormalMode == NPVoxNormalMode.AUTO) { mesh.RecalculateNormals(); } }
public System.Func <NPVoxISceneEditable, bool> DrawSceneTool(NPVoxToUnity npVoxToUnity, Transform transform, int tool) { if (Input == null) { return(null); } NPVoxModel model = ((NPVoxIModelFactory)Input).GetProduct() as NPVoxModel; if (!model) { return(null); } Vector3 pivot = npVoxToUnity.ToUnityPosition(GetPivot()); // Position handle if (tool == 0) { Vector3 oldTranslation = GetTranslation(); Vector3 newTranslation = npVoxToUnity.ToSaveVoxDirection( Handles.PositionHandle(npVoxToUnity.ToUnityDirection(oldTranslation) + pivot, Quaternion.identity) - pivot ); if (!newTranslation.Equals(oldTranslation)) { return((NPVoxISceneEditable t) => { (t as NPVoxModelTransformerBase).SetTranslation(newTranslation); return true; }); } } // Quaternion Handle if (tool == 1) { Quaternion oldQuaternion = GetRotation(); Quaternion newQuaternion = Handles.RotationHandle(oldQuaternion, pivot); if (!newQuaternion.Equals(oldQuaternion)) { return((NPVoxISceneEditable t) => { (t as NPVoxModelTransformerBase).SetRotation(newQuaternion); return true; }); } } // Scale Handle if (tool == 2) { Vector3 oldScale = GetScale(); Vector3 newScale = Handles.ScaleHandle(oldScale, pivot, GetRotation(), 1.0f); if (!newScale.Equals(oldScale)) { return((NPVoxISceneEditable t) => { (t as NPVoxModelTransformerBase).SetScale(newScale); return true; }); } } // Pivot Handle if (tool == 3) { Vector3 newPivot = Handles.PositionHandle(pivot, Quaternion.identity); if (!newPivot.Equals(pivot)) { return((NPVoxISceneEditable t) => { (t as NPVoxModelTransformerBase).SetPivot(newPivot); return true; }); } } return(null); }
public System.Func <NPVoxISceneEditable, bool> DrawSceneTool(NPVoxToUnity npVoxToUnity, Transform transform, int tool) { if (Input == null) { return(null); } NPVoxModel model = ((NPVoxIModelFactory)Input).GetProduct() as NPVoxModel; if (!model) { return(null); } if (!(PreviousFrame is NPVoxIModelFactory)) { return(null); } if (SocketOffsets.Length < 4 || ControlPointOffsets.Length < 4) { ResetSceneTools(); } NPVoxToUnity sourceN2U = new NPVoxToUnity(((NPVoxIModelFactory)PreviousFrame).GetProduct(), npVoxToUnity.VoxeSize); NPVoxSocket sourceSocket1 = ((NPVoxIModelFactory)PreviousFrame).GetProduct().GetSocketByName(SocketName1); NPVoxSocket sourceSocket2 = ((NPVoxIModelFactory)PreviousFrame).GetProduct().GetSocketByName(SocketName2); NPVoxModel targetModel = model; if (TargetFrame is NPVoxIModelFactory) { targetModel = ((NPVoxIModelFactory)TargetFrame).GetProduct() as NPVoxModel; } NPVoxToUnity targetN2U = new NPVoxToUnity(targetModel, npVoxToUnity.VoxeSize); NPVoxSocket targetSocket1 = targetModel.GetSocketByName(SocketName1); NPVoxSocket targetSocket2 = targetModel.GetSocketByName(SocketName2); if (targetSocket1.IsInvalid()) { Debug.LogWarning("SocketName1 not found in targetModel"); return(null); } if (targetSocket2.IsInvalid()) { Debug.LogWarning("SocketName2 not found in targetModel"); return(null); } NPVoxSocket[] sockets = new NPVoxSocket[4]; sockets[INDEX_SOURCE_1] = sourceSocket1; sockets[INDEX_SOURCE_2] = sourceSocket2; sockets[INDEX_TARGET_1] = targetSocket1; sockets[INDEX_TARGET_2] = targetSocket2; NPVoxToUnity[] n2u = new NPVoxToUnity[4]; n2u[INDEX_SOURCE_1] = sourceN2U; n2u[INDEX_SOURCE_2] = sourceN2U; n2u[INDEX_TARGET_1] = targetN2U; n2u[INDEX_TARGET_2] = targetN2U; NPVoxToUnity n = n2u[currentEditedSocket]; Vector3 pos = n.ToUnityPosition(sockets[currentEditedSocket].Anchor); if (tool == 0) { if (Event.current.type == EventType.MouseDown) { currentEditedSocket = (currentEditedSocket + 1) % 4; } switch (currentEditedSocket) { case INDEX_TARGET_1: Handles.color = Color.green; break; case INDEX_TARGET_2: Handles.color = Color.green; break; case INDEX_SOURCE_1: Handles.color = Color.yellow; break; case INDEX_SOURCE_2: Handles.color = Color.yellow; break; } Handles.CubeCap(0, pos, Quaternion.identity, 0.5f); } // offset Vector3 offset = n.ToUnityDirection(SocketOffsets[currentEditedSocket]); if (tool == 1) { offset = n.ToSaveVoxDirection(Handles.PositionHandle(pos + offset, Quaternion.identity) - pos); if (offset != SocketOffsets[currentEditedSocket]) { return((NPVoxISceneEditable t) => { (t as NPVoxTrailGenerator).SocketOffsets[currentEditedSocket] = offset; return true; }); } } Vector3 controlOffset = n.ToUnityDirection(ControlPointOffsets[currentEditedSocket]); // Control Point if (tool == 2) { controlOffset = n.ToSaveVoxDirection(Handles.PositionHandle(pos + offset + controlOffset, Quaternion.identity) - pos - offset); if (controlOffset != ControlPointOffsets[currentEditedSocket]) { return((NPVoxISceneEditable t) => { (t as NPVoxTrailGenerator).ControlPointOffsets[currentEditedSocket] = controlOffset; return true; }); } } return(null); }
// =================================================================================================== // Inspector UI // =================================================================================================== public override void OnInspectorGUI() { if (!viewModel.IsPlaying && wasPreview) { // workaround for stupid "getting control 5" exception wasPreview = false; Repaint(); return; } viewModel.ProcessInvalidations(); NPVoxAnimationEditorSession session = ((NPVoxAnimationEditorSession)target); EditorGUILayout.BeginVertical(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Close Editor") || !session.animation) { NPVoxAnimationEditor.CloseAnimationEditor(session); } if (GUILayout.Button("Debug")) { viewModel.DebugButton(); } if (GUILayout.Button("Invalidate & Reimport All")) { NPipelineUtils.InvalidateAndReimportAll(session.animation); } if (GUILayout.Button("Invalidate & Reimport All Deep")) { NPipelineUtils.InvalidateAndReimportAllDeep(session.animation); } if (GUILayout.Button("Help")) { NPVoxAnimHelpWindow.ShowWindow(); } EditorGUILayout.EndHorizontal(); GUILayout.Label("Preview: ", EditorStyles.boldLabel); DrawPreview(); if (!viewModel.IsPlaying) { GUILayout.Space(10); GUILayout.Label("Frames: ", EditorStyles.boldLabel); DrawFrameSelection(); GUILayout.Space(10); DrawModelSelection(); DrawTransformationSelector(); GUILayout.Space(10); GUILayout.Label("Presentation: ", EditorStyles.boldLabel); DrawModeToolbar(); DrawSocketTools(); } else { // Debug.Log("playing"); DrawFrameList(); } DrawMaterialSelection(); session.groundplateOffset = EditorGUILayout.FloatField("Ground Offset", session.groundplateOffset); EditorGUILayout.EndVertical(); if (meshRefreshRequested) { meshRefreshRequested = false; UpdateMeshes(); SceneView.RepaintAll(); } // unfocus by pressing escape Event e = Event.current; if (e.isKey && e.keyCode == KeyCode.Escape) { unfocus(); } // ground plate if (viewModel.SelectedFrame != null && viewModel.SelectedFrame.Source != null && session.groundFilter) { NPVoxModel model = viewModel.SelectedFrame.Source.GetProduct(); NPVoxToUnity n2u = new NPVoxToUnity(model, viewModel.Animation.MeshFactory.VoxelSize); Vector3 pos = n2u.ToUnityPosition(new Vector3(model.BoundingBox.SaveCenter.x, model.BoundingBox.SaveCenter.y, model.BoundingBox.Forward + 1)); session.groundFilter.transform.position = pos + Vector3.forward * session.groundplateOffset; } KeyboardShortcuts(); }
public static NPVoxMeshData[] GenerateVoxMeshData( NPVoxModel model, Vector3 cubeSize, NPVoxOptimization optimization = NPVoxOptimization.OFF, int BloodColorIndex = 0, NPVoxFaces loop = null, NPVoxFaces cutout = null, NPVoxFaces include = null) { bool hasVoxelGroups = model.HasVoxelGroups(); byte vertexGroupCount = model.NumVoxelGroups; var voxMeshData = new NPVoxMeshData[model.NumVoxels]; int currentVertexIndex = 0; if (loop == null) { loop = new NPVoxFaces(); } if (include == null) { include = new NPVoxFaces(1, 1, 1, 1, 1, 1); } NPVoxBox voxelsToInclude = model.BoundingBox; Vector3 cutoutOffset = Vector3.zero; if (cutout != null) { Vector3 originalCenter = voxelsToInclude.SaveCenter; voxelsToInclude.Left = ( sbyte )Mathf.Abs(cutout.Left); voxelsToInclude.Down = ( sbyte )Mathf.Abs(cutout.Down); voxelsToInclude.Back = ( sbyte )Mathf.Abs(cutout.Back); voxelsToInclude.Right = ( sbyte )(voxelsToInclude.Right - ( sbyte )Mathf.Abs(cutout.Right)); voxelsToInclude.Up = ( sbyte )(voxelsToInclude.Up - ( sbyte )Mathf.Abs(cutout.Up)); voxelsToInclude.Forward = ( sbyte )(voxelsToInclude.Forward - ( sbyte )Mathf.Abs(cutout.Forward)); cutoutOffset = Vector3.Scale(originalCenter - voxelsToInclude.SaveCenter, cubeSize); } NPVoxToUnity npVoxToUnity = new NPVoxToUnity(model, cubeSize); Vector3 size = new Vector3( voxelsToInclude.Size.X * cubeSize.x, voxelsToInclude.Size.Y * cubeSize.y, voxelsToInclude.Size.Z * cubeSize.z ); NPVoxBox voxelNormalNeighbours = new NPVoxBox(new NPVoxCoord(-1, -1, -1), new NPVoxCoord(1, 1, 1)); // Collect temporary data to use for model generation int voxIndex = 0; foreach (NPVoxCoord voxCoord in voxelsToInclude.Enumerate()) { if (model.HasVoxel(voxCoord)) { voxMeshData[voxIndex] = new NPVoxMeshData(); voxMeshData[voxIndex].loop = loop; voxMeshData[voxIndex].cutout = cutout; voxMeshData[voxIndex].include = include; // Compute voxel center voxMeshData[voxIndex].voxelCenter = npVoxToUnity.ToUnityPosition(voxCoord) + cutoutOffset; voxMeshData[voxIndex].voxCoord = voxCoord; voxMeshData[voxIndex].voxToUnity = npVoxToUnity; // Determine vertex group index voxMeshData[voxIndex].vertexGroupIndex = 0; if (hasVoxelGroups) { voxMeshData[voxIndex].vertexGroupIndex = model.GetVoxelGroup(voxCoord); } // do we have this side voxMeshData[voxIndex].hasLeft = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.LEFT, loop)); voxMeshData[voxIndex].hasRight = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.RIGHT, loop)); voxMeshData[voxIndex].hasDown = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.DOWN, loop)); voxMeshData[voxIndex].hasUp = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.UP, loop)); voxMeshData[voxIndex].hasForward = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.FORWARD, loop)); voxMeshData[voxIndex].hasBack = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.BACK, loop)); // do we actually want to include this side in our mesh // NOTE: cutout < 0 means we still render the mesh even though it is cutout // cutout > 0 means we don't render the mesh when cutout voxMeshData[voxIndex].includeLeft = (voxMeshData[voxIndex].hasLeft || (cutout.Left < 0 && voxCoord.X == voxelsToInclude.Left)) && include.Left == 1; voxMeshData[voxIndex].includeRight = (voxMeshData[voxIndex].hasRight || (cutout.Right < 0 && voxCoord.X == voxelsToInclude.Right)) && include.Right == 1; voxMeshData[voxIndex].includeUp = (voxMeshData[voxIndex].hasUp || (cutout.Up < 0 && voxCoord.Y == voxelsToInclude.Up)) && include.Up == 1; voxMeshData[voxIndex].includeDown = (voxMeshData[voxIndex].hasDown || (cutout.Down < 0 && voxCoord.Y == voxelsToInclude.Down)) && include.Down == 1; voxMeshData[voxIndex].includeBack = (voxMeshData[voxIndex].hasBack || (cutout.Back < 0 && voxCoord.Z == voxelsToInclude.Back)) && include.Back == 1; voxMeshData[voxIndex].includeForward = (voxMeshData[voxIndex].hasForward || (cutout.Forward < 0 && voxCoord.Z == voxelsToInclude.Forward)) && include.Forward == 1; voxMeshData[voxIndex].isHidden = !voxMeshData[voxIndex].hasForward && !voxMeshData[voxIndex].hasBack && !voxMeshData[voxIndex].hasLeft && !voxMeshData[voxIndex].hasRight && !voxMeshData[voxIndex].hasUp && !voxMeshData[voxIndex].hasDown; if (voxMeshData[voxIndex].isHidden && optimization == NPVoxOptimization.PER_VOXEL) { continue; } if (voxMeshData[voxIndex].isHidden && BloodColorIndex > 0) { model.SetVoxel(voxCoord, ( byte )BloodColorIndex); // WTF WTF WTF?!? we should not modify the MODEL in here !!!! elfapo: AAAAHHH NOOOO!!!! :O j.k. ;) } // prepare cube vertices voxMeshData[voxIndex].numVertices = 0; voxMeshData[voxIndex].vertexIndexOffsetBegin = currentVertexIndex; if (optimization != NPVoxOptimization.PER_FACE || voxMeshData[voxIndex].includeBack || voxMeshData[voxIndex].includeLeft || voxMeshData[voxIndex].includeDown) { voxMeshData[voxIndex].vertexIndexOffsets[0] = voxMeshData[voxIndex].numVertices++; voxMeshData[voxIndex].vertexPositionOffsets[voxMeshData[voxIndex].vertexIndexOffsets[0]] = new Vector3(-0.5f, -0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || voxMeshData[voxIndex].includeBack || voxMeshData[voxIndex].includeRight || voxMeshData[voxIndex].includeDown) { voxMeshData[voxIndex].vertexIndexOffsets[1] = voxMeshData[voxIndex].numVertices++; voxMeshData[voxIndex].vertexPositionOffsets[voxMeshData[voxIndex].vertexIndexOffsets[1]] = new Vector3(0.5f, -0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || voxMeshData[voxIndex].includeBack || voxMeshData[voxIndex].includeLeft || voxMeshData[voxIndex].includeUp) { voxMeshData[voxIndex].vertexIndexOffsets[2] = voxMeshData[voxIndex].numVertices++; voxMeshData[voxIndex].vertexPositionOffsets[voxMeshData[voxIndex].vertexIndexOffsets[2]] = new Vector3(-0.5f, 0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || voxMeshData[voxIndex].includeBack || voxMeshData[voxIndex].includeRight || voxMeshData[voxIndex].includeUp) { voxMeshData[voxIndex].vertexIndexOffsets[3] = voxMeshData[voxIndex].numVertices++; voxMeshData[voxIndex].vertexPositionOffsets[voxMeshData[voxIndex].vertexIndexOffsets[3]] = new Vector3(0.5f, 0.5f, -0.5f); } if (optimization != NPVoxOptimization.PER_FACE || voxMeshData[voxIndex].includeForward || voxMeshData[voxIndex].includeLeft || voxMeshData[voxIndex].includeDown) { voxMeshData[voxIndex].vertexIndexOffsets[4] = voxMeshData[voxIndex].numVertices++; voxMeshData[voxIndex].vertexPositionOffsets[voxMeshData[voxIndex].vertexIndexOffsets[4]] = new Vector3(-0.5f, -0.5f, 0.5f); } if (optimization != NPVoxOptimization.PER_FACE || voxMeshData[voxIndex].includeForward || voxMeshData[voxIndex].includeRight || voxMeshData[voxIndex].includeDown) { voxMeshData[voxIndex].vertexIndexOffsets[5] = voxMeshData[voxIndex].numVertices++; voxMeshData[voxIndex].vertexPositionOffsets[voxMeshData[voxIndex].vertexIndexOffsets[5]] = new Vector3(0.5f, -0.5f, 0.5f); } if (optimization != NPVoxOptimization.PER_FACE || voxMeshData[voxIndex].includeForward || voxMeshData[voxIndex].includeLeft || voxMeshData[voxIndex].includeUp) { voxMeshData[voxIndex].vertexIndexOffsets[6] = voxMeshData[voxIndex].numVertices++; voxMeshData[voxIndex].vertexPositionOffsets[voxMeshData[voxIndex].vertexIndexOffsets[6]] = new Vector3(-0.5f, 0.5f, 0.5f); } if (optimization != NPVoxOptimization.PER_FACE || voxMeshData[voxIndex].includeForward || voxMeshData[voxIndex].includeRight || voxMeshData[voxIndex].includeUp) { voxMeshData[voxIndex].vertexIndexOffsets[7] = voxMeshData[voxIndex].numVertices++; voxMeshData[voxIndex].vertexPositionOffsets[voxMeshData[voxIndex].vertexIndexOffsets[7]] = new Vector3(0.5f, 0.5f, 0.5f); } currentVertexIndex += voxMeshData[voxIndex].numVertices; voxIndex++; } } Array.Resize(ref voxMeshData, voxIndex); return(voxMeshData); }
public static NPVoxCoord DrawVoxelHandle(Vector3 handlePosition, NPVoxCoord voxPosition, NPVoxToUnity npVoxToUnity) { int controlID = GUIUtility.GetControlID(FocusType.Passive); // if(HandleUtility.nearestControl == controlID) // { // Handles.color = Color.yellow; // } // else // { // Handles.color = Color.white; // } Handles.DotCap(controlID, handlePosition, Quaternion.identity, npVoxToUnity.VoxeSize.x * 0.25f); Vector3 screenPosition = Handles.matrix.MultiplyPoint(handlePosition); switch (Event.current.GetTypeForControl(controlID)) { case EventType.Layout: HandleUtility.AddControl( controlID, HandleUtility.DistanceToCircle(screenPosition, npVoxToUnity.VoxeSize.x * 0.25f) ); break; case EventType.MouseDown: if (HandleUtility.nearestControl == controlID && Event.current.button == 0) { mouseStartPos = Event.current.mousePosition; startCoordVox = voxPosition; // Respond to a press on this handle. Drag starts automatically. GUIUtility.hotControl = controlID; Event.current.Use(); } break; case EventType.MouseUp: if (GUIUtility.hotControl == controlID) { // Respond to a release on this handle. Drag stops automatically. GUIUtility.hotControl = 0; Event.current.Use(); } break; case EventType.MouseDrag: if (GUIUtility.hotControl == controlID) { // Do whatever with mouse deltas here GUI.changed = true; Vector3 pos = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin - HandleUtility.GUIPointToWorldRay(mouseStartPos).origin; NPVoxCoord result = startCoordVox + npVoxToUnity.ToVoxDirection(pos); if (!result.Equals(voxPosition)) { SceneView.RepaintAll(); return(result); } } break; } return(voxPosition); }
override protected NPVoxModel CreateProduct(NPVoxModel reuse = null) { if (Input == null) { return(NPVoxModel.NewInvalidInstance(reuse, "No Input Setup")); } NPVoxModel model = ((NPVoxIModelFactory)Input).GetProduct() as NPVoxModel; NPVoxModel targetModel = model; if (TargetFrame is NPVoxIModelFactory) { targetModel = ((NPVoxIModelFactory)TargetFrame).GetProduct() as NPVoxModel; } if (!(PreviousFrame is NPVoxIModelFactory)) { Debug.LogWarning("previous frame is not a model factory"); return(NPVoxModel.NewInstance(NPVoxCoord.ZERO, reuse)); } #if UNITY_EDITOR if (SocketOffsets.Length < 4 || ControlPointOffsets.Length < 4) { ResetSceneTools(); } #endif NPVoxModel sourceModel = ((NPVoxIModelFactory)PreviousFrame).GetProduct(); NPVoxSocket sourceSocket1 = sourceModel.GetSocketByName(SocketName1); NPVoxSocket sourceSocket2 = sourceModel.GetSocketByName(SocketName2); NPVoxSocket targetSocket1 = targetModel.GetSocketByName(SocketName1); NPVoxSocket targetSocket2 = targetModel.GetSocketByName(SocketName2); if (sourceSocket1.IsInvalid()) { Debug.LogWarning("SocketName1 not found in sourceModel"); return(NPVoxModel.NewInstance(NPVoxCoord.ZERO, reuse)); } if (sourceSocket2.IsInvalid()) { Debug.LogWarning("SocketName2 not found in sourceModel"); return(NPVoxModel.NewInstance(NPVoxCoord.ZERO, reuse)); } if (targetSocket1.IsInvalid()) { Debug.LogWarning("SocketName1 not found in newModel"); return(NPVoxModel.NewInstance(NPVoxCoord.ZERO, reuse)); } if (targetSocket2.IsInvalid()) { Debug.LogWarning("SocketName2 not found in oldModel"); return(NPVoxModel.NewInstance(NPVoxCoord.ZERO, reuse)); } if (TheStepSize < 0.01f) { Debug.LogWarning("Stepsize too small"); return(NPVoxModel.NewInstance(NPVoxCoord.ZERO, reuse)); } NPVoxToUnity sourceN2U = new NPVoxToUnity(sourceModel, Vector3.one); NPVoxToUnity targetN2U = new NPVoxToUnity(targetModel, Vector3.one); NPVoxToUnity modelN2U = new NPVoxToUnity(model, Vector3.one); // calculate size for our new model NPVoxBox requiredBounds = model.BoundingBox; requiredBounds.EnlargeToInclude(modelN2U.ToVoxCoord(sourceN2U.ToUnityPosition(sourceSocket1.Anchor) + SocketOffsets[INDEX_SOURCE_1])); requiredBounds.EnlargeToInclude(modelN2U.ToVoxCoord(sourceN2U.ToUnityPosition(sourceSocket2.Anchor) + SocketOffsets[INDEX_SOURCE_2])); requiredBounds.EnlargeToInclude(modelN2U.ToVoxCoord(targetN2U.ToUnityPosition(targetSocket1.Anchor) + SocketOffsets[INDEX_TARGET_1])); requiredBounds.EnlargeToInclude(modelN2U.ToVoxCoord(targetN2U.ToUnityPosition(targetSocket2.Anchor) + SocketOffsets[INDEX_TARGET_2])); requiredBounds.EnlargeToInclude(modelN2U.ToVoxCoord(sourceN2U.ToUnityPosition(sourceSocket1.Anchor) + SocketOffsets[INDEX_SOURCE_1] + ControlPointOffsets[INDEX_SOURCE_1])); requiredBounds.EnlargeToInclude(modelN2U.ToVoxCoord(sourceN2U.ToUnityPosition(sourceSocket2.Anchor) + SocketOffsets[INDEX_SOURCE_2] + ControlPointOffsets[INDEX_SOURCE_2])); requiredBounds.EnlargeToInclude(modelN2U.ToVoxCoord(targetN2U.ToUnityPosition(targetSocket1.Anchor) + SocketOffsets[INDEX_TARGET_1] + ControlPointOffsets[INDEX_TARGET_1])); requiredBounds.EnlargeToInclude(modelN2U.ToVoxCoord(targetN2U.ToUnityPosition(targetSocket2.Anchor) + SocketOffsets[INDEX_TARGET_2] + ControlPointOffsets[INDEX_TARGET_2])); // create our product model NPVoxModel productModel = NPVoxModelTransformationUtil.CreateWithNewSize(model, requiredBounds, reuse); // prepare voxel groups bool addVoxelGroups = SetVoxelGroup > 0 || productModel.HasVoxelGroups() || SetBaseVoxelGroup > 0; byte theVoxelGroup = (byte)SetVoxelGroup; if (addVoxelGroups) { if (!productModel.HasVoxelGroups()) { productModel.InitVoxelGroups(); foreach (NPVoxCoord coord in productModel.EnumerateVoxels()) { productModel.SetVoxelGroup(coord, SetBaseVoxelGroup); } } if (theVoxelGroup > productModel.NumVoxelGroups - 1) { productModel.NumVoxelGroups = (byte)(theVoxelGroup + 1); } if (SetBaseVoxelGroup > productModel.NumVoxelGroups - 1) { productModel.NumVoxelGroups = (byte)(SetBaseVoxelGroup + 1); } } // check if we have a circularloop #if UNITY_EDITOR if (NPipelineUtils.IsPrevious(PreviousFrame as NPipeIImportable, this, true)) { Debug.LogWarning("cycular pipeline detected"); return(productModel); } #endif NPVoxToUnity productN2U = new NPVoxToUnity(productModel, Vector3.one); // build our colortable bool[] usedColors = NPVoxModelUtils.GetUsedColors(productModel); Color32[] colorTable = productModel.Colortable; byte[] Colors = new byte[NumColorSteps]; Color32 startColor = Color1; Color32 endColor = Color2; bool takeColorFromModel = ColorNumFromModel > -1; if (takeColorFromModel) { byte color1 = NPVoxModelUtils.FindUsedColor(ref usedColors, ColorNumFromModel); startColor = colorTable[color1]; endColor = colorTable[color1]; endColor.a = 15; } // Debug.Log("Me: " + NPipelineUtils.GetPipelineDebugString(this)); for (int i = 0; i < NumColorSteps; i++) { byte color = NPVoxModelUtils.FindUnusedColor(ref usedColors); // Debug.Log("Color: " + color); colorTable[color] = Color32.Lerp(startColor, endColor, ((float)i / (float)NumColorSteps)); Colors[i] = color; } // calculate mathetmatical constants Vector3 unityStartPoint1 = targetN2U.ToUnityPosition(targetSocket1.Anchor) + targetN2U.ToUnityDirection(SocketOffsets[INDEX_TARGET_1]); Vector3 bezierStartPoint1 = unityStartPoint1 + targetN2U.ToUnityDirection(ControlPointOffsets[INDEX_TARGET_1]); Vector3 unityEndPoint1 = sourceN2U.ToUnityPosition(sourceSocket1.Anchor) + sourceN2U.ToUnityDirection(SocketOffsets[INDEX_SOURCE_1]); Vector3 bezierEndPoint1 = unityEndPoint1 + sourceN2U.ToUnityDirection(ControlPointOffsets[INDEX_SOURCE_1]); Vector3 direction1 = unityEndPoint1 - unityStartPoint1; float dir1len = direction1.magnitude; Vector3 unityStartPoint2 = targetN2U.ToUnityPosition(targetSocket2.Anchor) + targetN2U.ToUnityDirection(SocketOffsets[INDEX_TARGET_2]); Vector3 bezierStartPoint2 = unityStartPoint2 + targetN2U.ToUnityDirection(ControlPointOffsets[INDEX_TARGET_2]); Vector3 unityEndPoint2 = sourceN2U.ToUnityPosition(sourceSocket2.Anchor) + sourceN2U.ToUnityDirection(SocketOffsets[INDEX_SOURCE_2]); Vector3 bezierEndPoint2 = unityEndPoint2 + sourceN2U.ToUnityDirection(ControlPointOffsets[INDEX_SOURCE_2]); Vector3 direction2 = unityEndPoint2 - unityStartPoint2; float dir2len = direction2.magnitude; float travelled = 0.0f; float distance = dir1len > dir2len ? dir1len : dir2len; if (distance > MaxDistance) { distance = MaxDistance; } float StepSize = TheStepSize / distance; // draw the trail while (travelled < distance) { float alpha = (travelled / distance); float idx = alpha * (float)(NumColorSteps - 1); byte color = Colors[(int)Mathf.Round(idx)]; Vector3 currentP1 = NPVoxGeomUtil.GetBezierPoint(unityStartPoint1, bezierStartPoint1, bezierEndPoint1, unityEndPoint1, alpha); Vector3 currentP2 = NPVoxGeomUtil.GetBezierPoint(unityStartPoint2, bezierStartPoint2, bezierEndPoint2, unityEndPoint2, alpha); Vector3 currentP1vox = productN2U.ToSaveVoxCoord(currentP1); Vector3 currentP2vox = productN2U.ToSaveVoxCoord(currentP2); NPVoxGeomUtil.DrawLine(productModel, currentP1vox, currentP2vox, color, theVoxelGroup, false); // currentP1 += direction1 * stepSize1; // currentP2 += direction2 * stepSize2; travelled += StepSize; } productModel.Colortable = colorTable; productModel.RecalculateNumVoxels(); return(productModel); }