예제 #1
0
    public NPVoxBox GetAffectedArea(uint boneMask)
    {
        NPVoxBox affectedArea = null;

        foreach (NPVoxCoord coord in Enumerate())
        {
            if (IsInBoneMask(coord, boneMask))
            {
                if (affectedArea == null)
                {
                    affectedArea = new NPVoxBox(coord, coord);
                }
                else
                {
                    affectedArea.EnlargeToInclude(coord);
                }
            }
        }

        if (affectedArea == null)
        {
            Debug.Log("Bone Mask did not produce any valid affected area");
            affectedArea = NPVoxBox.INVALID;
        }

        return(affectedArea);
    }
예제 #2
0
    override protected NPVoxModel CreateProduct(NPVoxModel reuse = null)
    {
        if (Input == null)
        {
            return(NPVoxModel.NewInvalidInstance(reuse, "No Input Setup"));
        }

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

        // backwards compatibility
        if (TryToResolveConflicts == false)
        {
            TryToResolveConflicts = true;
            ResolveConflictMethod = NPVoxModelTransformationUtil.ResolveConflictMethodType.NONE;
        }

        // shift afftected area if the parent bounding box changed
        {
            NPVoxBox parentBounds = model.BoundingBox;
            if (!lastParentModelBounds.Equals(NPVoxBox.INVALID) && !lastParentModelBounds.Equals(parentBounds))
            {
                sbyte      deltaX = (sbyte)((parentBounds.Right - lastParentModelBounds.Right) / 2);
                sbyte      deltaY = (sbyte)((parentBounds.Up - lastParentModelBounds.Up) / 2);
                sbyte      deltaZ = (sbyte)((parentBounds.Forward - lastParentModelBounds.Forward) / 2);
                NPVoxCoord delta  = new NPVoxCoord(deltaX, deltaY, deltaZ);
                AffectedArea = new NPVoxBox(AffectedArea.LeftDownBack + delta, AffectedArea.RightUpForward + delta);
                // Debug.Log("Moving affected area by + " + deltaX + " " + deltaY + " " + deltaZ);
            }
            lastParentModelBounds = parentBounds;
        }

        return(NPVoxModelTransformationUtil.MatrixTransform(model, AffectedArea, Matrix, PivotOffset, ResolveConflictMethod, reuse));
    }
    public static NPVoxBoneModel MatrixTransform(NPVoxBoneModel sourceModel, NPVoxBox affectedArea, uint boneMask, Matrix4x4 matrix, Vector3 pivot, ResolveConflictMethodType resolveConflictMethod = ResolveConflictMethodType.CLOSEST, NPVoxModel reuse = null, byte markColor = 0)
    {
        Vector3   pivotPoint      = affectedArea.SaveCenter + pivot;
        Matrix4x4 transformMatrix = (Matrix4x4.TRS(pivotPoint, Quaternion.identity, Vector3.one) * matrix) * Matrix4x4.TRS(-pivotPoint, Quaternion.identity, Vector3.one);

        return(Transform(sourceModel, affectedArea, boneMask, transformMatrix, resolveConflictMethod, reuse, markColor));
    }
    public void DeleteBox(NPVoxBone bone, NPVoxBox box)
    {
        Undo.RecordObject(this, "Delete Box");
        List <NPVoxBox> boxes = GetBoxes(bone);

        boxes.Remove(box);
    }
예제 #5
0
    private NPVoxModel CreateSlicedModel(NPVoxModel source, NPVoxModel reuse)
    {
        NPVoxBox targetBox    = slice.Clone();
        NPVoxBox sourceBounds = source.BoundingBox;

        targetBox.Clamp(source.BoundingBox);

        NPVoxCoord origin    = targetBox.LeftDownBack;
        NPVoxModel model     = NPVoxModel.NewInstance(source, targetBox.Size, reuse);
        int        numVoxels = 0;

        foreach (NPVoxCoord coord in targetBox.Enumerate())
        {
            if (source.HasVoxel(coord))
            {
                numVoxels++;
                model.SetVoxel(coord - origin, source.GetVoxel(coord));
            }
        }

        model.NumVoxels  = numVoxels;
        model.Colortable = source.Colortable;

        return(model);
    }
예제 #6
0
    public void Contains_ShouldReturnFalseWhenInBox()
    {
        NPVoxBox sut = NPVoxBox.FromCenterSize(new NPVoxCoord(2, 2, 2), new NPVoxCoord(3, 3, 3));

        Assert.IsFalse(sut.Contains(new NPVoxCoord(0, 0, 0)));
        Assert.IsFalse(sut.Contains(new NPVoxCoord(4, 4, 4)));
    }
예제 #7
0
 public void Clamp(NPVoxBox max)
 {
     if (Left < max.Left)
     {
         Left = max.Left;
     }
     if (Right > max.Right)
     {
         Right = max.Right;
     }
     if (Down < max.Down)
     {
         Down = max.Down;
     }
     if (Up > max.Up)
     {
         Up = max.Up;
     }
     if (Back < max.Back)
     {
         Back = max.Back;
     }
     if (Forward > max.Forward)
     {
         Forward = max.Forward;
     }
 }
예제 #8
0
    public void Size_ShouldReturnCorrectSize()
    {
        NPVoxBox sut = new NPVoxBox(new NPVoxCoord(1, 1, 1), new NPVoxCoord(4, 4, 4));

        Assert.AreEqual(4, sut.Size.X);
        Assert.AreEqual(4, sut.Size.Y);
        Assert.AreEqual(4, sut.Size.Z);
    }
예제 #9
0
    public void Contains_ShouldReturnTrueWhenInBox()
    {
        NPVoxBox sut = NPVoxBox.FromCenterSize(new NPVoxCoord(2, 2, 2), new NPVoxCoord(3, 3, 3));

        Assert.IsTrue(sut.Contains(new NPVoxCoord(2, 2, 2)));
        Assert.IsTrue(sut.Contains(new NPVoxCoord(1, 1, 1)));
        Assert.IsTrue(sut.Contains(new NPVoxCoord(3, 3, 3)));
    }
예제 #10
0
    public void Clamp_ShouldReturnClampedVoxBox()
    {
        NPVoxModel sut = NPVoxModel.NewInstance(new NPVoxCoord(3, 3, 3));
        NPVoxBox   box = sut.Clamp(new NPVoxBox(new NPVoxCoord(-2, -2, -2), new NPVoxCoord(6, 6, 6)));

        Assert.AreEqual(new NPVoxCoord(2, 2, 2), box.RightUpForward);
        Assert.AreEqual(new NPVoxCoord(0, 0, 0), box.LeftDownBack);
    }
예제 #11
0
    public void Center_ShouldReturnCorrectCenter()
    {
        NPVoxBox sut = new NPVoxBox(new NPVoxCoord(1, 1, 1), new NPVoxCoord(3, 3, 3));

        Assert.AreEqual(2, sut.Center.X);
        Assert.AreEqual(2, sut.Center.Y);
        Assert.AreEqual(2, sut.Center.Z);
    }
예제 #12
0
    public override bool Equals(System.Object other)
    {
        NPVoxBox o = other as NPVoxBox;

        if (o == null)
        {
            return(false);
        }
        return(o.LeftDownBack.Equals(this.leftDownBack) && o.RightUpForward.Equals(this.rightUpForward));
    }
예제 #13
0
 public NPVoxBox Clamp(NPVoxBox box)
 {
     if (IsInside(box.LeftDownBack) && IsInside(box.RightUpForward))
     {
         return(box);
     }
     else
     {
         return(new NPVoxBox(Clamp(box.LeftDownBack), Clamp(box.RightUpForward)));
     }
 }
예제 #14
0
    private bool DrawBoxSelection()
    {
        if (viewModel.PreviousModelFactory == null)
        {
            return(false);
        }
        NPVoxModel   previousTransformedModel = viewModel.PreviousModelFactory.GetProduct();
        NPVoxToUnity npVoxToUnity             = new NPVoxToUnity(previousTransformedModel, viewModel.Animation.MeshFactory.VoxelSize);

        List <NPVoxBox> boxes = viewModel.GetNonEditableBoxes();

        if (boxes != null)
        {
            foreach (NPVoxBox b in boxes)
            {
                NPVoxHandles.DrawBoxSelection(npVoxToUnity, b, false);
            }
        }

        if (!viewModel.IsAreaSelectionActive())
        {
            return(false);
        }


        NPVoxBox box = viewModel.GetAffectedBox();

        if (Event.current.shift)
        {
            // affected area picker
            NPVoxCoord someCoord    = box.RoundedCenter;
            NPVoxCoord someNewCoord = NPVoxHandles.VoxelPicker(new NPVoxToUnity(previousTransformedModel, viewModel.Animation.MeshFactory.VoxelSize), someCoord, 0, ((NPVoxAnimationEditorSession)target).previewFilter.transform);
            if (!someCoord.Equals(someNewCoord))
            {
                viewModel.ChangeAffectedBox(new NPVoxBox(someNewCoord, someNewCoord));
            }
        }
        else
        {
            // affected area box
            NPVoxBox newBox = NPVoxHandles.DrawBoxSelection(npVoxToUnity, box);
            if (!newBox.Equals(box))
            {
                viewModel.ChangeAffectedBox(newBox);
            }
        }

        return(true);
    }
예제 #15
0
    public void FromCenterSize_ShouldConstructCorrectBox()
    {
        NPVoxBox sut = NPVoxBox.FromCenterSize(new NPVoxCoord(2, 2, 2), new NPVoxCoord(3, 3, 3));

        Assert.AreEqual(2, sut.Center.X);
        Assert.AreEqual(2, sut.Center.Y);
        Assert.AreEqual(2, sut.Center.Z);
        Assert.AreEqual(3, sut.Size.X);
        Assert.AreEqual(3, sut.Size.Y);
        Assert.AreEqual(3, sut.Size.Z);
        Assert.AreEqual(1, sut.LeftDownBack.X);
        Assert.AreEqual(1, sut.LeftDownBack.Y);
        Assert.AreEqual(1, sut.LeftDownBack.Z);
        Assert.AreEqual(3, sut.RightUpForward.X);
        Assert.AreEqual(3, sut.RightUpForward.Y);
        Assert.AreEqual(3, sut.RightUpForward.Z);
    }
    public static NPVoxCoord GetNearbyCoord(NPVoxModel model, Vector3 saveCoord, ResolveConflictMethodType resolveConflictMethod)
    {
        NPVoxCoord favoriteCoord = NPVoxCoordUtil.ToCoord(saveCoord);

        if (model.HasVoxelFast(favoriteCoord))
        {
            NPVoxBox box = new NPVoxBox(favoriteCoord - NPVoxCoord.ONE, favoriteCoord + NPVoxCoord.ONE);
            favoriteCoord = NPVoxCoord.INVALID;
            float nearestDistance             = 9999f;
            int   favoriteEnclosingVoxelCount = -1;
            foreach (NPVoxCoord currentTestCoord in box.Enumerate())
            {
                if (model.IsInside(currentTestCoord) && !model.HasVoxelFast(currentTestCoord))
                {
                    if (resolveConflictMethod == ResolveConflictMethodType.CLOSEST)
                    {
                        float distance = Vector3.Distance(NPVoxCoordUtil.ToVector(currentTestCoord), saveCoord);
                        if (distance < nearestDistance)
                        {
                            nearestDistance = distance;
                            favoriteCoord   = currentTestCoord;
                        }
                    }
                    else
                    {
                        int      enclosingVoxelCount = 0;
                        NPVoxBox enclosingBoxCheck   = new NPVoxBox(currentTestCoord - NPVoxCoord.ONE, currentTestCoord + NPVoxCoord.ONE);
                        foreach (NPVoxCoord enclosingTestCoord in enclosingBoxCheck.Enumerate())
                        {
                            if (model.IsInside(currentTestCoord) && model.HasVoxelFast(currentTestCoord))
                            {
                                enclosingVoxelCount++;
                            }
                        }

                        if (enclosingVoxelCount > favoriteEnclosingVoxelCount)
                        {
                            enclosingVoxelCount = favoriteEnclosingVoxelCount;
                            favoriteCoord       = currentTestCoord;
                        }
                    }
                }
            }
        }
        return(favoriteCoord);
    }
    public static NPVoxModel CreateWithNewSize(NPVoxModel source, NPVoxBox newBounds, NPVoxModel reuse = null)
    {
        NPVoxCoord delta;
        NPVoxCoord newSize;

        CalculateResizeOffset(source.BoundingBox, newBounds, out delta, out newSize);

        NPVoxModel newModel = NPVoxModel.NewInstance(source, newSize, reuse);

        newModel.NumVoxels      = source.NumVoxels;
        newModel.NumVoxelGroups = source.NumVoxelGroups;
        newModel.Colortable     = source.Colortable != null ? (Color32[])source.Colortable.Clone() : null;
        newModel.Sockets        = source.Sockets != null ? (NPVoxSocket[])source.Sockets.Clone() : null;

        if (newModel.Sockets != null)
        {
            for (int i = 0; i < newModel.Sockets.Length; i++)
            {
                newModel.Sockets[i].Anchor = newModel.Sockets[i].Anchor + delta;
            }
        }

        bool hasVoxelGroups = source.HasVoxelGroups();

        if (hasVoxelGroups)
        {
            newModel.InitVoxelGroups();
            newModel.NumVoxelGroups = source.NumVoxelGroups;
        }

        foreach (NPVoxCoord coord in source.EnumerateVoxels())
        {
            NPVoxCoord targetCoord = coord + delta;
            newModel.SetVoxel(targetCoord, source.GetVoxel(coord));
            if (hasVoxelGroups)
            {
                newModel.SetVoxelGroup(targetCoord, source.GetVoxelGroup(coord));
            }
        }

//        newModel.InvalidateVoxelCache();

        return(newModel);
    }
    public static void CalculateResizeOffset(NPVoxBox parentBounds, NPVoxBox thisBounds, out NPVoxCoord delta, out NPVoxCoord size)
    {
        if (!thisBounds.Equals(parentBounds))
        {
            size = parentBounds.Size;
            bool isOverflow = false;

            sbyte deltaX = (sbyte)(Mathf.Max(parentBounds.Left - thisBounds.Left, thisBounds.Right - parentBounds.Right));
            if ((int)deltaX * 2 + (int)size.X > 126) // check for overflow
            {
                deltaX     = (sbyte)((float)deltaX - Mathf.Ceil(((float)deltaX * 2f + (float)size.X) - 126) / 2f);
                isOverflow = true;
            }

            sbyte deltaY = (sbyte)(Mathf.Max(parentBounds.Down - thisBounds.Down, thisBounds.Up - parentBounds.Up));
            if ((int)deltaY * 2 + (int)size.Y > 126) // check for overflow
            {
                deltaY     = (sbyte)((float)deltaY - Mathf.Ceil(((float)deltaY * 2f + (float)size.Y) - 126) / 2f);
                isOverflow = true;
            }

            sbyte deltaZ = (sbyte)(Mathf.Max(parentBounds.Back - thisBounds.Back, thisBounds.Forward - parentBounds.Forward));
            if ((int)deltaZ * 2 + (int)size.Z > 126) // check for overflow
            {
                deltaZ     = (sbyte)((float)deltaZ - Mathf.Ceil(((float)deltaZ * 2f + (float)size.Z) - 126) / 2f);
                isOverflow = true;
            }

            delta = new NPVoxCoord(deltaX, deltaY, deltaZ);
            size  = size + delta + delta;

            if (isOverflow)
            {
                Debug.LogWarning("Transformed Model is large, clamped to " + size);
            }
        }
        else
        {
            size  = parentBounds.Size;
            delta = NPVoxCoord.ZERO;
        }
    }
 public void ChangeAffectedBox(NPVoxBox newBox)
 {
     ChangeTransformation((NPVoxISceneEditable transformer) =>
     {
         if (transformer is NPVoxSkeletonBuilder)
         {
             if (((NPVoxSkeletonBuilder)transformer).CurrentEditedBox != null)
             {
                 ((NPVoxSkeletonBuilder)transformer).CurrentEditedBox.LeftDownBack   = newBox.LeftDownBack;
                 ((NPVoxSkeletonBuilder)transformer).CurrentEditedBox.RightUpForward = newBox.RightUpForward;
             }
             return(false);
         }
         else
         {
             ((NPVoxModelTransformer)transformer).AffectedArea = newBox;
             return(true);
         }
     }
                          );
 }
예제 #20
0
    override protected NPVoxModel CreateProduct(NPVoxModel reuse = null)
    {
        if (Input == null)
        {
            return(NPVoxModel.NewInvalidInstance(reuse, "No Input Setup"));
        }

        NPVoxBoneModel model = ((NPVoxIModelFactory)Input).GetProduct() as NPVoxBoneModel;

        if (model == null)
        {
            return(NPVoxModel.NewInvalidInstance(reuse, "Can only transform bone models"));
        }

        // hack to center pivot on selected bones
        if (regenerateName)
        {
            RecenterBonePivot(model);
        }

        RegenerateName(model);

        NPVoxBox affectedBox = GetAffectedBox();

        if (affectedBox.Equals(NPVoxBox.INVALID))
        {
            NPVoxModel newInstance = NPVoxModel.NewInstance(model, reuse);
            newInstance.CopyOver(model);
            newInstance.RecalculateNumVoxels(true);
            return(newInstance);
        }
        else
        {
            reuse = NPVoxModelTransformationUtil.MatrixTransform(model, affectedBox, boneMask, Matrix, PivotOffset, ResolveConflictMethod, reuse);
            reuse.RecalculateNumVoxels(true);
            return(reuse);
        }
    }
예제 #21
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);
        }
    }
예제 #22
0
    public NPVoxBox GetAffectedBox()
    {
        if (Input == null)
        {
            Debug.Log("Input was NULL");
            return(NPVoxBox.INVALID);
        }

        NPVoxBoneModel affectedAreaSourceModel = (Input as NPVoxIModelFactory).GetProduct() as NPVoxBoneModel;

        if (affectedAreaSourceModel == null)
        {
            Debug.Log("Input did not procue a bone model");
            return(NPVoxBox.INVALID);
        }

        if (affectedAreaSourceModel == this.lastAffectedAreaSourceModel && this.lastAffectedAreaSourceModelVersion == affectedAreaSourceModel.GetVersion() && lastAffectedAreaBoneMask == this.boneMask)
        {
            return(lastAffectedArea);
        }

        NPVoxBox affectedArea = affectedAreaSourceModel.GetAffectedArea(boneMask);

        this.lastAffectedArea = affectedArea;
        this.lastAffectedAreaSourceModelVersion = affectedAreaSourceModel.GetVersion();
        this.lastAffectedAreaSourceModel        = affectedAreaSourceModel;
        this.lastAffectedAreaBoneMask           = this.boneMask;

        if (lastAffectedArea == null)
        {
            lastAffectedArea = NPVoxBox.INVALID;
        }

//        Debug.Log("Recalculate Affected Area");

        return(lastAffectedArea);
    }
    public void AddTransformation(NPVoxCompositeProcessorBase <NPVoxIModelFactory, NPVoxModel> template = null)
    {
        Undo.RecordObjects(new Object[] { this, animation }, "Add Transformation ");
        NPVoxCompositeProcessorBase <NPVoxIModelFactory, NPVoxModel> transformer;

        if (template != null)
        {
            transformer = (NPVoxCompositeProcessorBase <NPVoxIModelFactory, NPVoxModel>)template.Clone();
        }
        else
        {
            transformer = (NPVoxModelTransformer)NPVoxModelTransformer.CreateInstance(typeof(NPVoxModelTransformer));
            if (this.CurrentModelFactory != null && ((NPVoxModelTransformer)transformer))
            {
                NPVoxModel model = this.CurrentModelFactory.GetProduct();
                UnityEngine.Assertions.Assert.IsNotNull(model);
                ((NPVoxModelTransformer)transformer).AffectedArea = NPVoxBox.FromCenterSize(model.BoundingBox.RoundedCenter, new NPVoxCoord(3, 3, 3));
            }
        }
        SelectedFrame.AppendTransformer(transformer);
        InvalidateOutputMeshes();
        SelectTransformation(Transformers.Length - 1, true);
        this.SetCurrentTool(Tool.AREA);
    }
예제 #24
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);
    }
예제 #25
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();
        }
    }
    public override void Process(NPVoxModel model, NPVoxMeshTempData tempdata, Vector3[] inNormals, ref Vector3[] outNormals)
    {
        if (meshReference != null)
        {
            Vector3 sizeVoxel = tempdata.voxToUnity.VoxeSize;
            if (!dataAlreadyCollected)
            {
                Vector3  sizeVoxModel   = tempdata.voxToUnity.UnityVoxModelSize;
                NPVoxBox boundsVoxModel = model.BoundingBox;
                Bounds   boundsMesh     = meshReference.bounds;

                offset = boundsMesh.min;

                scale = new Vector3(
                    boundsMesh.size.x / sizeVoxModel.x,
                    boundsMesh.size.y / sizeVoxModel.z,
                    boundsMesh.size.z / sizeVoxModel.y
                    );

                meshReference.GetNormals(meshNormals);

                meshReference.GetVertices(meshVertices);
                triangleList = meshReference.GetTriangles(0);
            }

            Vector3 x = new Vector3(
                (tempdata.voxCoord.X + 0.5f) * sizeVoxel.x,
                (tempdata.voxCoord.Y + 0.5f) * sizeVoxel.y,
                (tempdata.voxCoord.Z + 0.5f) * sizeVoxel.z
                );

            x = new Vector3(
                x.x * scale.x,
                x.z * scale.z,
                x.y * scale.y
                );

            x += offset;

            int     bestTriangle        = -1;
            float   bestDistanceSquared = float.PositiveInfinity;
            Vector3 bestNormal          = Vector3.zero;
            Vector3 bestPoint           = Vector3.zero;

            for (int triangle = 0; triangle < triangleList.Length; triangle += 3)
            {
                Vector3 v1 = meshVertices[triangleList[triangle + 0]];
                Vector3 v2 = meshVertices[triangleList[triangle + 1]];
                Vector3 v3 = meshVertices[triangleList[triangle + 2]];

                Bounds boundTest = new Bounds(v1, Vector3.zero);
                boundTest.Encapsulate(v2);
                boundTest.Encapsulate(v3);
                boundTest.Expand(0.1f);

                if (!boundTest.Contains(x))
                {
                    continue;
                }

                Vector3 n = LinearAlgebra.ComputePlaneNormal(v1, v2, v3);

                Vector3 xProjected;
                LinearAlgebra.ProjectPointToPlane(v1, n, x, out xProjected);

                Vector3 xBarycentric = LinearAlgebra.WorldToBarycentric3(v1, v2, v3, xProjected);

                if (xBarycentric.x < 0.0)
                {
                    xProjected = LinearAlgebra.ClampToLine(v2, v3, xProjected);
                }

                else if (xBarycentric.y < 0.0)
                {
                    xProjected = LinearAlgebra.ClampToLine(v3, v1, xProjected);
                }

                else if (xBarycentric.z < 0.0)
                {
                    xProjected = LinearAlgebra.ClampToLine(v1, v2, xProjected);
                }

                float sqaredDistance = (xProjected - x).sqrMagnitude;

                if (!float.IsNaN(sqaredDistance) && sqaredDistance < bestDistanceSquared)
                {
                    bestDistanceSquared = sqaredDistance;
                    bestTriangle        = triangle;
                    bestNormal          = n;
                    bestPoint           = xProjected;
                }
            }

            Vector3 average = Vector3.zero;

            bool smoothNormals = true;

            if (bestTriangle != -1)
            {
                if (smoothNormals)
                {
                    average = LinearAlgebra.BarycentricToWorld(
                        meshNormals[triangleList[bestTriangle + 0]],
                        meshNormals[triangleList[bestTriangle + 1]],
                        meshNormals[triangleList[bestTriangle + 2]],
                        LinearAlgebra.WorldToBarycentric3(
                            meshVertices[triangleList[bestTriangle + 0]],
                            meshVertices[triangleList[bestTriangle + 1]],
                            meshVertices[triangleList[bestTriangle + 2]],
                            bestPoint)
                        );
                }
                else
                {
                    average = meshNormals[triangleList[bestTriangle]];
                    //average = new Vector3(
                    //    bestNormal.x,
                    //    bestNormal.z,
                    //    bestNormal.y
                    //    );
                }


                average = new Vector3(
                    average.x / scale.x,
                    average.z / scale.z,
                    average.y / scale.y
                    );
            }

            for (int t = 0; t < tempdata.numVertices; t++)
            {
                outNormals[tempdata.vertexIndexOffsetBegin + t] = average;
            }
        }
        else
        {
            for (int t = 0; t < tempdata.numVertices; t++)
            {
                outNormals[tempdata.vertexIndexOffsetBegin + t] = inNormals[tempdata.vertexIndexOffsetBegin + t];
            }
        }
    }
    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);
    }
예제 #28
0
    override protected NPVoxModel CreateProduct(NPVoxModel reuse = null)
    {
        if (Input == null)
        {
            return(NPVoxModel.NewInvalidInstance(reuse, "Input was null"));
        }
        NPVoxModel inputModel = ((NPVoxIModelFactory)Input).GetProduct();

        bool hasVoxelGroups = inputModel.HasVoxelGroups();

        if (AffectedArea.Equals(NPVoxBox.INVALID))
        {
            NPVoxModel model = NPVoxModel.NewInstance(inputModel, reuse);
            model.CopyOver(inputModel);
            return(model);
        }

        NPVoxBox clampedBox = inputModel.Clamp(AffectedArea);

        NPVoxModel transformedModel = null;

        transformedModel = NPVoxModel.NewInstance(inputModel, reuse);
        if (hasVoxelGroups)
        {
            transformedModel.InitVoxelGroups();
        }
        transformedModel.NumVoxelGroups = inputModel.NumVoxelGroups;
        transformedModel.NumVoxels      = inputModel.NumVoxels;
        transformedModel.Colortable     = inputModel.Colortable != null ? (Color32[])inputModel.Colortable.Clone() : null;
        transformedModel.Sockets        = inputModel.Sockets != null ? (NPVoxSocket[])inputModel.Sockets.Clone() : null;

        NPVoxBoneModel transformedBoneModel = transformedModel as NPVoxBoneModel;
        NPVoxBoneModel inputBoneModel       = inputModel as NPVoxBoneModel;
        bool           isBoneModel          = false;

        if (transformedBoneModel != null)
        {
            transformedBoneModel.AllBones = NPVoxBone.CloneBones(inputBoneModel.AllBones);
            isBoneModel = true;
        }

        byte brightenedColor = NPVoxModelUtils.FindUnusedColor(inputModel);

        if (brightenedColor == 0)
        {
            Debug.LogWarning("could not find a free color to brighten the model");
        }

        Color32 brightenColor32 = inputModel.Colortable[brightenedColor];

        foreach (NPVoxCoord coord in inputModel.EnumerateVoxels())
        {
            if (!isBoneModel)
            {
                if (clampedBox.Contains(coord) && brightenedColor != 0)
                {
                    brightenColor32 = inputModel.Colortable[inputModel.GetVoxel(coord)];
                    transformedModel.SetVoxel(coord, brightenedColor);
                }
                else
                {
                    transformedModel.SetVoxel(coord, inputModel.GetVoxel(coord));
                }
            }
            else
            {
                if (hiddenBonesMask == 0 || !inputBoneModel.IsInBoneMask(coord, hiddenBonesMask))
                {
                    if (clampedBox.Contains(coord) && brightenedColor != 0 && inputBoneModel.IsInBoneMask(coord, boneMask))
                    {
                        brightenColor32 = inputModel.Colortable[inputModel.GetVoxel(coord)];
                        transformedModel.SetVoxel(coord, brightenedColor);
                    }
                    else
                    {
                        transformedModel.SetVoxel(coord, inputModel.GetVoxel(coord));
                    }
                }
                transformedBoneModel.SetBoneMask(coord, inputBoneModel.GetBoneMask(coord));
            }

            if (hasVoxelGroups)
            {
                transformedModel.SetVoxelGroup(coord, inputModel.GetVoxelGroup(coord));
            }
        }

        if (brightenedColor != 0)
        {
            transformedModel.Colortable[brightenedColor] = NPVoxModelUtils.BrightenColor(brightenColor32);
        }


        transformedModel.RecalculateNumVoxels(true);
        return(transformedModel);
    }
예제 #29
0
 public void ChangeAffectedArea(NPVoxBox newBox)
 {
     this.AffectedArea = newBox;
 }
    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);
        }
    }