示例#1
0
    // Update is called once per frame
    void Update()
    {
        if (lastText == Text)
        {
            return;
        }

        lastText = Text;

        GameObjectUtil.DestroyAllChildren(this.transform);

        char[]  chars      = Text.ToCharArray();
        Vector3 currentPos = transform.position;

        for (int i = 0; i < Text.Length; i++)
        {
            char c = chars[i];
            NPVoxFont.Character character = Font.GetCharacter(c);

            if (!character.mesh || !character.material)
            {
                Debug.LogWarning("Character " + (int)c + " Not found in Font: " + c);
                continue;
            }
            NPVoxToUnity n2u = new NPVoxToUnity(character.Size, character.VoxelSize);
            GameObject   go  = GameObject.Instantiate(Font.CharacterPrefab, this.transform);
            go.transform.position = currentPos + n2u.ToUnityDirection(new Vector3(((float)character.Size.X) * 0.5f, 0.0f, 0.0f));
            currentPos           += n2u.ToUnityDirection(new NPVoxCoord(character.Size.X, 0, 0));
            go.name = (int)c + "";
            go.GetComponent <MeshFilter>().sharedMesh       = character.mesh;
            go.GetComponent <MeshRenderer>().sharedMaterial = character.material;
        }
    }
示例#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);
                }
            }
        }
    }
    void OnDrawGizmos()
    {
//        if (Selection.activeGameObject != this.gameObject)
//        {
//            return;
//        }

        NPVoxMeshOutput MeshOutput = MeshFactory as NPVoxMeshOutput;

        if (MeshOutput)
        {
            NPVoxToUnity npVoxToUnity = MeshOutput.GetNPVoxToUnity();
            NPVoxModel   model        = MeshOutput.GetVoxModel();
            if (model)
            {
                foreach (NPVoxSocket socket in model.Sockets)
                {
                    Vector3    anchorPos     = npVoxToUnity.ToUnityPosition(socket.Anchor);
                    Quaternion rotation      = Quaternion.Euler(socket.EulerAngles);
                    Vector3    anchorRight   = npVoxToUnity.ToUnityDirection(rotation * Vector3.right);
                    Vector3    anchorUp      = npVoxToUnity.ToUnityDirection(rotation * Vector3.up);
                    Vector3    anchorForward = npVoxToUnity.ToUnityDirection(rotation * Vector3.forward);

                    Gizmos.color = new Color(0.5f, 1.0f, 0.1f, 0.75f);
                    Gizmos.DrawCube(transform.position + anchorPos, Vector3.one * 0.4f);

                    Gizmos.color = Color.red;
                    Gizmos.DrawLine(transform.position + anchorPos, transform.position + anchorPos + anchorRight * 10.0f);
                    Gizmos.color = Color.green;
                    Gizmos.DrawLine(transform.position + anchorPos, transform.position + anchorPos + anchorUp * 10.0f);
                    Gizmos.color = Color.blue;
                    Gizmos.DrawLine(transform.position + anchorPos, transform.position + anchorPos + anchorForward * 10.0f);
                }
            }
        }
    }
    public System.Func <NPVoxISceneEditable, bool> DrawSceneTool(NPVoxToUnity npVoxToUnity, 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);
    }
    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);
        }
    }
    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);
    }
    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);
    }