public static NPVoxModel TransformSocket(NPVoxModel sourceModel, string socketName, Matrix4x4 transformMatrix, NPVoxModel reuse = null)
    {
        NPVoxModel transformedModel = null;

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

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

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

        return(transformedModel);
    }
Example #2
0
    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 newModel = NPVoxModel.NewInstance(model, NPVoxCoord.ZERO, reuse);

        newModel.CopyOver(model);

        bool addVoxelGroups = addVoxelGroup || newModel.HasVoxelGroups();
        byte theVoxelGroup  = (byte)255;

        if (addVoxelGroups)
        {
            if (!newModel.HasVoxelGroups())
            {
                newModel.InitVoxelGroups();
                foreach (NPVoxCoord coord in newModel.EnumerateVoxels())
                {
                    newModel.SetVoxelGroup(coord, 0);
                }
                theVoxelGroup           = 1;
                newModel.NumVoxelGroups = 2;
            }
            else
            {
                theVoxelGroup = newModel.NumVoxelGroups;
                newModel.NumVoxelGroups++;
            }
        }

        Vector3 direction1 = rotation1 * Vector3.forward;
        Vector3 direction2 = rotation2 * Vector3.forward;

        bool[]    usedColors = NPVoxModelUtils.GetUsedColors(newModel);
        Color32[] colorTable = newModel.Colortable;

        Vector3 currentP1 = NPVoxCoordUtil.ToVector(startCoord1);
        Vector3 currentP2 = NPVoxCoordUtil.ToVector(startCoord2);

        for (int i = 0; i < numSteps; i++)
        {
            byte color = NPVoxModelUtils.FindUnusedColor(ref usedColors);
            colorTable[color] = Color32.Lerp(startColor, endColor, (float)i / (float)numSteps);
            NPVoxGeomUtil.DrawLine(newModel, currentP1, currentP2, color, theVoxelGroup);
            currentP1 += direction1 * stepSize1;
            currentP2 += direction2 * stepSize2;
        }
        newModel.Colortable = colorTable;


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

        return(TransformSocket(sourceModel, socketName, transformMatrix, reuse));
    }
Example #4
0
    override public Vector3 GetPivot()
    {
        NPVoxIModelFactory modelFactory = (Input as NPVoxIModelFactory);

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

        if (modelFactory != null)
        {
            NPVoxSocket socket = modelFactory.GetProduct().GetSocketByName(SocketName);
            this.PivotOffset = pivot - NPVoxCoordUtil.ToVector(socket.Anchor);
        }
        else
        {
            this.PivotOffset = Vector3.zero;
        }
    }
    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 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);
    }
Example #8
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);
    }
    public override void Process(NPVoxModel model, NPVoxMeshData tempdata, Vector3[] inNormals, ref Vector3[] outNormals)
    {
        // calculate normals based on present neighbour voxels
        Vector3 voxelNormal = Vector3.zero;

        if (!tempdata.isHidden)
        {
            foreach (NPVoxCoord offset in voxelNormalNeighbours.Enumerate())
            {
                NPVoxCoord checkCoord = tempdata.voxCoord + offset;
                checkCoord = model.LoopCoord(checkCoord, tempdata.loop);
                if (!model.HasVoxel(checkCoord))
                {
                    voxelNormal += NPVoxCoordUtil.ToVector(offset);
                }
            }
            voxelNormal.Normalize();
        }
        else
        {
            voxelNormal = tempdata.voxelCenter.normalized;
        }

        for (int t = 0; t < tempdata.numVertices; t++)
        {
            Vector3 normal = Vector3.zero;

            switch (m_normalMode)
            {
            case NPVoxNormalMode.VOXEL:
                normal = voxelNormal;

                normal = Vector3.zero;

                if (tempdata.vertexPositionOffsets[t].x < 0.0f)
                {
                    if (tempdata.hasLeft && !tempdata.hasForward && !tempdata.hasBack && !tempdata.hasUp && !tempdata.hasDown)
                    {
                        normal.x = -1;
                    }
                    else
                    {
                        normal.x = voxelNormal.x;
                    }
                }
                else if (tempdata.vertexPositionOffsets[t].x > 0.0f)
                {
                    if (tempdata.hasRight && !tempdata.hasForward && !tempdata.hasBack && !tempdata.hasUp && !tempdata.hasDown)
                    {
                        normal.x = 1;
                    }
                    else
                    {
                        normal.x = voxelNormal.x;
                    }
                }

                if (tempdata.vertexPositionOffsets[t].y < 0.0f)
                {
                    if (tempdata.hasUp && !tempdata.hasForward && !tempdata.hasBack && !tempdata.hasLeft && !tempdata.hasRight)
                    {
                        normal.y = -1;
                    }
                    else
                    {
                        normal.y = voxelNormal.y;
                    }
                }
                else if (tempdata.vertexPositionOffsets[t].y > 0.0f)
                {
                    if (tempdata.hasDown && !tempdata.hasForward && !tempdata.hasBack && !tempdata.hasLeft && !tempdata.hasRight)
                    {
                        normal.y = +1;
                    }
                    else
                    {
                        normal.y = voxelNormal.y;
                    }
                }

                if (tempdata.vertexPositionOffsets[t].z < 0.0f)
                {
                    if (tempdata.hasBack && !tempdata.hasLeft && !tempdata.hasRight && !tempdata.hasUp && !tempdata.hasDown)
                    {
                        normal.z = -1;
                    }
                    else
                    {
                        normal.z = voxelNormal.z;
                    }
                }
                else if (tempdata.vertexPositionOffsets[t].z > 0.0f)
                {
                    if (tempdata.hasForward && !tempdata.hasLeft && !tempdata.hasRight && !tempdata.hasUp && !tempdata.hasDown)
                    {
                        normal.z = +1;
                    }
                    else
                    {
                        normal.z = voxelNormal.z;
                    }
                }

                if (Mathf.Abs(normal.x) < 0.1f && Mathf.Abs(normal.y) < 0.1f && Mathf.Abs(normal.z) < 0.1f)
                {
                    // we would like to have full color when we are a stand-alone voxel, however there is no way to do so right now, so we just
                    // fallback to the centoid normal
                    normal = tempdata.voxelCenter;
                }

                normal.Normalize();
                break;

            case NPVoxNormalMode.SMOOTH:
                normal = Vector3.zero;

                for (float xx = -0.5f; xx < 1.0f; xx += 1f)
                {
                    for (float yy = -.5f; yy < 1; yy += 1)
                    {
                        for (float zz = -.5f; zz < 1; zz += 1)
                        {
                            sbyte xCoord = ( sbyte )Mathf.Round(tempdata.vertexPositionOffsets[t].x + xx);
                            sbyte yCoord = ( sbyte )Mathf.Round(tempdata.vertexPositionOffsets[t].y + yy);
                            sbyte zCoord = ( sbyte )Mathf.Round(tempdata.vertexPositionOffsets[t].z + zz);

                            if (!model.HasVoxel(tempdata.voxCoord + new NPVoxCoord(( sbyte )xCoord, ( sbyte )yCoord, ( sbyte )zCoord)))
                            {
                                normal += new Vector3(
                                    xx,
                                    yy,
                                    zz
                                    );
                            }
                        }
                    }
                }

                normal.Normalize();
                break;

            case NPVoxNormalMode.FORWARD: normal = Vector3.forward; break;

            case NPVoxNormalMode.BACK: normal = Vector3.back; break;

            case NPVoxNormalMode.UP: normal = Vector3.up; break;

            case NPVoxNormalMode.DOWN: normal = Vector3.down; break;

            case NPVoxNormalMode.LEFT: normal = Vector3.left; break;

            case NPVoxNormalMode.RIGHT: normal = Vector3.right; break;
            }
            outNormals[tempdata.vertexIndexOffsetBegin + t] = normal;
        }
    }
Example #10
0
    public static void CreateMesh(
        NPVoxModel model,
        Mesh mesh,
        Vector3 cubeSize,
        Vector3 NormalVariance,
        int NormalVarianceSeed         = 0,
        NPVoxOptimization optimization = NPVoxOptimization.OFF,
        NPVoxNormalMode NormalMode     = NPVoxNormalMode.SMOOTH,
        int BloodColorIndex            = 0,
        NPVoxFaces loop     = null,
        NPVoxFaces cutout   = null,
        NPVoxFaces include  = null,
        int MinVertexGroups = 1,
        NPVoxNormalMode[] NormalModePerVoxelGroup = null
        )
    {
        bool hasVoxelGroups   = model.HasVoxelGroups();
        var  vertices         = new Vector3[model.NumVoxels * 8];
        byte vertexGroupCount = model.NumVoxelGroups;
        var  triangles        = new int[vertexGroupCount, model.NumVoxels * 36];

        var normals  = new Vector3[model.NumVoxels * 8];
        var tangents = new Vector4[model.NumVoxels * 8];
        var colors   = new Color[model.NumVoxels * 8];

        int currentVertexIndex   = 0;
        var currentTriangleIndex = new int[vertexGroupCount];

        for (int i = 0; i < vertexGroupCount; i++)
        {
            currentTriangleIndex[i] = 0;
        }

        UnityEngine.Random.InitState(NormalVarianceSeed);

        if (loop == null)
        {
            loop = new NPVoxFaces();
        }

        if (include == null)
        {
            include = new NPVoxFaces(1, 1, 1, 1, 1, 1);
        }

        NPVoxBox voxelsToInclude = model.BoundingBox;
        Vector3  cutoutOffset    = Vector3.zero;

        if (cutout != null)
        {
            Vector3 originalCenter = voxelsToInclude.SaveCenter;
            voxelsToInclude.Left    = (sbyte)Mathf.Abs(cutout.Left);
            voxelsToInclude.Down    = (sbyte)Mathf.Abs(cutout.Down);
            voxelsToInclude.Back    = (sbyte)Mathf.Abs(cutout.Back);
            voxelsToInclude.Right   = (sbyte)(voxelsToInclude.Right - (sbyte)Mathf.Abs(cutout.Right));
            voxelsToInclude.Up      = (sbyte)(voxelsToInclude.Up - (sbyte)Mathf.Abs(cutout.Up));
            voxelsToInclude.Forward = (sbyte)(voxelsToInclude.Forward - (sbyte)Mathf.Abs(cutout.Forward));
            cutoutOffset            = Vector3.Scale(originalCenter - voxelsToInclude.SaveCenter, cubeSize);
        }

        NPVoxToUnity npVoxToUnity = new NPVoxToUnity(model, cubeSize);
        Vector3      size         = new Vector3(
            voxelsToInclude.Size.X * cubeSize.x,
            voxelsToInclude.Size.Y * cubeSize.y,
            voxelsToInclude.Size.Z * cubeSize.z
            );

        NPVoxBox voxelNormalNeighbours = new NPVoxBox(new NPVoxCoord(-1, -1, -1), new NPVoxCoord(1, 1, 1));

        NPVoxNormalMode normalMode = NormalMode;

        foreach (NPVoxCoord voxCoord in voxelsToInclude.Enumerate())
        {
            if (model.HasVoxel(voxCoord))
            {
                Vector3 voxelCenter = npVoxToUnity.ToUnityPosition(voxCoord) + cutoutOffset;

                int vertexGroupIndex = 0;
                if (hasVoxelGroups)
                {
                    vertexGroupIndex = model.GetVoxelGroup(voxCoord);
                }

                if (NormalModePerVoxelGroup != null && NormalModePerVoxelGroup.Length > vertexGroupIndex)
                {
                    normalMode = NormalModePerVoxelGroup[vertexGroupIndex];
                }
                else
                {
                    normalMode = NormalMode;
                }

                // do we have this side
                bool hasLeft    = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.LEFT, loop));
                bool hasRight   = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.RIGHT, loop));
                bool hasDown    = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.DOWN, loop));
                bool hasUp      = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.UP, loop));
                bool hasForward = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.FORWARD, loop));
                bool hasBack    = !model.HasVoxel(model.LoopCoord(voxCoord + NPVoxCoord.BACK, loop));

                // do we actually want to include this side in our mesh
                // NOTE: cutout < 0 means we still render the mesh even though it is cutout
                //       cutout > 0 means we don't render the mesh when cutout
                bool includeLeft    = (hasLeft || (cutout.Left < 0 && voxCoord.X == voxelsToInclude.Left)) && include.Left == 1;
                bool includeRight   = (hasRight || (cutout.Right < 0 && voxCoord.X == voxelsToInclude.Right)) && include.Right == 1;
                bool includeUp      = (hasUp || (cutout.Up < 0 && voxCoord.Y == voxelsToInclude.Up)) && include.Up == 1;
                bool includeDown    = (hasDown || (cutout.Down < 0 && voxCoord.Y == voxelsToInclude.Down)) && include.Down == 1;
                bool includeBack    = (hasBack || (cutout.Back < 0 && voxCoord.Z == voxelsToInclude.Back)) && include.Back == 1;
                bool includeForward = (hasForward || (cutout.Forward < 0 && voxCoord.Z == voxelsToInclude.Forward)) && include.Forward == 1;

                bool isHidden = !hasForward && !hasBack && !hasLeft && !hasRight && !hasUp && !hasDown;

                if (isHidden && optimization == NPVoxOptimization.PER_VOXEL)
                {
                    continue;
                }

                if (isHidden && BloodColorIndex > 0)
                {
                    model.SetVoxel(voxCoord, (byte)BloodColorIndex); // WTF WTF WTF?!? we should not modify the MODEL in here !!!!
                }

                Color color = model.GetColor(voxCoord);

                // prepare cube vertices
                int numVertices = 0;

                int[]     vertexIndexOffsets    = new int[8];
                Vector3[] vertexPositionOffsets = new Vector3[8];

                if (optimization != NPVoxOptimization.PER_FACE || includeBack || includeLeft || includeDown)
                {
                    vertexIndexOffsets[0] = numVertices++;
                    vertexPositionOffsets[vertexIndexOffsets[0]] = new Vector3(-0.5f, -0.5f, -0.5f);
                }
                if (optimization != NPVoxOptimization.PER_FACE || includeBack || includeRight || includeDown)
                {
                    vertexIndexOffsets[1] = numVertices++;
                    vertexPositionOffsets[vertexIndexOffsets[1]] = new Vector3(0.5f, -0.5f, -0.5f);
                }
                if (optimization != NPVoxOptimization.PER_FACE || includeBack || includeLeft || includeUp)
                {
                    vertexIndexOffsets[2] = numVertices++;
                    vertexPositionOffsets[vertexIndexOffsets[2]] = new Vector3(-0.5f, 0.5f, -0.5f);
                }
                if (optimization != NPVoxOptimization.PER_FACE || includeBack || includeRight || includeUp)
                {
                    vertexIndexOffsets[3] = numVertices++;
                    vertexPositionOffsets[vertexIndexOffsets[3]] = new Vector3(0.5f, 0.5f, -0.5f);
                }
                if (optimization != NPVoxOptimization.PER_FACE || includeForward || includeLeft || includeDown)
                {
                    vertexIndexOffsets[4] = numVertices++;
                    vertexPositionOffsets[vertexIndexOffsets[4]] = new Vector3(-0.5f, -0.5f, 0.5f);
                }
                if (optimization != NPVoxOptimization.PER_FACE || includeForward || includeRight || includeDown)
                {
                    vertexIndexOffsets[5] = numVertices++;
                    vertexPositionOffsets[vertexIndexOffsets[5]] = new Vector3(0.5f, -0.5f, 0.5f);
                }
                if (optimization != NPVoxOptimization.PER_FACE || includeForward || includeLeft || includeUp)
                {
                    vertexIndexOffsets[6] = numVertices++;
                    vertexPositionOffsets[vertexIndexOffsets[6]] = new Vector3(-0.5f, 0.5f, 0.5f);
                }
                if (optimization != NPVoxOptimization.PER_FACE || includeForward || includeRight || includeUp)
                {
                    vertexIndexOffsets[7] = numVertices++;
                    vertexPositionOffsets[vertexIndexOffsets[7]] = new Vector3(0.5f, 0.5f, 0.5f);
                }

                // add cube faces
                int i = currentTriangleIndex[vertexGroupIndex];

                // back
                if (optimization != NPVoxOptimization.PER_FACE || includeBack)
                {
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[0];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1];
                }

                // Forward
                if (optimization != NPVoxOptimization.PER_FACE || includeForward)
                {
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[7];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5];
                }

                // right
                if (optimization != NPVoxOptimization.PER_FACE || includeRight)
                {
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[7];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5];
                }

                // left
                if (optimization != NPVoxOptimization.PER_FACE || includeLeft)
                {
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[0];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6];
                }

                // up
                if (optimization != NPVoxOptimization.PER_FACE || includeUp)
                {
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[2];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[3];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[6];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[7];
                }

                // down
                if (optimization != NPVoxOptimization.PER_FACE || includeDown)
                {
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[0];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[1];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[5];
                    triangles[vertexGroupIndex, i++] = currentVertexIndex + vertexIndexOffsets[4];
                }

                // TODO create some kind of strategy pattern for the normal calculation, else this here is becomming a mess ...
                Vector3 variance = Vector3.zero;
                if (NormalVariance.x != 0 || NormalVariance.y != 0 || NormalVariance.z != 0)
                {
                    variance.x = -NormalVariance.x * 0.5f + 2 * UnityEngine.Random.value * NormalVariance.x;
                    variance.y = -NormalVariance.y * 0.5f + 2 * UnityEngine.Random.value * NormalVariance.y;
                    variance.z = -NormalVariance.z * 0.5f + 2 * UnityEngine.Random.value * NormalVariance.z;
                }

                // calculate normals based on present neighbour voxels
                Vector3 voxelNormal = Vector3.zero;
                if (!isHidden)
                {
                    foreach (NPVoxCoord offset in voxelNormalNeighbours.Enumerate())
                    {
                        NPVoxCoord checkCoord = voxCoord + offset;
                        checkCoord = model.LoopCoord(checkCoord, loop);
                        if (!model.HasVoxel(checkCoord))
                        {
                            voxelNormal += NPVoxCoordUtil.ToVector(offset);
                        }
                    }
                    voxelNormal.Normalize();
                }
                else
                {
                    voxelNormal = voxelCenter.normalized;
                }

                // Normals
                for (int t = 0; t < numVertices; t++)
                {
                    Vector3 normal = Vector3.zero;

                    switch (normalMode)
                    {
                    case NPVoxNormalMode.VOXEL:
                        normal = voxelNormal;

                        normal = Vector3.zero;

                        if (vertexPositionOffsets[t].x < 0.0f)
                        {
                            if (hasLeft && !hasForward && !hasBack && !hasUp && !hasDown)
                            {
                                normal.x = -1;
                            }
                            else
                            {
                                normal.x = voxelNormal.x;
                            }
                        }
                        else if (vertexPositionOffsets[t].x > 0.0f)
                        {
                            if (hasRight && !hasForward && !hasBack && !hasUp && !hasDown)
                            {
                                normal.x = 1;
                            }
                            else
                            {
                                normal.x = voxelNormal.x;
                            }
                        }

                        if (vertexPositionOffsets[t].y < 0.0f)
                        {
                            if (hasUp && !hasForward && !hasBack && !hasLeft && !hasRight)
                            {
                                normal.y = -1;
                            }
                            else
                            {
                                normal.y = voxelNormal.y;
                            }
                        }
                        else if (vertexPositionOffsets[t].y > 0.0f)
                        {
                            if (hasDown && !hasForward && !hasBack && !hasLeft && !hasRight)
                            {
                                normal.y = +1;
                            }
                            else
                            {
                                normal.y = voxelNormal.y;
                            }
                        }

                        if (vertexPositionOffsets[t].z < 0.0f)
                        {
                            if (hasBack && !hasLeft && !hasRight && !hasUp && !hasDown)
                            {
                                normal.z = -1;
                            }
                            else
                            {
                                normal.z = voxelNormal.z;
                            }
                        }
                        else if (vertexPositionOffsets[t].z > 0.0f)
                        {
                            if (hasForward && !hasLeft && !hasRight && !hasUp && !hasDown)
                            {
                                normal.z = +1;
                            }
                            else
                            {
                                normal.z = voxelNormal.z;
                            }
                        }

                        if (Mathf.Abs(normal.x) < 0.1f && Mathf.Abs(normal.y) < 0.1f && Mathf.Abs(normal.z) < 0.1f)
                        {
                            // we would like to have full color when we are a stand-alone voxel, however there is no way to do so right now, so we just
                            // fallback to the centoid normal
                            normal = voxelCenter;
                        }

                        normal.Normalize();
                        break;

                    case NPVoxNormalMode.SMOOTH:
                        normal = Vector3.zero;

                        for (float xx = -0.5f; xx < 1.0f; xx += 1f)
                        {
                            for (float yy = -.5f; yy < 1; yy += 1)
                            {
                                for (float zz = -.5f; zz < 1; zz += 1)
                                {
                                    sbyte xCoord = (sbyte)Mathf.Round(vertexPositionOffsets[t].x + xx);
                                    sbyte yCoord = (sbyte)Mathf.Round(vertexPositionOffsets[t].y + yy);
                                    sbyte zCoord = (sbyte)Mathf.Round(vertexPositionOffsets[t].z + zz);

                                    if (!model.HasVoxel(voxCoord + new NPVoxCoord((sbyte)xCoord, (sbyte)yCoord, (sbyte)zCoord)))
                                    {
                                        normal += new Vector3(
                                            xx,
                                            yy,
                                            zz
                                            );
                                    }
                                }
                            }
                        }

                        normal.Normalize();
                        break;

                    case NPVoxNormalMode.FORWARD: normal = Vector3.forward; break;

                    case NPVoxNormalMode.BACK: normal = Vector3.back; break;

                    case NPVoxNormalMode.UP: normal = Vector3.up; break;

                    case NPVoxNormalMode.DOWN: normal = Vector3.down; break;

                    case NPVoxNormalMode.LEFT: normal = Vector3.left; break;

                    case NPVoxNormalMode.RIGHT: normal = Vector3.right; break;
                    }

                    normals[currentVertexIndex + t] = (normal + variance).normalized;

                    // store voxel center for shader usage
                    Vector4 tangent = new Vector4();
                    tangent.x = voxelCenter.x;
                    tangent.y = voxelCenter.y;
                    tangent.z = voxelCenter.z;
                    // encode model size
                    tangent.w = ((voxelsToInclude.Size.X & 0x7F) << 14) | ((voxelsToInclude.Size.Y & 0x7F) << 7) | (voxelsToInclude.Size.Z & 0x7F);


                    tangents[currentVertexIndex + t] = tangent;
                }

                // UVs
                for (int t = 0; t < numVertices; t++)
                {
                    colors[currentVertexIndex + t] = color;
                }

                // translate & scale vertices to voxel position
                for (int t = 0; t < numVertices; t++)
                {
                    vertices[currentVertexIndex + t] = voxelCenter + Vector3.Scale(vertexPositionOffsets[t], cubeSize);
                }

                currentTriangleIndex[vertexGroupIndex] = i;
                currentVertexIndex += numVertices;
            }
        }

        // shrink arrays as needed
        if (optimization != NPVoxOptimization.OFF)
        {
            Array.Resize(ref vertices, currentVertexIndex);
            Array.Resize(ref normals, currentVertexIndex);
            Array.Resize(ref tangents, currentVertexIndex);
            Array.Resize(ref colors, currentVertexIndex);
        }

        mesh.vertices = vertices;
        if (hasVoxelGroups)
        {
            mesh.subMeshCount = Math.Max(vertexGroupCount, MinVertexGroups);
            for (int i = 0; i < vertexGroupCount; i++)
            {
                int   numberOfTrianglesForVertexGroup = currentTriangleIndex[i];
                int[] trianglesForVertexGroup         = new int[numberOfTrianglesForVertexGroup];
                for (int j = 0; j < numberOfTrianglesForVertexGroup; j++)
                {
                    trianglesForVertexGroup[j] = triangles[i, j];
                }
                mesh.SetTriangles(trianglesForVertexGroup, i);
            }
        }
        else
        {
            int   numberOfTrianglesForVertexGroup = currentTriangleIndex[0];
            int[] trianglesForVertexGroup         = new int[numberOfTrianglesForVertexGroup];
            Buffer.BlockCopy(triangles, 0,
                             trianglesForVertexGroup, 0,
                             numberOfTrianglesForVertexGroup * sizeof(int));

            if (MinVertexGroups < 2)
            {
                mesh.triangles = trianglesForVertexGroup;
            }
            else
            {
                mesh.subMeshCount = MinVertexGroups;
                mesh.SetTriangles(trianglesForVertexGroup, 0);
            }
        }



        mesh.normals  = normals;
        mesh.tangents = tangents;
        mesh.colors   = colors;
        mesh.bounds   = new Bounds(Vector3.zero, size);

        if (NormalMode == NPVoxNormalMode.AUTO)
        {
            mesh.RecalculateNormals();
        }
    }