Пример #1
0
    override protected NPVoxModel CreateProduct(NPVoxModel reuse = null)
    {
        if (Input == null)
        {
            return(NPVoxModel.NewInvalidInstance(reuse, "No Input Setup"));;
        }

        NPVoxModel model = ((NPVoxIModelFactory)Input).GetProduct();

        if (Absolute)
        {
            NPVoxModel newModel = NPVoxModel.NewInstance(model, reuse);
            newModel.CopyOver(model);

            NPVoxSocket socket = model.GetSocketByName(SocketName);
            socket.Anchor      = NPVoxCoordUtil.ToCoord(GetTranslation() + GetPivot());
            socket.EulerAngles = GetRotation().eulerAngles;
            newModel.SetSocket(socket);

            return(newModel);
        }
        else
        {
            return(NPVoxModelTransformationUtil.MatrixTransformSocket(model, SocketName, Matrix, PivotOffset, reuse));
        }
    }
Пример #2
0
    override protected NPVoxModel CreateProduct(NPVoxModel reuse = null)
    {
        if (Input != null)
        {
            // todo voxel group

            NPVoxModel inputModel = ((NPVoxIModelFactory)Input).GetProduct();

            NPVoxIModelFactory targetFactory = this.Target as NPVoxIModelFactory;
            if (targetFactory != null)
            {
                NPVoxModel targetModel = targetFactory.GetProduct();

                NPVoxSocket inputSocket  = inputModel.GetSocketByName(InputSocketName);
                NPVoxSocket targetSocket = targetModel.GetSocketByName(TargetSocketName);

                NPVoxModel model = NPVoxModelTransformationUtil.SocketTransform(inputModel, targetModel, inputSocket, targetSocket, ResolveConflictMethod, reuse);
                model.name = "zzz Model Socket Combiner";
                return(model);
            }
            else
            {
                reuse = NPVoxModel.NewInstance(inputModel, reuse);
                reuse.CopyOver(inputModel);
                return(reuse);
            }
        }
        else
        {
//            return NPVoxModel.NewInvalidInstance(reuse, "No Input Setup");
            throw new NPipeException("No Input Setup");
        }
    }
    public static NPVoxModel TransformSocket(NPVoxModel sourceModel, string socketName, Matrix4x4 transformMatrix, NPVoxModel reuse = null)
    {
        NPVoxModel transformedModel = null;

        transformedModel = NPVoxModel.NewInstance(sourceModel, reuse);
        transformedModel.CopyOver(sourceModel);

        NPVoxSocket[] sockets = new NPVoxSocket[sourceModel.Sockets.Length];
        for (int i = 0; i < sockets.Length; i++)
        {
            NPVoxSocket socket = sourceModel.Sockets[i];
            if (socket.Name == socketName)
            {
                // transform anchor
                Vector3 saveOriginalAnchor = NPVoxCoordUtil.ToVector(socket.Anchor);
                Vector3 saveTargetAnchor   = transformMatrix.MultiplyPoint(saveOriginalAnchor);
                socket.Anchor = sourceModel.Clamp(NPVoxCoordUtil.ToCoord(saveTargetAnchor));

                // transform Quaternion
                Quaternion originalRotation = Quaternion.Euler(socket.EulerAngles);
                Matrix4x4  rotated          = (Matrix4x4.TRS(Vector3.zero, originalRotation, Vector3.one) * transformMatrix);
                socket.EulerAngles = Matrix4x4Util.GetRotation(rotated).eulerAngles;
            }
            sockets[i] = socket;
        }
        transformedModel.Sockets = sockets;

        return(transformedModel);
    }
    public static NPVoxModel MatrixTransformSocket(NPVoxModel sourceModel, string socketName, Matrix4x4 matrix, Vector3 pivot, NPVoxModel reuse = null)
    {
        NPVoxSocket socket          = sourceModel.GetSocketByName(socketName);
        Vector3     pivotPoint      = NPVoxCoordUtil.ToVector(socket.Anchor) + pivot;
        Matrix4x4   transformMatrix = (Matrix4x4.TRS(pivotPoint, Quaternion.identity, Vector3.one) * matrix) * Matrix4x4.TRS(-pivotPoint, Quaternion.identity, Vector3.one);

        return(TransformSocket(sourceModel, socketName, transformMatrix, reuse));
    }
Пример #5
0
 public void SetSocket(NPVoxSocket socket)
 {
     for (int i = 0; i < this.Sockets.Length; i++)
     {
         if (this.Sockets[i].Name == socket.Name)
         {
             this.Sockets[i] = socket;
             return;
         }
     }
 }
Пример #6
0
    override public Vector3 GetPivot()
    {
        NPVoxIModelFactory modelFactory = (Input as NPVoxIModelFactory);

        if (modelFactory != null)
        {
            NPVoxSocket socket = modelFactory.GetProduct().GetSocketByName(SocketName);
            return(this.PivotOffset + NPVoxCoordUtil.ToVector(socket.Anchor));
        }
        else
        {
            return(Vector3.zero);
        }
    }
Пример #7
0
    override public void SetPivot(Vector3 pivot)
    {
        NPVoxIModelFactory modelFactory = (Input as NPVoxIModelFactory);

        if (modelFactory != null)
        {
            NPVoxSocket socket = modelFactory.GetProduct().GetSocketByName(SocketName);
            this.PivotOffset = pivot - NPVoxCoordUtil.ToVector(socket.Anchor);
        }
        else
        {
            this.PivotOffset = Vector3.zero;
        }
    }
Пример #8
0
 override public Quaternion GetRotation()
 {
     if (Absolute)
     {
         NPVoxIModelFactory modelFactory = (Input as NPVoxIModelFactory);
         if (modelFactory != null && quaternionReadFromSocketName != SocketName)
         {
             quaternionReadFromSocketName = SocketName;
             NPVoxSocket socket = modelFactory.GetProduct().GetSocketByName(SocketName);
             Matrix = Matrix4x4.TRS(GetTranslation(), Quaternion.Euler(socket.EulerAngles), Vector3.one);
         }
     }
     return(Matrix4x4Util.GetRotation(Matrix));
 }
Пример #9
0
    public NPVoxSocket GetSocketByName(string socketName)
    {
        foreach (NPVoxSocket socket in this.Sockets)
        {
            if (socket.Name == socketName)
            {
                return(socket);
            }
        }

        NPVoxSocket invalidSocket = new NPVoxSocket();

        invalidSocket.SetInvalid();
        return(invalidSocket);
    }
    public static NPVoxModel Transform(NPVoxModel sourceModel, NPVoxBox affectedArea, Matrix4x4 transformMatrix, ResolveConflictMethodType resolveConflictMethod = ResolveConflictMethodType.CLOSEST, NPVoxModel reuse = null)
    {
        NPVoxBox clampedBox = sourceModel.Clamp(affectedArea);

        // calculate size & offset for new model
        NPVoxCoord size   = sourceModel.Size;
        NPVoxCoord offset = NPVoxCoord.ZERO;
        {
            NPVoxBox parentBounds = sourceModel.BoundingBox;
            NPVoxBox thisBounds   = parentBounds.Clone();

            // transform voxels
            foreach (NPVoxCoord coord in clampedBox.Enumerate())
            {
                Vector3    saveCoord = transformMatrix.MultiplyPoint(NPVoxCoordUtil.ToVector(coord));
                NPVoxCoord newCoord  = NPVoxCoordUtil.ToCoord(saveCoord);
                if (!sourceModel.IsInside(newCoord))
                {
                    thisBounds.EnlargeToInclude(newCoord);
                }
            }
            // transform sockets
            foreach (NPVoxSocket socket in sourceModel.Sockets)
            {
                NPVoxCoord newCoord = NPVoxCoordUtil.ToCoord(transformMatrix.MultiplyPoint(NPVoxCoordUtil.ToVector(socket.Anchor)));
                if (clampedBox.Contains(socket.Anchor) && !sourceModel.IsInside(newCoord))
                {
                    thisBounds.EnlargeToInclude(newCoord);
                }
            }

            CalculateResizeOffset(parentBounds, thisBounds, out offset, out size);
        }


        bool           hasVoxelGroups  = sourceModel.HasVoxelGroups();
        NPVoxBoneModel sourceBoneModel = sourceModel as NPVoxBoneModel;
        bool           hasBoneGropus   = sourceBoneModel != null;

        NPVoxModel     transformedModel     = NPVoxModel.NewInstance(sourceModel, size, reuse);
        NPVoxBoneModel transformedBoneModel = transformedModel as NPVoxBoneModel;

        if (hasVoxelGroups)
        {
            transformedModel.InitVoxelGroups();
            transformedModel.NumVoxelGroups = sourceModel.NumVoxelGroups;
        }
        if (hasBoneGropus)
        {
            transformedBoneModel.AllBones = NPVoxBone.CloneBones(sourceBoneModel.AllBones);
        }

        // 1. copy all voxels over that are not affected by the transformation
        transformedModel.NumVoxels  = sourceModel.NumVoxels;
        transformedModel.Colortable = sourceModel.Colortable;
        foreach (NPVoxCoord coord in sourceModel.EnumerateVoxels())
        {
            NPVoxCoord movedCoord = coord + offset;
            if (!clampedBox.Contains(coord))
            {
                transformedModel.SetVoxel(movedCoord, sourceModel.GetVoxel(coord));
                if (hasVoxelGroups)
                {
                    transformedModel.SetVoxelGroup(movedCoord, sourceModel.GetVoxelGroup(coord));
                }
                if (hasBoneGropus)
                {
                    transformedBoneModel.SetBoneMask(movedCoord, sourceBoneModel.GetBoneMask(coord));
                }
            }
        }

        // 2. copy all voxels that can be tranformed without conflict,
        Dictionary <NPVoxCoord, Vector3> conflictVoxels = new Dictionary <NPVoxCoord, Vector3>();

        foreach (NPVoxCoord sourceCoord in clampedBox.Enumerate())
        {
            if (sourceModel.HasVoxelFast(sourceCoord))
            {
                Vector3    saveCoord       = transformMatrix.MultiplyPoint(NPVoxCoordUtil.ToVector(sourceCoord));
                Vector3    targetCoordSave = saveCoord + NPVoxCoordUtil.ToVector(offset);
                NPVoxCoord targetCoord     = NPVoxCoordUtil.ToCoord(targetCoordSave);

                if (!transformedModel.HasVoxelFast(targetCoord))
                {
                    transformedModel.SetVoxel(targetCoord, sourceModel.GetVoxel(sourceCoord));
                    if (hasVoxelGroups)
                    {
                        transformedModel.SetVoxelGroup(targetCoord, sourceModel.GetVoxelGroup(sourceCoord));
                    }
                    if (hasBoneGropus)
                    {
                        transformedBoneModel.SetBoneMask(targetCoord, sourceBoneModel.GetBoneMask(sourceCoord));
                    }
                }
                else
                {
                    conflictVoxels[sourceCoord] = targetCoordSave;
                }
            }
        }

        // 3. try to fit in voxels that had conflicts
        int numberOfConflictsSolved = 0;

        if (resolveConflictMethod != ResolveConflictMethodType.NONE)
        {
            foreach (NPVoxCoord sourceCoord in conflictVoxels.Keys)
            {
                if (sourceModel.HasVoxelFast(sourceCoord))
                {
                    Vector3    targetSaveCoord = conflictVoxels[sourceCoord];
                    NPVoxCoord nearbyCoord     = GetNearbyCoord(transformedModel, targetSaveCoord, resolveConflictMethod);
                    if (!nearbyCoord.Equals(NPVoxCoord.INVALID))
                    {
                        transformedModel.SetVoxel(nearbyCoord, sourceModel.GetVoxel(sourceCoord));
                        if (hasVoxelGroups)
                        {
                            transformedModel.SetVoxelGroup(nearbyCoord, sourceModel.GetVoxelGroup(sourceCoord));
                        }
                        if (hasBoneGropus)
                        {
                            transformedBoneModel.SetBoneMask(nearbyCoord, sourceBoneModel.GetBoneMask(sourceCoord));
                        }
                        numberOfConflictsSolved++;
                    }
                }
            }

            if (numberOfConflictsSolved != conflictVoxels.Count)
            {
                Debug.Log(string.Format("transformation has resolved {0}/{1} conflicting voxels", numberOfConflictsSolved, conflictVoxels.Count));
            }
        }

        // 4. transform all sockets
        NPVoxSocket[] sockets = new NPVoxSocket[sourceModel.Sockets.Length];
        for (int i = 0; i < sockets.Length; i++)
        {
            NPVoxSocket socket = sourceModel.Sockets[i];
            if (clampedBox.Contains(socket.Anchor))
            {
                // transform anchor
                Vector3 saveOriginalAnchor = NPVoxCoordUtil.ToVector(socket.Anchor);
                Vector3 saveTargetAnchor   = transformMatrix.MultiplyPoint(saveOriginalAnchor) + NPVoxCoordUtil.ToVector(offset);
                socket.Anchor = NPVoxCoordUtil.ToCoord(saveTargetAnchor);

                // transform Quaternion
                Quaternion originalRotation = Quaternion.Euler(socket.EulerAngles);
                Matrix4x4  rotated          = (Matrix4x4.TRS(Vector3.zero, originalRotation, Vector3.one) * transformMatrix);
                socket.EulerAngles = Matrix4x4Util.GetRotation(rotated).eulerAngles;
            }
            else
            {
                socket.Anchor = socket.Anchor + offset;
            }
            sockets[i] = socket;
        }
        transformedModel.Sockets = sockets;


        // 5. count all voxels
        transformedModel.NumVoxels = transformedModel.NumVoxels - (conflictVoxels.Count - numberOfConflictsSolved);
        transformedModel.RecalculateNumVoxels(true);
        return(transformedModel);
    }
    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 static NPVoxModel CreateFlippedModel(NPVoxModel source, NPVoxCoord xFlip, NPVoxCoord yFlip, NPVoxCoord zFlip, NPVoxModel reuse = null)
    {
        sbyte      sizeX = (sbyte)(xFlip.X * source.SizeX + xFlip.Z * source.SizeZ + xFlip.Y * source.SizeY);
        sbyte      sizeY = (sbyte)(yFlip.X * source.SizeX + yFlip.Z * source.SizeZ + yFlip.Y * source.SizeY);
        sbyte      sizeZ = (sbyte)(zFlip.X * source.SizeX + zFlip.Z * source.SizeZ + zFlip.Y * source.SizeY);
        NPVoxModel model = NPVoxModel.NewInstance(source, new NPVoxCoord(
                                                      (sbyte)Mathf.Abs(sizeX),
                                                      (sbyte)Mathf.Abs(sizeY),
                                                      (sbyte)Mathf.Abs(sizeZ)
                                                      ), reuse);
        sbyte xOffset = 0;

        if (sizeX < 0)
        {
            xOffset = (sbyte)((sizeX - 1));
        }
        sbyte yOffset = 0;

        if (sizeY < 0)
        {
            yOffset = (sbyte)((sizeY - 1));
        }
        sbyte zOffset = 0;

        if (sizeZ < 0)
        {
            zOffset = (sbyte)((sizeZ - 1));
        }

        NPVoxFaces allFaces = new NPVoxFaces();

        allFaces.Back    = 1;
        allFaces.Forward = 1;
        allFaces.Left    = 1;
        allFaces.Right   = 1;
        allFaces.Up      = 1;
        allFaces.Down    = 1;

        bool hasVoxelGroups = source.HasVoxelGroups();

        if (hasVoxelGroups)
        {
            model.InitVoxelGroups();
        }
        model.NumVoxelGroups = source.NumVoxelGroups;
        model.Colortable     = source.Colortable;
        model.NumVoxels      = source.NumVoxels;

        // Transform Coordinates
        foreach (NPVoxCoord sourceCoord in source.Enumerate())
        {
            NPVoxCoord coord = new NPVoxCoord(
                (sbyte)(xOffset + (xFlip.X * sourceCoord.X + xFlip.Z * sourceCoord.Z + xFlip.Y * sourceCoord.Y)),
                (sbyte)(yOffset + (yFlip.X * sourceCoord.X + yFlip.Z * sourceCoord.Z + yFlip.Y * sourceCoord.Y)),
                (sbyte)(zOffset + (zFlip.X * sourceCoord.X + zFlip.Z * sourceCoord.Z + zFlip.Y * sourceCoord.Y))
                );
            coord = model.LoopCoord(coord, allFaces);

            model.SetVoxel(coord, source.GetVoxel(sourceCoord));
            if (hasVoxelGroups)
            {
                model.SetVoxelGroup(coord, source.GetVoxelGroup(sourceCoord));
            }
        }

        // Transform Sockets
//        Matrix4x4 t = Matrix4x4.identity;
//        if (xFlip.X != 0) t = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(xFlip.X, 1, 1));
//        if (xFlip.Y != 0) t *= Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1, xFlip.Y, 1));
//        if (xFlip.Z != 0) t *= Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1, 1, xFlip.Z));

        NPVoxSocket[] sockets = new NPVoxSocket[source.Sockets.Length];
        for (int i = 0; i < sockets.Length; i++)
        {
            // Anchor
            NPVoxCoord sourceCoord = source.Sockets[i].Anchor;
            NPVoxCoord anchorCoord = new NPVoxCoord(
                (sbyte)(xOffset + (xFlip.X * sourceCoord.X + xFlip.Z * sourceCoord.Z + xFlip.Y * sourceCoord.Y)),
                (sbyte)(yOffset + (yFlip.X * sourceCoord.X + yFlip.Z * sourceCoord.Z + yFlip.Y * sourceCoord.Y)),
                (sbyte)(zOffset + (zFlip.X * sourceCoord.X + zFlip.Z * sourceCoord.Z + zFlip.Y * sourceCoord.Y))
                );
            anchorCoord = model.LoopCoord(anchorCoord, allFaces);

            sockets[i].Name   = source.Sockets[i].Name;
            sockets[i].Anchor = anchorCoord;

            // transform Quaternion
            Quaternion rotation = Quaternion.Euler(source.Sockets[i].EulerAngles);

            Vector3 anchorRight   = rotation * Vector3.right;
            Vector3 anchorUp      = rotation * Vector3.up;
            Vector3 anchorForward = rotation * Vector3.forward;

            Vector3 newRight   = anchorRight;
            Vector3 newUp      = anchorUp;
            Vector3 newForward = anchorForward;

            if (xFlip.X < 0)
            {
                newRight.Scale(new Vector3(-1f, 1f, 1f));
                newUp.Scale(new Vector3(-1f, 1f, 1f));
                newForward.Scale(new Vector3(-1f, 1f, 1f));
                Quaternion q = Quaternion.LookRotation(newForward, newUp);
                sockets[i].EulerAngles = q.eulerAngles;
            }
            // TODO: other mirrors not yet supported
        }
        model.Sockets = sockets;

        model.name = "zzz Flipped Model";
        return(model);
    }
    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);
    }