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);
            }
コード例 #2
0
            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 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));
                }
            }
コード例 #4
0
            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);
                 * }
                 */
            }