Ejemplo n.º 1
0
        void ApplyBlendShapeFramesToMeshAndBuildMap()
        {
            if (MBVersion.GetMajorVersion() > 5 ||
                (MBVersion.GetMajorVersion() == 5 && MBVersion.GetMinorVersion() >= 3))
            {
                if (blendShapesInCombined.Length != blendShapes.Length)
                {
                    blendShapesInCombined = new MBBlendShape[blendShapes.Length];
                }
                Vector3[] targVerts = new UnityEngine.Vector3[verts.Length];
                Vector3[] targNorms = new UnityEngine.Vector3[verts.Length];
                Vector3[] targTans  = new UnityEngine.Vector3[verts.Length];

                ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = null;

                MBVersion.ClearBlendShapes(_mesh);
                for (int bsIdx = 0; bsIdx < blendShapes.Length; bsIdx++)
                {
                    MBBlendShape         blendShape = blendShapes[bsIdx];
                    MB_DynamicGameObject dgo        = instance2Combined_MapGet(blendShape.gameObject);
                    if (dgo != null)
                    {
                        int destIdx = dgo.vertIdx;
                        for (int frmIdx = 0; frmIdx < blendShape.frames.Length; frmIdx++)
                        {
                            MBBlendShapeFrame frame = blendShape.frames[frmIdx];
                            Array.Copy(frame.vertices, 0, targVerts, destIdx, frame.vertices.Length);
                            Array.Copy(frame.normals, 0, targNorms, destIdx, frame.normals.Length);
                            Array.Copy(frame.tangents, 0, targTans, destIdx, frame.tangents.Length);
                            MBVersion.AddBlendShapeFrame(_mesh, ConvertBlendShapeNameToOutputName(blendShape.name) + blendShape.gameObjectID, frame.frameWeight, targVerts, targNorms, targTans);
                            // We re-use these arrays restore them to zero
                            _ZeroArray(targVerts, destIdx, frame.vertices.Length);
                            _ZeroArray(targNorms, destIdx, frame.normals.Length);
                            _ZeroArray(targTans, destIdx, frame.tangents.Length);
                        }
                    }
                    else
                    {
                        Debug.LogError("InstanceID in blend shape that was not in instance2combinedMap");
                    }
                    blendShapesInCombined[bsIdx] = blendShape;
                }

                //this is necessary to get the renderer to refresh its data about the blendshapes.
                ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = null;
                ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = _mesh;

                // Add the map to the target renderer.
                if (settings.doBlendShapes)
                {
                    MB_BlendShape2CombinedMap mapComponent = _targetRenderer.GetComponent <MB_BlendShape2CombinedMap>();
                    if (mapComponent == null)
                    {
                        mapComponent = _targetRenderer.gameObject.AddComponent <MB_BlendShape2CombinedMap>();
                    }
                    SerializableSourceBlendShape2Combined map = mapComponent.GetMap();
                    BuildSrcShape2CombinedMap(map, blendShapes);
                }
            }
        }
            internal void CopyVertsNormsTansToBuffers(MB_DynamicGameObject dgo, MB_IMeshBakerSettings settings, int vertsIdx, Vector3[] nnorms, Vector4[] ntangs, Vector3[] nverts, Vector3[] normals, Vector4[] tangents, Vector3[] verts)
            {
                bool isMeshRenderer = dgo.gameObject.GetComponent <Renderer>() is MeshRenderer;

                if (settings.smrNoExtraBonesWhenCombiningMeshRenderers &&
                    isMeshRenderer &&
                    dgo._tmpSMR_CachedBones[0] != dgo.gameObject.transform // bone may not have a parent ancestor that is a bone
                    )
                {
                    // transform all the verticies, norms and tangents into the parent bone's local space (adjusted by the parent bone's bind pose).
                    // there should be only one bone and bind pose for a mesh renderer dgo.
                    // The bone and bind pose should be the parent-bone's NOT the MeshRenderers.
                    Matrix4x4 l2parentMat = dgo._tmpSMR_CachedBindposes[0].inverse * dgo._tmpSMR_CachedBones[0].worldToLocalMatrix * dgo.gameObject.transform.localToWorldMatrix;

                    // Similar to local2world but with translation removed and we are using the inverse transpose.
                    // We use this for normals and tangents because it handles scaling correctly.
                    Matrix4x4 l2parentRotScale = l2parentMat;
                    l2parentRotScale[0, 3] = l2parentRotScale[1, 3] = l2parentRotScale[2, 3] = 0f;
                    l2parentRotScale       = l2parentRotScale.inverse.transpose;

                    //can't modify the arrays we get from the cache because they will be modified multiple times if the same mesh is being added multiple times.
                    for (int j = 0; j < nverts.Length; j++)
                    {
                        int vIdx = vertsIdx + j;
                        verts[vertsIdx + j] = l2parentMat.MultiplyPoint3x4(nverts[j]);
                        if (settings.doNorm)
                        {
                            normals[vIdx] = l2parentRotScale.MultiplyPoint3x4(nnorms[j]).normalized;
                        }
                        if (settings.doTan)
                        {
                            float w = ntangs[j].w; //need to preserve the w value
                            tangents[vIdx]   = l2parentRotScale.MultiplyPoint3x4(((Vector3)ntangs[j])).normalized;
                            tangents[vIdx].w = w;
                        }
                    }
                }
                else
                {
                    if (settings.doNorm)
                    {
                        nnorms.CopyTo(normals, vertsIdx);
                    }
                    if (settings.doTan)
                    {
                        ntangs.CopyTo(tangents, vertsIdx);
                    }
                    nverts.CopyTo(verts, vertsIdx);
                }
            }
Ejemplo n.º 3
0
    bool _collectMaterialTriangles(Mesh m, MB_DynamicGameObject dgo, Material[] sharedMaterials, OrderedDictionary sourceMats2submeshIdx_map)
    {
        //everything here applies to the source object being added

        int numTriMeshes = m.subMeshCount;

        if (sharedMaterials.Length < numTriMeshes)
        {
            numTriMeshes = sharedMaterials.Length;
        }
        dgo._submeshTris      = new List <int> [numTriMeshes];
        dgo.targetSubmeshIdxs = new int[numTriMeshes];
        for (int i = 0; i < dgo._submeshTris.Length; i++)
        {
            dgo._submeshTris[i] = new List <int>();
        }
        for (int i = 0; i < numTriMeshes; i++)
        {
            if (doMultiMaterial)
            {
                if (!sourceMats2submeshIdx_map.Contains(sharedMaterials[i]))
                {
                    Debug.LogError("Object " + dgo.go + " has a material that was not found in the result materials maping. " + sharedMaterials[i]);
                    //todo might need to cleanup
                    return(false);
                }
                dgo.targetSubmeshIdxs[i] = (int)sourceMats2submeshIdx_map[sharedMaterials[i]];
            }
            else
            {
                dgo.targetSubmeshIdxs[i] = 0;
            }
            List <int> targTris = dgo._submeshTris[i];
            // add distinct triangles to master list
            int[] sourceTris = m.GetTriangles(i);
            for (int j = 0; j < sourceTris.Length; j++)
            {
                targTris.Add(sourceTris[j]);
            }
            if (VERBOSE)
            {
                Debug.Log("Collecting triangles for: " + dgo.go.name + " submesh:" + i + " maps to submesh:" + dgo.targetSubmeshIdxs[i] + " added:" + sourceTris.Length);
            }
        }
        return(true);
    }
 public void FindBonesToDelete(MB_DynamicGameObject dgo)
 {
     Debug.Assert(_didSetup);
     Debug.Assert(combiner.settings.renderType == MB_RenderType.skinnedMeshRenderer);
     // We could be working with adding and deleting smr body parts from the same rig. Different smrs will share
     // the same bones. Track if we need to delete a bone or not.
     for (int j = 0; j < dgo.indexesOfBonesUsed.Length; j++)
     {
         int idxOfUsedBone = dgo.indexesOfBonesUsed[j];
         List <MB_DynamicGameObject> dgosThatUseBone = boneIdx2dgoMap[idxOfUsedBone];
         if (dgosThatUseBone.Contains(dgo))
         {
             dgosThatUseBone.Remove(dgo);
             if (dgosThatUseBone.Count == 0)
             {
                 boneIdxsToDelete.Add(idxOfUsedBone);
             }
         }
     }
 }
Ejemplo n.º 5
0
    bool _collectOutOfBoundsUVRects(Mesh m, MB_DynamicGameObject dgo, Material[] sharedMaterials, OrderedDictionary sourceMats2submeshIdx_map)
    {
        int numResultMats = 1;

        if (doMultiMaterial)
        {
            numResultMats = resultMaterials.Length;
        }
        dgo.obUVRects = new Rect[numResultMats];
        for (int i = 0; i < dgo.obUVRects.Length; i++)
        {
            dgo.obUVRects[i] = new Rect(0f, 0f, 1f, 1f);
        }
        int numTriMeshes = m.subMeshCount;

        if (sharedMaterials.Length < numTriMeshes)
        {
            numTriMeshes = sharedMaterials.Length;
        }
        for (int i = 0; i < numTriMeshes; i++)
        {
            int combinedSubmeshIdx = 0;
            if (doMultiMaterial)
            {
                if (!sourceMats2submeshIdx_map.Contains(sharedMaterials[i]))
                {
                    Debug.LogError("Object " + dgo.go + " has a material in sharedMaterials that was not found in the material to rect map. " + sharedMaterials[i] + " numKeys " + sourceMats2submeshIdx_map.Keys.Count);
                    //todo might need to cleanup
                    return(false);
                }
                combinedSubmeshIdx = (int)sourceMats2submeshIdx_map[sharedMaterials[i]];
            }
            Rect r = new Rect();
            MB_Utility.hasOutOfBoundsUVs(m, ref r, combinedSubmeshIdx);
            dgo.obUVRects[dgo.targetSubmeshIdxs[i]] = r;
        }
        return(true);
    }
            public bool MapSharedMaterialsToAtlasRects(Material[] sharedMaterials,
                                                       bool checkTargetSubmeshIdxsFromPreviousBake,
                                                       Mesh m, MeshChannelsCache meshChannelsCache,
                                                       Dictionary <int, MB_Utility.MeshAnalysisResult[]> meshAnalysisResultsCache,
                                                       OrderedDictionary sourceMats2submeshIdx_map, GameObject go, MB_DynamicGameObject dgoOut)
            {
                MB_TextureTilingTreatment[] tilingTreatment = new MB_TextureTilingTreatment[sharedMaterials.Length];
                Rect[] uvRectsInAtlas       = new Rect[sharedMaterials.Length];
                Rect[] encapsulatingRect    = new Rect[sharedMaterials.Length];
                Rect[] sourceMaterialTiling = new Rect[sharedMaterials.Length];
                int[]  sliceIdx             = new int[sharedMaterials.Length];
                String errorMsg             = "";

                for (int srcSubmeshIdx = 0; srcSubmeshIdx < sharedMaterials.Length; srcSubmeshIdx++)
                {
                    System.Object subIdx = sourceMats2submeshIdx_map[sharedMaterials[srcSubmeshIdx]];
                    int           resMatIdx;
                    if (subIdx == null)
                    {
                        Debug.LogError("Source object " + go.name + " used a material " + sharedMaterials[srcSubmeshIdx] + " that was not in the baked materials.");
                        return(false);
                    }
                    else
                    {
                        resMatIdx = (int)subIdx;
                        if (checkTargetSubmeshIdxsFromPreviousBake)
                        {
                            /*
                             *  Possibilities:
                             *  Consider a mesh with three submeshes with materials A, B, C that map to
                             *  different submeshes in the combined mesh, AA,BB,CC. The user is updating the UVs on a
                             *  MeshRenderer so that object 'one' now uses material C => CC instead of A => AA. This will mean that the
                             *  triangle buffers will need to be resized. This is not allowed in UpdateGameObjects.
                             *  Must map to the same submesh that the old one mapped to.
                             */

                            if (resMatIdx != dgoOut.targetSubmeshIdxs[srcSubmeshIdx])
                            {
                                Debug.LogError(String.Format("Update failed for object {0}. Material {1} is mapped to a different submesh in the combined mesh than the previous material. This is not supported. Try using AddDelete.", go.name, sharedMaterials[srcSubmeshIdx]));
                                return(false);
                            }
                        }
                    }

                    if (!TryMapMaterialToUVRect(sharedMaterials[srcSubmeshIdx], m, srcSubmeshIdx, resMatIdx, meshChannelsCache, meshAnalysisResultsCache,
                                                out tilingTreatment[srcSubmeshIdx],
                                                out uvRectsInAtlas[srcSubmeshIdx],
                                                out encapsulatingRect[srcSubmeshIdx],
                                                out sourceMaterialTiling[srcSubmeshIdx],
                                                out sliceIdx[srcSubmeshIdx],
                                                ref errorMsg, LOG_LEVEL))
                    {
                        Debug.LogError(errorMsg);
                        return(false);
                    }
                }

                dgoOut.uvRects              = uvRectsInAtlas;
                dgoOut.encapsulatingRect    = encapsulatingRect;
                dgoOut.sourceMaterialTiling = sourceMaterialTiling;
                dgoOut.textureArraySliceIdx = sliceIdx;
                return(true);
            }
            public void _copyAndAdjustUVsFromMesh(MB2_TextureBakeResults tbr, MB_DynamicGameObject dgo, Mesh mesh, int uvChannel, int vertsIdx, Vector2[] uvsOut, float[] uvsSliceIdx, MeshChannelsCache meshChannelsCache)
            {
                Debug.Assert(dgo.sourceSharedMaterials != null && dgo.sourceSharedMaterials.Length == dgo.targetSubmeshIdxs.Length,
                             "sourceSharedMaterials array was a different size than the targetSubmeshIdxs. Was this old data that is being updated? " + dgo.sourceSharedMaterials.Length);
                Vector2[] nuvs = meshChannelsCache.GetUVChannel(uvChannel, mesh);

                int[] done = new int[nuvs.Length]; //use this to track uvs that have already been adjusted don't adjust twice
                for (int l = 0; l < done.Length; l++)
                {
                    done[l] = -1;
                }
                bool triangleArraysOverlap = false;

                //Rect uvRectInSrc = new Rect (0f,0f,1f,1f);
                //need to address the UVs through the submesh indexes because
                //each submesh has a different UV index
                bool doTextureArray = tbr.resultType == MB2_TextureBakeResults.ResultType.textureArray;

                for (int srcSubmeshIdx = 0; srcSubmeshIdx < dgo.targetSubmeshIdxs.Length; srcSubmeshIdx++)
                {
                    int[] srcSubTris;
                    if (dgo._tmpSubmeshTris != null)
                    {
                        srcSubTris = dgo._tmpSubmeshTris[srcSubmeshIdx].data;
                    }
                    else
                    {
                        srcSubTris = mesh.GetTriangles(srcSubmeshIdx);
                    }

                    float slice            = dgo.textureArraySliceIdx[srcSubmeshIdx];
                    int   resultSubmeshIdx = dgo.targetSubmeshIdxs[srcSubmeshIdx];

                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log(String.Format("Build UV transform for mesh {0} submesh {1} encapsulatingRect {2}",
                                                dgo.name, srcSubmeshIdx, dgo.encapsulatingRect[srcSubmeshIdx]));
                    }

                    bool considerUVs = textureBakeResults.GetConsiderMeshUVs(resultSubmeshIdx, dgo.sourceSharedMaterials[srcSubmeshIdx]);
                    Rect rr          = MB3_TextureCombinerMerging.BuildTransformMeshUV2AtlasRect(
                        considerUVs,
                        dgo.uvRects[srcSubmeshIdx],
                        dgo.obUVRects == null || dgo.obUVRects.Length == 0 ? new Rect(0, 0, 1, 1) : dgo.obUVRects[srcSubmeshIdx],
                        dgo.sourceMaterialTiling[srcSubmeshIdx],
                        dgo.encapsulatingRect[srcSubmeshIdx]);

                    for (int srcSubTriIdx = 0; srcSubTriIdx < srcSubTris.Length; srcSubTriIdx++)
                    {
                        int srcVertIdx = srcSubTris[srcSubTriIdx];
                        if (done[srcVertIdx] == -1)
                        {
                            done[srcVertIdx] = srcSubmeshIdx; //prevents a uv from being adjusted twice. Same vert can be on more than one submesh.
                            Vector2 nuv = nuvs[srcVertIdx];   //don't modify nuvs directly because it is cached and we might be re-using
                            //if (textureBakeResults.fixOutOfBoundsUVs) {
                            //uvRectInSrc can be larger than (out of bounds uvs) or smaller than 0..1
                            //this transforms the uvs so they fit inside the uvRectInSrc sample box

                            // scale, shift to fit in atlas rect
                            nuv.x = rr.x + nuv.x * rr.width;
                            nuv.y = rr.y + nuv.y * rr.height;
                            int idx = vertsIdx + srcVertIdx;
                            uvsOut[idx] = nuv;
                            if (doTextureArray)
                            {
                                uvsSliceIdx[idx] = slice;
                            }
                        }
                        if (done[srcVertIdx] != srcSubmeshIdx)
                        {
                            triangleArraysOverlap = true;
                        }
                    }
                }
                if (triangleArraysOverlap)
                {
                    if (LOG_LEVEL >= MB2_LogLevel.warn)
                    {
                        Debug.LogWarning(dgo.name + "has submeshes which share verticies. Adjusted uvs may not map correctly in combined atlas.");
                    }
                }

                if (LOG_LEVEL >= MB2_LogLevel.trace)
                {
                    Debug.Log(string.Format("_copyAndAdjustUVsFromMesh copied {0} verts", nuvs.Length));
                }
            }
Ejemplo n.º 8
0
    bool _addToCombined(GameObject[] goToAdd, GameObject[] goToDelete, bool disableRendererInSource)
    {
        if (goToAdd == null)
        {
            goToAdd = empty;
        }
        if (goToDelete == null)
        {
            goToDelete = empty;
        }
        if (_mesh == null)
        {
            _mesh = new Mesh();
        }
        if (mat2rect_map.Keys.Count == 0)
        {
            _initialize();
        }

        int numResultMats = 1;

        if (doMultiMaterial)
        {
            numResultMats = resultMaterials.Length;
        }

        if (VERBOSE)
        {
            Debug.Log("_addToCombined objs adding:" + goToAdd.Length + " objs deleting:" + goToDelete.Length + " fixOutOfBounds:" + fixOutOfBoundsUVs + " doMultiMaterial:" + doMultiMaterial);
        }

        OrderedDictionary sourceMats2submeshIdx_map = null;

        if (doMultiMaterial)
        {
            //build the sourceMats to submesh index map
            sourceMats2submeshIdx_map = new OrderedDictionary();
            for (int i = 0; i < numResultMats; i++)
            {
                MB_MultiMaterial mm = resultMaterials[i];
                for (int j = 0; j < mm.sourceMaterials.Count; j++)
                {
                    if (mm.sourceMaterials[j] == null)
                    {
                        Debug.LogError("Found null material in source materials for combined mesh materials " + i);
                        return(false);
                    }
                    if (!sourceMats2submeshIdx_map.Contains(mm.sourceMaterials[j]))
                    {
                        sourceMats2submeshIdx_map.Add(mm.sourceMaterials[j], i);
                    }
                }
            }
        }

        if (submeshTris.Length == 0)
        {
            submeshTris = new int[numResultMats][];
            for (int i = 0; i < submeshTris.Length; i++)
            {
                submeshTris[i] = new int[0];
            }
        }

        //calculate num to delete
        int totalDeleteVerts = 0;

//		int totalDeleteTris = 0;
        int[] totalDeleteSubmeshTris = new int[numResultMats];
        for (int i = 0; i < goToDelete.Length; i++)
        {
            MB_DynamicGameObject dgo;
            if (instance2combined_map.TryGetValue(goToDelete[i], out dgo))
            {
                totalDeleteVerts += dgo.numVerts;
//				totalDeleteTris += dgo.numTris;
                for (int j = 0; j < dgo.submeshNumTris.Length; j++)
                {
                    totalDeleteSubmeshTris[j] += dgo.submeshNumTris[j];
                }
            }
            else
            {
                Debug.LogWarning("Trying to delete an object that is not in combined mesh");
            }
        }

        //now add
        List <MB_DynamicGameObject> toAddDGOs = new List <MB_DynamicGameObject>();
        int totalAddVerts = 0;

//		int totalAddTris = 0;
        int[] totalAddSubmeshTris = new int[numResultMats];
        for (int i = 0; i < goToAdd.Length; i++)
        {
            if (!instance2combined_map.ContainsKey(goToAdd[i]))
            {
                MB_DynamicGameObject dgo = new MB_DynamicGameObject();

                GameObject go = goToAdd[i];

                Material[] sharedMaterials = MB_Utility.GetGOMaterials(go);

                if (sharedMaterials == null)
                {
                    Debug.LogError("Object " + go.name + " does not have a Renderer");
                    goToAdd[i] = null;
                    continue;
                }

                Mesh m = MB_Utility.GetMesh(go);
                if (m == null)
                {
                    Debug.LogError("Object " + go.name + " MeshFilter or SkinedMeshRenderer had no mesh");
                    goToAdd[i] = null;
                }

                Rect[] uvRects = new Rect[sharedMaterials.Length];
                for (int j = 0; j < sharedMaterials.Length; j++)
                {
                    if (!mat2rect_map.TryGetValue(sharedMaterials[j], out uvRects[j]))
                    {
                        Debug.LogError("Object " + go.name + " has an unknown material " + sharedMaterials[j] + ". Try baking textures");
                        goToAdd[i] = null;
                    }
                }
                if (goToAdd[i] != null)
                {
                    dgo.go         = goToAdd[i];
                    dgo.uvRects    = uvRects;
                    dgo.sharedMesh = m;
                    dgo.numVerts   = m.vertexCount;

                    if (!_collectMaterialTriangles(m, dgo, sharedMaterials, sourceMats2submeshIdx_map))
                    {
                        return(false);
                    }
                    dgo.submeshNumTris = new int[numResultMats];
                    dgo.submeshTriIdxs = new int[numResultMats];

                    if (fixOutOfBoundsUVs)
                    {
                        if (!_collectOutOfBoundsUVRects(m, dgo, sharedMaterials, sourceMats2submeshIdx_map))
                        {
                            return(false);
                        }
                    }
                    toAddDGOs.Add(dgo);
                    totalAddVerts += dgo.numVerts;
//					totalAddTris += dgo.numTris;

                    for (int j = 0; j < dgo._submeshTris.Length; j++)
                    {
                        totalAddSubmeshTris[dgo.targetSubmeshIdxs[j]] += dgo._submeshTris[j].Count;
                    }
                }
            }
            else
            {
                Debug.LogWarning("Object " + goToAdd[i].name + " has already been added to " + name);
                goToAdd[i] = null;
            }
        }

        for (int i = 0; i < goToAdd.Length; i++)
        {
            if (goToAdd[i] != null && disableRendererInSource)
            {
                MB_Utility.DisableRendererInSource(goToAdd[i]);
            }
        }

        int newVertSize = verts.Length + totalAddVerts - totalDeleteVerts;

//		int newTrisSize = tris.Length + totalAddTris - totalDeleteTris;
        int[] newSubmeshTrisSize = new int[numResultMats];
        if (VERBOSE)
        {
            Debug.Log("Verts adding:" + totalAddVerts + " deleting:" + totalDeleteVerts);
        }

        if (VERBOSE)
        {
            Debug.Log("Submeshes:" + newSubmeshTrisSize.Length);
        }
        for (int i = 0; i < newSubmeshTrisSize.Length; i++)
        {
            newSubmeshTrisSize[i] = submeshTris[i].Length + totalAddSubmeshTris[i] - totalDeleteSubmeshTris[i];
            if (VERBOSE)
            {
                Debug.Log("    submesh :" + i + " already contains:" + submeshTris[i].Length + " trisAdded:" + totalAddSubmeshTris[i] + " trisDeleted:" + totalDeleteSubmeshTris[i]);
            }
        }

        if (newVertSize > 65534)
        {
            Debug.LogError("Cannot add objects. Resulting mesh will have more than 64k vertices .");
            return(false);
        }

        Vector3[] nverts    = new Vector3[newVertSize];
        Vector3[] nnormals  = new Vector3[newVertSize];
        Vector4[] ntangents = new Vector4[newVertSize];
        Vector2[] nuvs      = new Vector2[newVertSize];
        Vector2[] nuv1s     = new Vector2[newVertSize];
        Vector2[] nuv2s     = new Vector2[newVertSize];
        Color[]   ncolors   = new Color[newVertSize];
//		int[] ntris = new int[newTrisSize];
        int[][] nsubmeshTris = null;

        nsubmeshTris = new int[numResultMats][];
        for (int i = 0; i < nsubmeshTris.Length; i++)
        {
            nsubmeshTris[i] = new int[newSubmeshTrisSize[i]];
        }

        for (int i = 0; i < goToDelete.Length; i++)
        {
            MB_DynamicGameObject dgo;
            if (instance2combined_map.TryGetValue(goToDelete[i], out dgo))
            {
                dgo._beingDeleted = true;
            }
        }

        objectsInCombinedMesh.Sort();

        //copy existing arrays to narrays gameobj by gameobj omitting deleted ones
        int targVidx = 0;

        int[] targSubmeshTidx       = new int[numResultMats];
        int   triangleIdxAdjustment = 0;

        for (int i = 0; i < objectsInCombinedMesh.Count; i++)
        {
            MB_DynamicGameObject dgo = objectsInCombinedMesh[i];
            if (!dgo._beingDeleted)
            {
                if (VERBOSE)
                {
                    Debug.Log("Copying obj in combined arrays idx:" + i);
                }
                Array.Copy(verts, dgo.vertIdx, nverts, targVidx, dgo.numVerts);
                Array.Copy(normals, dgo.vertIdx, nnormals, targVidx, dgo.numVerts);
                Array.Copy(tangents, dgo.vertIdx, ntangents, targVidx, dgo.numVerts);
                Array.Copy(uvs, dgo.vertIdx, nuvs, targVidx, dgo.numVerts);
                Array.Copy(uv1s, dgo.vertIdx, nuv1s, targVidx, dgo.numVerts);
                Array.Copy(uv2s, dgo.vertIdx, nuv2s, targVidx, dgo.numVerts);
                Array.Copy(colors, dgo.vertIdx, ncolors, targVidx, dgo.numVerts);

                //adjust triangles, then copy them over

                for (int subIdx = 0; subIdx < numResultMats; subIdx++)
                {
                    int[] sTris    = submeshTris[subIdx];
                    int   sTriIdx  = dgo.submeshTriIdxs[subIdx];
                    int   sNumTris = dgo.submeshNumTris[subIdx];
                    if (VERBOSE)
                    {
                        Debug.Log("    Adjusting submesh triangles submesh:" + subIdx + " startIdx:" + sTriIdx + " num:" + sNumTris);
                    }
                    for (int j = sTriIdx; j < sTriIdx + sNumTris; j++)
                    {
                        sTris[j] = sTris[j] - triangleIdxAdjustment;
                    }
                    Array.Copy(sTris, sTriIdx, nsubmeshTris[subIdx], targSubmeshTidx[subIdx], sNumTris);
                }



//				dgo.triIdx = targTidx;
                dgo.vertIdx = targVidx;
//				targTidx += dgo.numTris;

                for (int j = 0; j < targSubmeshTidx.Length; j++)
                {
                    dgo.submeshTriIdxs[j] = targSubmeshTidx[j];
                    targSubmeshTidx[j]   += dgo.submeshNumTris[j];
                }

                targVidx += dgo.numVerts;
            }
            else
            {
                if (VERBOSE)
                {
                    Debug.Log("Not copying obj: " + i);
                }
                triangleIdxAdjustment += dgo.numVerts;
            }
        }

        for (int i = objectsInCombinedMesh.Count - 1; i >= 0; i--)
        {
            if (objectsInCombinedMesh[i]._beingDeleted)
            {
                instance2combined_map.Remove(objectsInCombinedMesh[i].go);
                objectsInCombinedMesh.RemoveAt(i);
            }
        }

        verts    = nverts;
        normals  = nnormals;
        tangents = ntangents;
        uvs      = nuvs;
        uv1s     = nuv1s;
        uv2s     = nuv2s;
        colors   = ncolors;
//		tris = ntris;
        submeshTris = nsubmeshTris;

        //add new
        for (int i = 0; i < toAddDGOs.Count; i++)
        {
            MB_DynamicGameObject dgo = toAddDGOs[i];
            GameObject           go  = dgo.go;
            int vertsIdx             = targVidx;
//			int trisIdx = targTidx;

            Mesh       mesh   = dgo.sharedMesh;
            Matrix4x4  l2wMat = go.transform.localToWorldMatrix;
            Quaternion l2wQ   = go.transform.rotation;
            nverts = mesh.vertices;
            Vector3[] nnorms = mesh.normals;
            Vector4[] ntangs = mesh.tangents;
            for (int j = 0; j < nverts.Length; j++)
            {
                nverts[j] = l2wMat.MultiplyPoint(nverts[j]);
                nnorms[j] = l2wQ * nnorms[j];
                float w = ntangs[j].w;                 //need to preserve the w value
                ntangs[j]   = l2wQ * ntangs[j];
                ntangs[j].w = w;
            }

            int numTriSets = mesh.subMeshCount;
            if (dgo.uvRects.Length < numTriSets)
            {
                Debug.LogWarning("Mesh " + dgo.go.name + " has more submeshes than materials");
                numTriSets = dgo.uvRects.Length;
            }
            else if (dgo.uvRects.Length > numTriSets)
            {
                Debug.LogWarning("Mesh " + dgo.go.name + " has fewer submeshes than materials");
            }
            nuvs = mesh.uv;
            int[] done = new int[nuvs.Length];             //use this to track uvs that have already been adjusted don't adjust twice
            for (int l = 0; l < done.Length; l++)
            {
                done[l] = -1;
            }

            bool triangleArraysOverlap = false;
            Rect obUVRect = new Rect();
            for (int k = 0; k < dgo._submeshTris.Length; k++)
            {
                List <int> subTris = dgo._submeshTris[k];
                Rect       uvRect  = dgo.uvRects[k];
                if (fixOutOfBoundsUVs)
                {
                    obUVRect = dgo.obUVRects[dgo.targetSubmeshIdxs[k]];
                }
                for (int l = 0; l < subTris.Count; l++)
                {
                    int vidx = subTris[l];
                    if (done[vidx] == -1)
                    {
                        done[vidx] = k;                         //prevents a uv from being adjusted twice
                        if (fixOutOfBoundsUVs)
                        {
                            nuvs[vidx].x = nuvs[vidx].x / obUVRect.width - obUVRect.x / obUVRect.width;
                            nuvs[vidx].y = nuvs[vidx].y / obUVRect.height - obUVRect.y / obUVRect.height;
                        }
                        nuvs[vidx].x = uvRect.x + nuvs[vidx].x * uvRect.width;
                        nuvs[vidx].y = uvRect.y + nuvs[vidx].y * uvRect.height;
                    }
                    if (done[vidx] != k)
                    {
                        triangleArraysOverlap = true;
                    }
                }
            }
            if (triangleArraysOverlap)
            {
                Debug.LogWarning(dgo.go.name + "has submeshes which share verticies. Adjusted uvs may not map correctly in combined atlas.");
            }

            nverts.CopyTo(verts, vertsIdx);
            nnorms.CopyTo(normals, vertsIdx);
            ntangs.CopyTo(tangents, vertsIdx);
            nuvs.CopyTo(uvs, vertsIdx);
            mesh.uv1.CopyTo(uv1s, vertsIdx);
            mesh.uv2.CopyTo(uv2s, vertsIdx);
            mesh.colors.CopyTo(colors, vertsIdx);
//			ntris = mesh.triangles;
//			for (int j = 0; j < ntris.Length; j++){
//				ntris[j] = ntris[j] + vertsIdx;
//			}

            for (int combinedMeshIdx = 0; combinedMeshIdx < targSubmeshTidx.Length; combinedMeshIdx++)
            {
                dgo.submeshTriIdxs[combinedMeshIdx] = targSubmeshTidx[combinedMeshIdx];
            }
            for (int j = 0; j < dgo._submeshTris.Length; j++)
            {
                List <int> sts = dgo._submeshTris[j];
                for (int k = 0; k < sts.Count; k++)
                {
                    sts[k] = sts[k] + vertsIdx;
                }
                int combinedMeshIdx = dgo.targetSubmeshIdxs[j];
                sts.CopyTo(submeshTris[combinedMeshIdx], targSubmeshTidx[combinedMeshIdx]);
                dgo.submeshNumTris[combinedMeshIdx] += sts.Count;
                targSubmeshTidx[combinedMeshIdx]    += sts.Count;
            }

            dgo.vertIdx = targVidx;

            instance2combined_map.Add(go, dgo);
            objectsInCombinedMesh.Add(dgo);

            targVidx += nverts.Length;
            for (int j = 0; j < dgo._submeshTris.Length; j++)
            {
                dgo._submeshTris[j].Clear();
            }
            dgo._submeshTris = null;
            if (VERBOSE)
            {
                Debug.Log("Added to combined:" + dgo.go.name + " verts:" + nverts.Length);
            }
        }
        return(true);
    }
Ejemplo n.º 9
0
        void ApplyBlendShapeFramesToMeshAndBuildMap_MergeBlendShapesWithTheSameName()
        {
            if (MBVersion.GetMajorVersion() > 5 ||
                (MBVersion.GetMajorVersion() == 5 && MBVersion.GetMinorVersion() >= 3))
            {
                Vector3[] targVerts = new UnityEngine.Vector3[verts.Length];
                Vector3[] targNorms = new UnityEngine.Vector3[verts.Length];
                Vector3[] targTans  = new UnityEngine.Vector3[verts.Length];

                MBVersion.ClearBlendShapes(_mesh);

                // Group source that share the same blendShapeName
                bool numFramesError = false;
                Dictionary <string, List <MBBlendShape> > shapeName2objs = new Dictionary <string, List <MBBlendShape> >();
                {
                    for (int i = 0; i < blendShapes.Length; i++)
                    {
                        MBBlendShape        blendShape     = blendShapes[i];
                        string              blendShapeName = ConvertBlendShapeNameToOutputName(blendShape.name);
                        List <MBBlendShape> dgosUsingBlendShape;
                        if (!shapeName2objs.TryGetValue(blendShapeName, out dgosUsingBlendShape))
                        {
                            dgosUsingBlendShape = new List <MBBlendShape>();
                            shapeName2objs.Add(blendShapeName, dgosUsingBlendShape);
                        }

                        dgosUsingBlendShape.Add(blendShape);
                        if (dgosUsingBlendShape.Count > 1)
                        {
                            if (dgosUsingBlendShape[0].frames.Length != blendShape.frames.Length)
                            {
                                Debug.LogError("BlendShapes with the same name must have the same number of frames.");
                                numFramesError = true;
                            }
                        }
                    }
                }

                if (numFramesError)
                {
                    return;
                }

                if (blendShapesInCombined.Length != blendShapes.Length)
                {
                    blendShapesInCombined = new MBBlendShape[shapeName2objs.Keys.Count];
                }

                int bsInCombinedIdx = 0;
                foreach (string shapeName in shapeName2objs.Keys)
                {
                    List <MBBlendShape> groupOfSrcObjs  = shapeName2objs[shapeName];
                    MBBlendShape        firstBlendShape = groupOfSrcObjs[0];
                    int    numFrames        = firstBlendShape.frames.Length;
                    int    db_numVertsAdded = 0;
                    int    db_numObjsAdded  = 0;
                    string db_vIdx          = "";

                    for (int frmIdx = 0; frmIdx < numFrames; frmIdx++)
                    {
                        float firstFrameWeight = firstBlendShape.frames[frmIdx].frameWeight;

                        for (int dgoIdx = 0; dgoIdx < groupOfSrcObjs.Count; dgoIdx++)
                        {
                            MBBlendShape         blendShape = groupOfSrcObjs[dgoIdx];
                            MB_DynamicGameObject dgo        = instance2Combined_MapGet(blendShape.gameObject);
                            int destIdx = dgo.vertIdx;
                            Debug.Assert(blendShape.frames.Length == numFrames);
                            MBBlendShapeFrame frame = blendShape.frames[frmIdx];
                            Debug.Assert(frame.frameWeight == firstFrameWeight);
                            Array.Copy(frame.vertices, 0, targVerts, destIdx, frame.vertices.Length);
                            Array.Copy(frame.normals, 0, targNorms, destIdx, frame.normals.Length);
                            Array.Copy(frame.tangents, 0, targTans, destIdx, frame.tangents.Length);
                            if (frmIdx == 0)
                            {
                                db_numVertsAdded += frame.vertices.Length;
                                db_vIdx          += blendShape.gameObject.name + " " + destIdx + ":" + (destIdx + frame.vertices.Length) + ", ";
                            }
                        }

                        db_numObjsAdded += groupOfSrcObjs.Count;
                        MBVersion.AddBlendShapeFrame(_mesh, shapeName, firstFrameWeight, targVerts, targNorms, targTans);

                        // We re-use these arrays restore them to zero
                        _ZeroArray(targVerts, 0, targVerts.Length);
                        _ZeroArray(targNorms, 0, targNorms.Length);
                        _ZeroArray(targTans, 0, targTans.Length);
                    }

                    blendShapesInCombined[bsInCombinedIdx] = firstBlendShape;
                    bsInCombinedIdx++;
                }



                //this is necessary to get the renderer to refresh its data about the blendshapes.
                ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = null;
                ((SkinnedMeshRenderer)_targetRenderer).sharedMesh = _mesh;

                // Add the map to the target renderer.
                if (settings.doBlendShapes)
                {
                    MB_BlendShape2CombinedMap mapComponent = _targetRenderer.GetComponent <MB_BlendShape2CombinedMap>();
                    if (mapComponent == null)
                    {
                        mapComponent = _targetRenderer.gameObject.AddComponent <MB_BlendShape2CombinedMap>();
                    }
                    SerializableSourceBlendShape2Combined map = mapComponent.GetMap();
                    BuildSrcShape2CombinedMap(map, blendShapesInCombined);
                }
            }
        }
            public bool CollectBonesToAddForDGO(MB_DynamicGameObject dgo, Renderer r, bool noExtraBonesForMeshRenderers, MeshChannelsCache meshChannelCache)
            {
                bool success = true;

                Debug.Assert(_didSetup, "Need to setup first.");
                Debug.Assert(combiner.settings.renderType == MB_RenderType.skinnedMeshRenderer);
                // We could be working with adding and deleting smr body parts from the same rig. Different smrs will share
                // the same bones.

                //cache the bone data that we will be adding.
                Matrix4x4[]  dgoBindPoses   = dgo._tmpSMR_CachedBindposes = meshChannelCache.GetBindposes(r, out dgo.isSkinnedMeshWithBones);
                BoneWeight[] dgoBoneWeights = dgo._tmpSMR_CachedBoneWeights = meshChannelCache.GetBoneWeights(r, dgo.numVerts, dgo.isSkinnedMeshWithBones);
                Transform[]  dgoBones       = dgo._tmpSMR_CachedBones = combiner._getBones(r, dgo.isSkinnedMeshWithBones);


                for (int i = 0; i < dgoBones.Length; i++)
                {
                    if (dgoBones[i] == null)
                    {
                        Debug.LogError("Source mesh r had a 'null' bone. Bones must not be null: " + r);
                        success = false;
                    }
                }

                if (!success)
                {
                    return(success);
                }

                if (noExtraBonesForMeshRenderers)
                {
                    if (MB_Utility.GetRenderer(dgo.gameObject) is MeshRenderer)
                    {
                        // We are visiting a single dgo which is a MeshRenderer.
                        // It may be the child decendant of a bone in another skinned mesh that is being baked or is already in the combined mesh. We need to find that bone if it exists.
                        // We need to check our parent ancestors and search the bone lists of the other dgos being added or previously baked looking for bones that may have been added
                        Debug.Assert(dgoBones.Length == 1 && dgoBindPoses.Length == 1);
                        //     find and cache the parent bone for this MeshRenderer (it may not be the transform.parent)
                        bool            foundBoneParent = false;
                        BoneAndBindpose boneParent      = new BoneAndBindpose();
                        {
                            Transform t = dgo.gameObject.transform.parent;
                            while (t != null)
                            {
                                // Look for parent peviously baked in the combined mesh.
                                foreach (BoneAndBindpose b in boneAndBindPose2idx.Keys)
                                {
                                    if (b.bone == t)
                                    {
                                        boneParent      = b;
                                        foundBoneParent = true;
                                        break;
                                    }
                                }

                                // Look for parent in something we are adding.
                                foreach (BoneAndBindpose b in bonesToAdd)
                                {
                                    if (b.bone == t)
                                    {
                                        boneParent      = b;
                                        foundBoneParent = true;
                                        break;
                                    }
                                }

                                if (foundBoneParent)
                                {
                                    break;
                                }
                                else
                                {
                                    t = t.parent;
                                }
                            }
                        }

                        if (foundBoneParent)
                        {
                            dgoBones[0]     = boneParent.bone;
                            dgoBindPoses[0] = boneParent.bindPose;
                        }
                    }
                }

                // The mesh being added may not use all bones on the rig. Find the bones actually used.
                int[] usedBoneIdx2srcMeshBoneIdx;
                {
                    /*
                     * HashSet<int> usedBones = new HashSet<int>();
                     * for (int j = 0; j < dgoBoneWeights.Length; j++)
                     * {
                     *  usedBones.Add(dgoBoneWeights[j].boneIndex0);
                     *  usedBones.Add(dgoBoneWeights[j].boneIndex1);
                     *  usedBones.Add(dgoBoneWeights[j].boneIndex2);
                     *  usedBones.Add(dgoBoneWeights[j].boneIndex3);
                     * }
                     *
                     * usedBoneIdx2srcMeshBoneIdx = new int[usedBones.Count];
                     * usedBones.CopyTo(usedBoneIdx2srcMeshBoneIdx);
                     */
                }

                {
                    usedBoneIdx2srcMeshBoneIdx = new int[dgoBones.Length];
                    for (int i = 0; i < usedBoneIdx2srcMeshBoneIdx.Length; i++)
                    {
                        usedBoneIdx2srcMeshBoneIdx[i] = i;
                    }
                }

                // For each bone see if it exists in the bones array (with the same bindpose.).
                // We might be baking several skinned meshes on the same rig. We don't want duplicate bones in the bones array.
                for (int i = 0; i < dgoBones.Length; i++)
                {
                    bool            foundInBonesList = false;
                    int             bidx;
                    int             dgoBoneIdx = usedBoneIdx2srcMeshBoneIdx[i];
                    BoneAndBindpose bb         = new BoneAndBindpose(dgoBones[dgoBoneIdx], dgoBindPoses[dgoBoneIdx]);
                    if (boneAndBindPose2idx.TryGetValue(bb, out bidx))
                    {
                        if (dgoBones[dgoBoneIdx] == combiner.bones[bidx] &&
                            !boneIdxsToDelete.Contains(bidx) &&
                            dgoBindPoses[dgoBoneIdx] == combiner.bindPoses[bidx])
                        {
                            foundInBonesList = true;
                        }
                    }

                    if (!foundInBonesList)
                    {
                        if (!bonesToAdd.Contains(bb))
                        {
                            bonesToAdd.Add(bb);
                        }
                    }
                }

                dgo._tmpSMRIndexesOfSourceBonesUsed = usedBoneIdx2srcMeshBoneIdx;
                return(success);
            }
            public static void AddBonesToNewBonesArrayAndAdjustBWIndexes(MB3_MeshCombinerSingle combiner, MB_DynamicGameObject dgo, Renderer r, int vertsIdx,
                                                                         Transform[] nbones, BoneWeight[] nboneWeights, MeshChannelsCache meshChannelCache)
            {
                Transform[]  dgoBones                  = dgo._tmpSMR_CachedBones;
                Matrix4x4[]  dgoBindPoses              = dgo._tmpSMR_CachedBindposes;
                BoneWeight[] dgoBoneWeights            = dgo._tmpSMR_CachedBoneWeights;
                int[]        srcIndex2combinedIndexMap = new int[dgoBones.Length];
                for (int j = 0; j < dgo._tmpSMRIndexesOfSourceBonesUsed.Length; j++)
                {
                    int dgoBoneIdx = dgo._tmpSMRIndexesOfSourceBonesUsed[j];

                    for (int k = 0; k < nbones.Length; k++)
                    {
                        if (dgoBones[dgoBoneIdx] == nbones[k])
                        {
                            if (dgoBindPoses[dgoBoneIdx] == combiner.bindPoses[k])
                            {
                                srcIndex2combinedIndexMap[dgoBoneIdx] = k;
                                break;
                            }
                        }
                    }
                }

                //remap the bone weights for this dgo
                //build a list of usedBones, can't trust dgoBones because it contains all bones in the rig
                for (int j = 0; j < dgoBoneWeights.Length; j++)
                {
                    int newVertIdx = vertsIdx + j;
                    nboneWeights[newVertIdx].boneIndex0 = srcIndex2combinedIndexMap[dgoBoneWeights[j].boneIndex0];
                    nboneWeights[newVertIdx].boneIndex1 = srcIndex2combinedIndexMap[dgoBoneWeights[j].boneIndex1];
                    nboneWeights[newVertIdx].boneIndex2 = srcIndex2combinedIndexMap[dgoBoneWeights[j].boneIndex2];
                    nboneWeights[newVertIdx].boneIndex3 = srcIndex2combinedIndexMap[dgoBoneWeights[j].boneIndex3];
                    nboneWeights[newVertIdx].weight0    = dgoBoneWeights[j].weight0;
                    nboneWeights[newVertIdx].weight1    = dgoBoneWeights[j].weight1;
                    nboneWeights[newVertIdx].weight2    = dgoBoneWeights[j].weight2;
                    nboneWeights[newVertIdx].weight3    = dgoBoneWeights[j].weight3;
                }

                // repurposing the _tmpIndexesOfSourceBonesUsed since
                //we don't need it anymore and this saves a memory allocation . remap the indexes that point to source bones to combined bones.
                for (int j = 0; j < dgo._tmpSMRIndexesOfSourceBonesUsed.Length; j++)
                {
                    dgo._tmpSMRIndexesOfSourceBonesUsed[j] = srcIndex2combinedIndexMap[dgo._tmpSMRIndexesOfSourceBonesUsed[j]];
                }
                dgo.indexesOfBonesUsed = dgo._tmpSMRIndexesOfSourceBonesUsed;
                dgo._tmpSMRIndexesOfSourceBonesUsed = null;
                dgo._tmpSMR_CachedBones             = null;
                dgo._tmpSMR_CachedBindposes         = null;
                dgo._tmpSMR_CachedBoneWeights       = null;

                //check original bones and bindPoses

                /*
                 * for (int j = 0; j < dgo.indexesOfBonesUsed.Length; j++) {
                 *  Transform bone = bones[dgo.indexesOfBonesUsed[j]];
                 *  Matrix4x4 bindpose = bindPoses[dgo.indexesOfBonesUsed[j]];
                 *  bool found = false;
                 *  for (int k = 0; k < dgo._originalBones.Length; k++) {
                 *      if (dgo._originalBones[k] == bone && dgo._originalBindPoses[k] == bindpose) {
                 *          found = true;
                 *      }
                 *  }
                 *  if (!found) Debug.LogError("A Mismatch between original bones and bones array. " + dgo.name);
                 * }
                 */
            }
            public void CopyBonesWeAreKeepingToNewBonesArrayAndAdjustBWIndexes(Transform[] nbones, Matrix4x4[] nbindPoses, BoneWeight[] nboneWeights, int totalDeleteVerts)
            {
                // bones are copied separately because some dgos share bones
                if (boneIdxsToDelete.Count > 0)
                {
                    int[] boneIdxsToDel = new int[boneIdxsToDelete.Count];
                    boneIdxsToDelete.CopyTo(boneIdxsToDel);
                    Array.Sort(boneIdxsToDel);
                    //bones are being moved in bones array so need to do some remapping
                    int[] oldBonesIndex2newBonesIndexMap = new int[combiner.bones.Length];
                    int   newIdx            = 0;
                    int   indexInDeleteList = 0;

                    //bones were deleted so we need to rebuild bones and bind poses
                    //and build a map of old bone indexes to new bone indexes
                    //do this by copying old to new skipping ones we are deleting
                    for (int i = 0; i < combiner.bones.Length; i++)
                    {
                        if (indexInDeleteList < boneIdxsToDel.Length &&
                            boneIdxsToDel[indexInDeleteList] == i)
                        {
                            //we are deleting this bone so skip its index
                            indexInDeleteList++;
                            oldBonesIndex2newBonesIndexMap[i] = -1;
                        }
                        else
                        {
                            oldBonesIndex2newBonesIndexMap[i] = newIdx;
                            nbones[newIdx]     = combiner.bones[i];
                            nbindPoses[newIdx] = combiner.bindPoses[i];
                            newIdx++;
                        }
                    }
                    //adjust the indexes on the boneWeights
                    int numVertKeeping = combiner.boneWeights.Length - totalDeleteVerts;
                    {
                        for (int i = 0; i < numVertKeeping; i++)
                        {
                            BoneWeight bw = nboneWeights[i];
                            bw.boneIndex0   = oldBonesIndex2newBonesIndexMap[bw.boneIndex0];
                            bw.boneIndex1   = oldBonesIndex2newBonesIndexMap[bw.boneIndex1];
                            bw.boneIndex2   = oldBonesIndex2newBonesIndexMap[bw.boneIndex2];
                            bw.boneIndex3   = oldBonesIndex2newBonesIndexMap[bw.boneIndex3];
                            nboneWeights[i] = bw;
                        }
                    }

                    /*
                     * unsafe
                     * {
                     *  fixed (BoneWeight* boneWeightFirstPtr = &nboneWeights[0])
                     *  {
                     *      BoneWeight* boneWeightPtr = boneWeightFirstPtr;
                     *      for (int i = 0; i < numVertKeeping; i++)
                     *      {
                     *          boneWeightPtr->boneIndex0 = oldBonesIndex2newBonesIndexMap[boneWeightPtr->boneIndex0];
                     *          boneWeightPtr->boneIndex1 = oldBonesIndex2newBonesIndexMap[boneWeightPtr->boneIndex1];
                     *          boneWeightPtr->boneIndex2 = oldBonesIndex2newBonesIndexMap[boneWeightPtr->boneIndex2];
                     *          boneWeightPtr->boneIndex3 = oldBonesIndex2newBonesIndexMap[boneWeightPtr->boneIndex3];
                     *          boneWeightPtr++;
                     *      }
                     *  }
                     * }
                     */

                    //adjust the bone indexes on the dgos from old to new
                    for (int i = 0; i < combiner.mbDynamicObjectsInCombinedMesh.Count; i++)
                    {
                        MB_DynamicGameObject dgo = combiner.mbDynamicObjectsInCombinedMesh[i];
                        for (int j = 0; j < dgo.indexesOfBonesUsed.Length; j++)
                        {
                            dgo.indexesOfBonesUsed[j] = oldBonesIndex2newBonesIndexMap[dgo.indexesOfBonesUsed[j]];
                        }
                    }
                }
                else
                { //no bones are moving so can simply copy bones from old to new
                    Array.Copy(combiner.bones, nbones, combiner.bones.Length);
                    Array.Copy(combiner.bindPoses, nbindPoses, combiner.bindPoses.Length);
                }
            }