Ejemplo n.º 1
0
    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);
        }
    }
Ejemplo n.º 2
0
    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);
    }
    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);
                }
            }
        }
    }
Ejemplo n.º 6
0
    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);
        }
    }
Ejemplo n.º 8
0
    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);
    }
Ejemplo n.º 9
0
    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);
    }
Ejemplo n.º 10
0
    // ===================================================================================================
    // 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();
    }
Ejemplo n.º 11
0
    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();
        }
    }
    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);
    }
    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);
    }
Ejemplo n.º 14
0
    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();
        }
    }
Ejemplo n.º 15
0
    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 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);
    }