예제 #1
0
        private GameObject ImportSubObject(GameObject parentObj, DataSet.ObjectData objData, Dictionary <string, Material> mats)
        {
            bool       conv2sided = buildOptions != null && buildOptions.convertToDoubleSided;
            GameObject go         = new GameObject();

            go.name = objData.name;
            int count = 0;

            if (parentObj.transform)
            {
                while (parentObj.transform.Find(go.name))
                {
                    count++;
                    go.name = objData.name + count;
                }
            }
            go.transform.SetParent(parentObj.transform, false);

            if (objData.allFaces.Count == 0)
            {
                throw new InvalidOperationException("Failed to parse vertex and uv data. It might be that the file is corrupt or is not a valid wavefront OBJ file.");

                //Debug.LogWarning("Sub object: " + objData.name + " has no face defined. Creating empty game object.");

                //return go;
            }

            //Debug.Log( "Importing sub object:" + objData.Name );

            // count vertices needed for all the faces and map face indices to new vertices
            Dictionary <string, int> vIdxCount = new Dictionary <string, int>();
            int vcount = 0;

            foreach (DataSet.FaceIndices fi in objData.allFaces)
            {
                string key = DataSet.GetFaceIndicesKey(fi);
                int    idx;
                // avoid duplicates
                if (!vIdxCount.TryGetValue(key, out idx))
                {
                    vIdxCount.Add(key, vcount);
                    vcount++;
                }
            }

            int arraySize = conv2sided ? vcount * 2 : vcount;

            Vector3[] newVertices = new Vector3[arraySize];
            Vector2[] newUVs      = new Vector2[arraySize];
            Vector3[] newNormals  = new Vector3[arraySize];
            Color32[] newColors   = new Color32[arraySize];

            bool hasColors = currDataSet.colorList.Count > 0;

            foreach (DataSet.FaceIndices fi in objData.allFaces)
            {
                string key = DataSet.GetFaceIndicesKey(fi);
                int    k   = vIdxCount[key];
                newVertices[k] = currDataSet.vertList[fi.vertIdx];
                if (conv2sided)
                {
                    newVertices[vcount + k] = newVertices[k];
                }
                if (hasColors)
                {
                    newColors[k] = currDataSet.colorList[fi.vertIdx];
                    if (conv2sided)
                    {
                        newColors[vcount + k] = newColors[k];
                    }
                }
                if (currDataSet.uvList.Count > 0)
                {
                    newUVs[k] = currDataSet.uvList[fi.uvIdx];
                    if (conv2sided)
                    {
                        newUVs[vcount + k] = newUVs[k];
                    }
                }
                if (currDataSet.normalList.Count > 0 && fi.normIdx >= 0)
                {
                    newNormals[k] = currDataSet.normalList[fi.normIdx];
                    if (conv2sided)
                    {
                        newNormals[vcount + k] = -newNormals[k];
                    }
                }
            }

            bool objectHasNormals = (currDataSet.normalList.Count > 0 && objData.hasNormals);
            bool objectHasColors  = (currDataSet.colorList.Count > 0 && objData.hasColors);
            bool objectHasUVs     = (currDataSet.uvList.Count > 0);

            int n = objData.faceGroups[0].faces.Count;

            int numIndices = conv2sided ? n * 2 : n;

            MeshFilter meshFilter = go.AddComponent <MeshFilter>();

            go.AddComponent <MeshRenderer>();

            Mesh mesh = new Mesh();

#if UNITY_2017_3_OR_NEWER
            if (Using32bitIndices())
            {
                if (arraySize > MAX_VERT_COUNT || numIndices > MAX_INDICES_LIMIT_FOR_A_MESH)
                {
                    mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                }
            }
#endif
            mesh.name             = go.name;
            meshFilter.sharedMesh = mesh;

            mesh.vertices = newVertices;
            if (objectHasUVs)
            {
                mesh.uv = newUVs;
            }
            if (objectHasNormals)
            {
                mesh.normals = newNormals;
            }
            if (objectHasColors)
            {
                mesh.colors32 = newColors;
            }

            Material material;

            string   matName  = (objData.faceGroups[0].materialName != null) ? objData.faceGroups[0].materialName : "default";
            Renderer renderer = go.GetComponent <Renderer>();

            if (mats.ContainsKey(matName))
            {
                material = mats[matName];
                renderer.sharedMaterial = material;
#if UNITY_5_6_OR_NEWER
                RendererExtensions.UpdateGIMaterials(renderer);
#else
                DynamicGI.UpdateMaterials(renderer);
#endif
            }
            else
            {
                if (mats.ContainsKey("default"))
                {
                    material = mats["default"];
                    renderer.sharedMaterial = material;
                    Debug.LogWarning("Material: " + matName + " not found. Using the default material.");
                }
                else
                {
                    Debug.LogError("Material: " + matName + " not found.");
                }
            }

            int[] indices = new int[numIndices];

            for (int s = 0; s < n; s++)
            {
                DataSet.FaceIndices fi = objData.faceGroups[0].faces[s];
                string key             = DataSet.GetFaceIndicesKey(fi);
                indices[s] = vIdxCount[key];
            }
            if (conv2sided)
            {
                for (int s = 0; s < n; s++)
                {
                    indices[s + n] = vcount + indices[s / 3 * 3 + 2 - s % 3];
                }
            }

            mesh.SetTriangles(indices, 0);


            if (!objectHasNormals)
            {
                mesh.RecalculateNormals();
            }
            if (objectHasUVs)
            {
                Solve(mesh);
            }
            if (buildOptions != null && buildOptions.buildColliders)
            {
#if UNITY_2018_3_OR_NEWER
                BuildMeshCollider(go, buildOptions.colliderConvex, buildOptions.colliderTrigger);
#else
                BuildMeshCollider(go, buildOptions.colliderConvex, buildOptions.colliderTrigger, buildOptions.colliderInflate, buildOptions.colliderSkinWidth);
#endif
            }
            return(go);
        }
예제 #2
0
        /// <summary>
        /// Build an object once at a time, to be reiterated until false is returned.
        /// </summary>
        /// <param name="parentObj">Game object to which the new objects will be attached</param>
        /// <param name="mats">Materials from the previously loaded library</param>
        /// <returns>Return true until no more objects can be added, then false.</returns>
        protected bool BuildNextObject(GameObject parentObj, Dictionary <string, Material> mats)
        {
            // if all the objects were built stop here
            if (buildStatus.objCount >= currDataSet.objectList.Count)
            {
                return(false);
            }

            // get the next object in the list
            DataSet.ObjectData objData = currDataSet.objectList[buildStatus.objCount];

            if (buildStatus.newObject)
            {
                if (buildStatus.objCount == 0 && objData.name == "default")
                {
                    buildStatus.currObjGameObject = parentObj;
                }
                else
                {
                    buildStatus.currObjGameObject = new GameObject();
                    buildStatus.currObjGameObject.transform.parent = parentObj.transform;
                    buildStatus.currObjGameObject.name             = objData.name;
                    // restore the scale if the parent was rescaled
                    buildStatus.currObjGameObject.transform.localScale = Vector3.one;
                }
                buildStatus.subObjParent = buildStatus.currObjGameObject;

                //if (od.Name != "default") go.name = od.Name;
                //Debug.Log("Object: " + objData.name);
                buildStatus.newObject       = false;
                buildStatus.subObjCount     = 0;
                buildStatus.idxCount        = 0;
                buildStatus.grpIdx          = 0;
                buildStatus.grpFaceIdx      = 0;
                buildStatus.meshPartIdx     = 0;
                buildStatus.totFaceIdxCount = 0;
                buildStatus.numGroups       = Mathf.Max(1, objData.faceGroups.Count);
            }

            bool splitLargeMeshes = true;

#if UNITY_2017_3_OR_NEWER
            // GPU support for 32 bit indices is not guaranteed on all platforms;
            // for example Android devices with Mali-400 GPU do not support them.
            // This check is performed in Using32bitIndices().
            // If nothing is rendered on your device problably Using32bitIndices() must be updated.
            if (Using32bitIndices())
            {
                splitLargeMeshes = false;
            }
#endif
            bool splitGrp = false;

            DataSet.FaceGroupData grp = new DataSet.FaceGroupData();
            grp.name         = objData.faceGroups[buildStatus.grpIdx].name;
            grp.materialName = objData.faceGroups[buildStatus.grpIdx].materialName;


            // data for sub-object
            DataSet.ObjectData subObjData = new DataSet.ObjectData();
            subObjData.hasNormals = objData.hasNormals;
            subObjData.hasColors  = objData.hasColors;

            HashSet <int> vertIdxSet = new HashSet <int>();

            bool conv2sided = buildOptions != null && buildOptions.convertToDoubleSided;

            int maxIdx4mesh = conv2sided ? MAX_INDICES_LIMIT_FOR_A_MESH / 2 : MAX_INDICES_LIMIT_FOR_A_MESH;

            // copy blocks of face indices to each sub-object data
            for (int f = buildStatus.grpFaceIdx; f < objData.faceGroups[buildStatus.grpIdx].faces.Count; f++)
            {
                // if large meshed must be split and
                // if passed the max num of vertices and not at the last iteration
                if (splitLargeMeshes && (vertIdxSet.Count / 3 > MAX_VERT_COUNT / 3 || subObjData.allFaces.Count / 3 > maxIdx4mesh / 3))
                {
                    // split the group across more objects
                    splitGrp = true;
                    buildStatus.grpFaceIdx = f;
                    Debug.LogWarningFormat("Maximum vertex number for a mesh exceeded.\nSplitting object {0} (group {1}, starting from index {2})...", grp.name, buildStatus.grpIdx, f);
                    break;
                }
                DataSet.FaceIndices fi = objData.faceGroups[buildStatus.grpIdx].faces[f];
                subObjData.allFaces.Add(fi);
                grp.faces.Add(fi);
                vertIdxSet.Add(fi.vertIdx);
            }
            if (splitGrp || buildStatus.meshPartIdx > 0)
            {
                buildStatus.meshPartIdx++;
            }
            // create an empty (group) object in case the group has been splitted
            if (buildStatus.meshPartIdx == 1)
            {
                GameObject grpObj = new GameObject();
                grpObj.transform.SetParent(buildStatus.currObjGameObject.transform, false);
                grpObj.name = grp.name;
                buildStatus.subObjParent = grpObj;
            }

            // add a suffix to the group name in case the group has been splitted
            if (buildStatus.meshPartIdx > 0)
            {
                grp.name = buildStatus.subObjParent.name + "_MeshPart" + buildStatus.meshPartIdx;
            }
            subObjData.name = grp.name;

            // add the group to the sub object data
            subObjData.faceGroups.Add(grp);

            // update the start index
            buildStatus.idxCount += subObjData.allFaces.Count;

            if (!splitGrp)
            {
                buildStatus.grpFaceIdx = 0;
                buildStatus.grpIdx++;
            }
            buildStatus.totFaceIdxCount += subObjData.allFaces.Count;
            GameObject subobj = ImportSubObject(buildStatus.subObjParent, subObjData, mats);
            if (subobj == null)
            {
                Debug.LogWarningFormat("Error loading sub object n.{0}.", buildStatus.subObjCount);
            }
            //else Debug.LogFormat( "Imported face indices: {0} to {1}", buildStatus.totFaceIdxCount - sub_od.AllFaces.Count, buildStatus.totFaceIdxCount );

            buildStatus.subObjCount++;

            if (buildStatus.totFaceIdxCount >= objData.allFaces.Count || buildStatus.grpIdx >= objData.faceGroups.Count)
            {
                if (buildStatus.totFaceIdxCount != objData.allFaces.Count)
                {
                    Debug.LogWarningFormat("Imported face indices: {0} of {1}", buildStatus.totFaceIdxCount, objData.allFaces.Count);
                    return(false);
                }
                buildStatus.objCount++;
                buildStatus.newObject = true;
            }
            return(true);
        }