예제 #1
0
    public override void Write()
    {
        Indent();       jsonWriter.Write("{\n");
        IndentIn();

        Indent(); jsonWriter.Write("\"inverseBindMatrices\": " + invBindMatricesAccessorIndex + ",\n");
        Indent(); jsonWriter.Write("\"joints\": [\n");

        IndentIn();
        foreach (Transform j in joints)
        {
            CommaNL();
            Indent();       jsonWriter.Write("" + GlTF_Writer.nodeIDs.IndexOf(GlTF_Node.GetIDFromObject(j)));
        }

        IndentOut();
        jsonWriter.WriteLine();
        Indent(); jsonWriter.Write("],\n");

        Indent(); jsonWriter.Write("\"name\": \"" + name + "\"\n");

        IndentOut();
        Indent();       jsonWriter.Write("}");
    }
    public void Populate(AnimationClip clip, Transform tr, bool bake = true)
    {
        // 1. browse clip, collect all curves and create a TargetCurveSet for each target
        Dictionary <string, TargetCurveSet> targetCurvesBinding = new Dictionary <string, TargetCurveSet>();

        collectClipCurves(clip, ref targetCurvesBinding);

        // Baking needs all properties, fill missing curves with transform data in 2 keyframes (start, endTime)
        // where endTime is clip duration
        generateMissingCurves(clip.length, ref tr, ref targetCurvesBinding);

        if (bake)
        {
            // Bake animation for all animated nodes
            foreach (string target in targetCurvesBinding.Keys)
            {
                Transform targetTr = target.Length > 0 ? tr.Find(target) : tr;
                if (targetTr == null)
                {
                    continue;
                }

                Transform targetObject = targetTr;
                string    targetId     = GlTF_Node.GetNameFromObject(targetObject);
                int       targetUUID   = GlTF_Node.GetIDFromObject(targetObject);

                // Initialize accessors for current animation
                GlTF_Accessor timeAccessor = new GlTF_Accessor(targetId + "_TimeAccessor_" + clip.name, GlTF_Accessor.Type.SCALAR, GlTF_Accessor.ComponentType.FLOAT);
                timeAccessor.bufferView = GlTF_Writer.floatBufferView;
                int timeAccessorIndex = GlTF_Writer.accessors.Count;
                GlTF_Writer.accessors.Add(timeAccessor);

                // Translation
                GlTF_Channel chTranslation     = new GlTF_Channel("translation", animSamplers.Count);
                GlTF_Target  targetTranslation = new GlTF_Target();
                targetTranslation.id   = targetId;
                targetTranslation.uuid = targetUUID;
                targetTranslation.path = "translation";
                chTranslation.target   = targetTranslation;
                channels.Add(chTranslation);

                GlTF_AnimSampler sTranslation        = new GlTF_AnimSampler(timeAccessorIndex, GlTF_Writer.accessors.Count);
                GlTF_Accessor    translationAccessor = new GlTF_Accessor(targetId + "_TranslationAccessor_" + clip.name, GlTF_Accessor.Type.VEC3, GlTF_Accessor.ComponentType.FLOAT);
                translationAccessor.bufferView = GlTF_Writer.vec3BufferViewAnim;
                GlTF_Writer.accessors.Add(translationAccessor);
                animSamplers.Add(sTranslation);

                // Rotation
                GlTF_Channel chRotation     = new GlTF_Channel("rotation", animSamplers.Count);
                GlTF_Target  targetRotation = new GlTF_Target();
                targetRotation.id   = GlTF_Node.GetNameFromObject(targetObject);
                targetRotation.uuid = targetUUID;
                targetRotation.path = "rotation";
                chRotation.target   = targetRotation;
                channels.Add(chRotation);

                GlTF_AnimSampler sRotation        = new GlTF_AnimSampler(timeAccessorIndex, GlTF_Writer.accessors.Count);
                GlTF_Accessor    rotationAccessor = new GlTF_Accessor(targetId + "_RotationAccessor_" + clip.name, GlTF_Accessor.Type.VEC4, GlTF_Accessor.ComponentType.FLOAT);
                rotationAccessor.bufferView = GlTF_Writer.vec4BufferViewAnim;
                GlTF_Writer.accessors.Add(rotationAccessor);
                animSamplers.Add(sRotation);

                // Scale
                GlTF_Channel chScale     = new GlTF_Channel("scale", animSamplers.Count);
                GlTF_Target  targetScale = new GlTF_Target();
                targetScale.id   = GlTF_Node.GetNameFromObject(targetObject);
                targetScale.uuid = targetUUID;
                targetScale.path = "scale";
                chScale.target   = targetScale;
                channels.Add(chScale);

                GlTF_AnimSampler sScale        = new GlTF_AnimSampler(timeAccessorIndex, GlTF_Writer.accessors.Count);
                GlTF_Accessor    scaleAccessor = new GlTF_Accessor(targetId + "_ScaleAccessor_" + clip.name, GlTF_Accessor.Type.VEC3, GlTF_Accessor.ComponentType.FLOAT);
                scaleAccessor.bufferView = GlTF_Writer.vec3BufferViewAnim;
                GlTF_Writer.accessors.Add(scaleAccessor);
                animSamplers.Add(sScale);

                // Bake and populate animation data
                float[]   times     = null;
                Vector3[] positions = null;
                Vector3[] scales    = null;
                Vector4[] rotations = null;
                bakeCurveSet(targetCurvesBinding[target], clip.length, bakingFramerate, ref times, ref positions, ref rotations, ref scales);

                // Populate accessors
                timeAccessor.Populate(times);
                translationAccessor.Populate(positions);
                rotationAccessor.Populate(rotations, false);
                scaleAccessor.Populate(scales, true);
            }
        }
        else
        {
            Debug.LogError("Only baked animation is supported for now. Skipping animation");
        }
    }
    public IEnumerator Export(string path, Preset presetAsset, bool buildZip, bool exportPBRMaterials, bool exportAnimation = true, bool doConvertImages = false)
    {
        writer = new GlTF_Writer();
        writer.Init();
        done = false;
        bool debugRightHandedScale = false;

        GlTF_Writer.exportedFiles.Clear();
        if (debugRightHandedScale)
        {
            GlTF_Writer.convertRightHanded = false;
        }

        writer.extraString.Add("exporterVersion", GlTF_Writer.exporterVersion);

        Transform[] transforms0 = Selection.GetTransforms(SelectionMode.TopLevel);
        //// Create rootNode
        //GlTF_Node correctionNode = new GlTF_Node();
        //correctionNode.id = GetInstanceID(transforms0[0]);
        //correctionNode.name = transforms0[0].name;
        //GlTF_Writer.nodes.Add(correctionNode);
        //GlTF_Writer.nodeIDs.Add(correctionNode.id);
        //GlTF_Writer.nodeNames.Add(correctionNode.name);
        //GlTF_Writer.rootNodes.Add(correctionNode);

        //path = toGlTFname(path);
        savedPath = Path.GetDirectoryName(path);

        // Temp list to keep track of skeletons
        Dictionary <string, GlTF_Skin> parsedSkins = new Dictionary <string, GlTF_Skin>();

        parsedSkins.Clear();

        // first, collect objects in the scene, add to lists
        Transform[]      transforms = Selection.GetTransforms(SelectionMode.Deep);
        List <Transform> trs        = new List <Transform>(transforms);
        // Prefilter selected nodes and look for skinning in order to list "bones" nodes
        //FIXME: improve this
        List <Transform> bones = new List <Transform>();

        foreach (Transform tr in trs)
        {
            if (!tr.gameObject.activeSelf)
            {
                continue;
            }

            SkinnedMeshRenderer skin = tr.GetComponent <SkinnedMeshRenderer>();
            if (skin)
            {
                foreach (Transform bone in skin.bones)
                {
                    bones.Add(bone);
                }
            }
        }

        nbSelectedObjects = trs.Count;
        int nbDisabledObjects = 0;
        int nbIndex           = 1;

        foreach (Transform tr in trs)
        {
            if (tr.gameObject.activeInHierarchy == false)
            {
                nbDisabledObjects++;
                continue;
            }

            // Initialize the node
            GlTF_Node node = new GlTF_Node();
            node.id   = GetInstanceID(tr);//GlTF_Node.GetNameFromObject(tr);
            node.name = GlTF_Writer.cleanNonAlphanumeric(tr.name);

            if (tr.GetComponent <Camera>() != null)
            {
                parseUnityCamera(tr);
            }

            if (tr.GetComponent <Light>() != null)
            {
                parseUnityLight(tr);
            }

            Mesh m = GetMesh(tr);
            if (m != null)
            {
                GlTF_Mesh mesh = new GlTF_Mesh();
                mesh.id   = GetInstanceID(m);
                mesh.name = GlTF_Writer.cleanNonAlphanumeric(GlTF_Mesh.GetNameFromObject(m));

                GlTF_Accessor positionAccessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "position"), GlTF_Accessor.Type.VEC3, GlTF_Accessor.ComponentType.FLOAT);
                positionAccessor.bufferView = GlTF_Writer.vec3BufferView;
                GlTF_Writer.accessors.Add(positionAccessor);

                GlTF_Accessor normalAccessor = null;
                if (m.normals.Length > 0)
                {
                    normalAccessor            = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "normal"), GlTF_Accessor.Type.VEC3, GlTF_Accessor.ComponentType.FLOAT);
                    normalAccessor.bufferView = GlTF_Writer.vec3BufferView;
                    GlTF_Writer.accessors.Add(normalAccessor);
                }

                GlTF_Accessor colorAccessor = null;
                if (m.colors.Length > 0)
                {
                    colorAccessor            = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "color"), GlTF_Accessor.Type.VEC4, GlTF_Accessor.ComponentType.FLOAT);
                    colorAccessor.bufferView = GlTF_Writer.vec4BufferView;
                    GlTF_Writer.accessors.Add(colorAccessor);
                }

                GlTF_Accessor uv0Accessor = null;
                if (m.uv.Length > 0)
                {
                    uv0Accessor            = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "uv0"), GlTF_Accessor.Type.VEC2, GlTF_Accessor.ComponentType.FLOAT);
                    uv0Accessor.bufferView = GlTF_Writer.vec2BufferView;
                    GlTF_Writer.accessors.Add(uv0Accessor);
                }

                GlTF_Accessor uv1Accessor = null;
                if (m.uv2.Length > 0)
                {
                    // check if object is affected by a lightmap
                    uv1Accessor            = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "uv1"), GlTF_Accessor.Type.VEC2, GlTF_Accessor.ComponentType.FLOAT);
                    uv1Accessor.bufferView = GlTF_Writer.vec2BufferView;
                    GlTF_Writer.accessors.Add(uv1Accessor);
                }

                GlTF_Accessor uv2Accessor = null;
                if (m.uv3.Length > 0)
                {
                    uv2Accessor            = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "uv2"), GlTF_Accessor.Type.VEC2, GlTF_Accessor.ComponentType.FLOAT);
                    uv2Accessor.bufferView = GlTF_Writer.vec2BufferView;
                    GlTF_Writer.accessors.Add(uv2Accessor);
                }

                GlTF_Accessor uv3Accessor = null;
                if (m.uv4.Length > 0)
                {
                    uv3Accessor            = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "uv3"), GlTF_Accessor.Type.VEC2, GlTF_Accessor.ComponentType.FLOAT);
                    uv3Accessor.bufferView = GlTF_Writer.vec2BufferView;
                    GlTF_Writer.accessors.Add(uv3Accessor);
                }

                GlTF_Accessor jointAccessor = null;
                if (exportAnimation && m.boneWeights.Length > 0)
                {
                    jointAccessor            = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "joints"), GlTF_Accessor.Type.VEC4, GlTF_Accessor.ComponentType.USHORT);
                    jointAccessor.bufferView = GlTF_Writer.vec4UshortBufferView;
                    GlTF_Writer.accessors.Add(jointAccessor);
                }

                GlTF_Accessor weightAccessor = null;
                if (exportAnimation && m.boneWeights.Length > 0)
                {
                    weightAccessor            = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "weights"), GlTF_Accessor.Type.VEC4, GlTF_Accessor.ComponentType.FLOAT);
                    weightAccessor.bufferView = GlTF_Writer.vec4BufferView;
                    GlTF_Writer.accessors.Add(weightAccessor);
                }

                GlTF_Accessor tangentAccessor = null;
                if (m.tangents.Length > 0)
                {
                    tangentAccessor            = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "tangents"), GlTF_Accessor.Type.VEC4, GlTF_Accessor.ComponentType.FLOAT);
                    tangentAccessor.bufferView = GlTF_Writer.vec4BufferView;
                    GlTF_Writer.accessors.Add(tangentAccessor);
                }

                var smCount = m.subMeshCount;
                for (var i = 0; i < smCount; ++i)
                {
                    GlTF_Primitive primitive = new GlTF_Primitive();
                    primitive.name  = GlTF_Primitive.GetNameFromObject(m, i);
                    primitive.index = i;
                    GlTF_Attributes attributes = new GlTF_Attributes();
                    attributes.positionAccessor  = positionAccessor;
                    attributes.normalAccessor    = normalAccessor;
                    attributes.colorAccessor     = colorAccessor;
                    attributes.texCoord0Accessor = uv0Accessor;
                    attributes.texCoord1Accessor = uv1Accessor;
                    attributes.texCoord2Accessor = uv2Accessor;
                    attributes.texCoord3Accessor = uv3Accessor;
                    attributes.jointAccessor     = jointAccessor;
                    attributes.weightAccessor    = weightAccessor;
                    attributes.tangentAccessor   = tangentAccessor;
                    primitive.attributes         = attributes;
                    GlTF_Accessor indexAccessor = new GlTF_Accessor(GlTF_Accessor.GetNameFromObject(m, "indices_" + i), GlTF_Accessor.Type.SCALAR, GlTF_Accessor.ComponentType.USHORT);
                    indexAccessor.bufferView = GlTF_Writer.ushortBufferView;
                    GlTF_Writer.accessors.Add(indexAccessor);
                    primitive.indices = indexAccessor;

                    var mr = GetRenderer(tr);
                    var sm = mr.sharedMaterials;
                    if (i < sm.Length)
                    {
                        var mat     = sm[i];
                        var matName = GlTF_Material.GetNameFromObject(mat);
                        if (GlTF_Writer.materialNames.Contains(matName))
                        {
                            primitive.materialIndex = GlTF_Writer.materialNames.IndexOf(matName);                             // THIS INDIRECTION CAN BE REMOVED!
                        }
                        else
                        {
                            GlTF_Material material = new GlTF_Material();
                            material.name           = GlTF_Writer.cleanNonAlphanumeric(mat.name);
                            primitive.materialIndex = GlTF_Writer.materials.Count;
                            GlTF_Writer.materialNames.Add(matName);
                            GlTF_Writer.materials.Add(material);

                            //technique
                            var s        = mat.shader;
                            var techName = GlTF_Technique.GetNameFromObject(s);
                            if (GlTF_Writer.techniqueNames.Contains(techName))
                            {
                                material.instanceTechniqueIndex = GlTF_Writer.techniqueNames.IndexOf(techName);                                // THIS INDIRECTION CAN BE REMOVED!
                            }
                            else
                            {
                                GlTF_Technique tech = new GlTF_Technique();
                                tech.name = techName;
                                GlTF_Technique.Parameter tParam = new GlTF_Technique.Parameter();
                                tParam.name     = "position";
                                tParam.type     = GlTF_Technique.Type.FLOAT_VEC3;
                                tParam.semantic = GlTF_Technique.Semantic.POSITION;
                                tech.parameters.Add(tParam);
                                GlTF_Technique.Attribute tAttr = new GlTF_Technique.Attribute();
                                tAttr.name  = "a_position";
                                tAttr.param = tParam.name;
                                tech.attributes.Add(tAttr);

                                if (normalAccessor != null)
                                {
                                    tParam          = new GlTF_Technique.Parameter();
                                    tParam.name     = "normal";
                                    tParam.type     = GlTF_Technique.Type.FLOAT_VEC3;
                                    tParam.semantic = GlTF_Technique.Semantic.NORMAL;
                                    tech.parameters.Add(tParam);
                                    tAttr       = new GlTF_Technique.Attribute();
                                    tAttr.name  = "a_normal";
                                    tAttr.param = tParam.name;
                                    tech.attributes.Add(tAttr);
                                }

                                if (uv0Accessor != null)
                                {
                                    tParam          = new GlTF_Technique.Parameter();
                                    tParam.name     = "texcoord0";
                                    tParam.type     = GlTF_Technique.Type.FLOAT_VEC2;
                                    tParam.semantic = GlTF_Technique.Semantic.TEXCOORD_0;
                                    tech.parameters.Add(tParam);
                                    tAttr       = new GlTF_Technique.Attribute();
                                    tAttr.name  = "a_texcoord0";
                                    tAttr.param = tParam.name;
                                    tech.attributes.Add(tAttr);
                                }

                                if (uv1Accessor != null)
                                {
                                    tParam          = new GlTF_Technique.Parameter();
                                    tParam.name     = "texcoord1";
                                    tParam.type     = GlTF_Technique.Type.FLOAT_VEC2;
                                    tParam.semantic = GlTF_Technique.Semantic.TEXCOORD_1;
                                    tech.parameters.Add(tParam);
                                    tAttr       = new GlTF_Technique.Attribute();
                                    tAttr.name  = "a_texcoord1";
                                    tAttr.param = tParam.name;
                                    tech.attributes.Add(tAttr);
                                }

                                if (uv2Accessor != null)
                                {
                                    tParam          = new GlTF_Technique.Parameter();
                                    tParam.name     = "texcoord2";
                                    tParam.type     = GlTF_Technique.Type.FLOAT_VEC2;
                                    tParam.semantic = GlTF_Technique.Semantic.TEXCOORD_2;
                                    tech.parameters.Add(tParam);
                                    tAttr       = new GlTF_Technique.Attribute();
                                    tAttr.name  = "a_texcoord2";
                                    tAttr.param = tParam.name;
                                    tech.attributes.Add(tAttr);
                                }

                                if (uv3Accessor != null)
                                {
                                    tParam          = new GlTF_Technique.Parameter();
                                    tParam.name     = "texcoord3";
                                    tParam.type     = GlTF_Technique.Type.FLOAT_VEC2;
                                    tParam.semantic = GlTF_Technique.Semantic.TEXCOORD_3;
                                    tech.parameters.Add(tParam);
                                    tAttr       = new GlTF_Technique.Attribute();
                                    tAttr.name  = "a_texcoord3";
                                    tAttr.param = tParam.name;
                                    tech.attributes.Add(tAttr);
                                }

                                tech.AddDefaultUniforms();

                                // Populate technique with shader data
                                GlTF_Writer.techniqueNames.Add(techName);
                                GlTF_Writer.techniques.Add(tech);

                                // create program
                                GlTF_Program program = new GlTF_Program();
                                program.name = GlTF_Program.GetNameFromObject(s);
                                tech.program = program.name;
                                foreach (var attr in tech.attributes)
                                {
                                    program.attributes.Add(attr.name);
                                }
                                GlTF_Writer.programs.Add(program);
                            }

                            unityToPBRMaterial(mat, ref material);
                        }
                    }
                    mesh.primitives.Add(primitive);
                }

                // If gameobject having SkinnedMeshRenderer component has been transformed,
                // the mesh would need to be baked here.
                mesh.Populate(m);
                GlTF_Writer.meshes.Add(mesh);
                node.meshIndex = GlTF_Writer.meshes.IndexOf(mesh);
            }

            // Parse animations
            if (exportAnimation)
            {
                Animator a = tr.GetComponent <Animator>();
                if (a != null)
                {
                    AnimationClip[] clips = AnimationUtility.GetAnimationClips(tr.gameObject);
                    for (int i = 0; i < clips.Length; i++)
                    {
                        //FIXME It seems not good to generate one animation per animator.
                        GlTF_Animation anim = new GlTF_Animation(GlTF_Writer.cleanNonAlphanumeric(clips[i].name));
                        anim.Populate(clips[i], tr, GlTF_Writer.bakeAnimation);
                        if (anim.channels.Count > 0)
                        {
                            GlTF_Writer.animations.Add(anim);
                        }
                    }
                }

                Animation animation = tr.GetComponent <Animation>();
                if (animation != null)
                {
                    AnimationClip clip = animation.clip;
                    //FIXME It seems not good to generate one animation per animator.
                    GlTF_Animation anim = new GlTF_Animation(GlTF_Writer.cleanNonAlphanumeric(clip.name));
                    anim.Populate(clip, tr, GlTF_Writer.bakeAnimation);
                    if (anim.channels.Count > 0)
                    {
                        GlTF_Writer.animations.Add(anim);
                    }
                }
            }

            // Parse transform
            if (tr.parent == null)
            {
                Matrix4x4 mat = Matrix4x4.identity;
                if (debugRightHandedScale)
                {
                    mat.m22 = -1;
                }
                mat         = mat * Matrix4x4.TRS(tr.localPosition, tr.localRotation, tr.localScale);
                node.matrix = new GlTF_Matrix(mat);
            }
            // Use good transform if parent object is not in selection
            else if (!trs.Contains(tr.parent))
            {
                node.hasParent = false;
                Matrix4x4 mat = Matrix4x4.identity;
                if (debugRightHandedScale)
                {
                    mat.m22 = -1;
                }
                mat         = mat * tr.localToWorldMatrix;
                node.matrix = new GlTF_Matrix(mat);
            }
            else
            {
                node.hasParent = true;
                if (tr.localPosition != Vector3.zero)
                {
                    node.translation = new GlTF_Translation(tr.localPosition);
                }
                if (tr.localScale != Vector3.one)
                {
                    node.scale = new GlTF_Scale(tr.localScale);
                }
                if (tr.localRotation != Quaternion.identity)
                {
                    node.rotation = new GlTF_Rotation(tr.localRotation);
                }
            }

            if (!node.hasParent)
            {
                // correctionNode.childrenNames.Add(node.name);
                // correctionNode.childrenIDs.Add(node.id);
                GlTF_Writer.rootNodes.Add(node);
            }

            if (tr.GetComponent <Camera>() != null)
            {
                node.cameraName = GlTF_Writer.cleanNonAlphanumeric(tr.name);
            }
            else if (tr.GetComponent <Light>() != null)
            {
                node.lightName = GlTF_Writer.cleanNonAlphanumeric(tr.name);
            }

            // Parse node's skin data
            GlTF_Accessor       invBindMatrixAccessor = null;
            SkinnedMeshRenderer skinMesh = tr.GetComponent <SkinnedMeshRenderer>();
            if (exportAnimation && skinMesh != null && skinMesh.enabled && checkSkinValidity(skinMesh, trs) && skinMesh.rootBone != null)
            {
                GlTF_Skin skin = new GlTF_Skin();

                skin.name = GlTF_Writer.cleanNonAlphanumeric(skinMesh.rootBone.name);// + "_skeleton_" + GlTF_Writer.cleanNonAlphanumeric(node.name) + tr.GetInstanceID();

                // Create invBindMatrices accessor
                invBindMatrixAccessor            = new GlTF_Accessor(skin.name + "invBindMatrices", GlTF_Accessor.Type.MAT4, GlTF_Accessor.ComponentType.FLOAT);
                invBindMatrixAccessor.bufferView = GlTF_Writer.mat4BufferView;
                GlTF_Writer.accessors.Add(invBindMatrixAccessor);

                // Generate skin data
                skin.Populate(tr, ref invBindMatrixAccessor, GlTF_Writer.accessors.Count - 1);
                GlTF_Writer.skins.Add(skin);
                node.skinIndex = GlTF_Writer.skins.IndexOf(skin);
            }

            foreach (Transform t in tr.transform)
            {
                if (t.gameObject.activeInHierarchy)
                {
                    node.childrenNames.Add(GlTF_Node.GetNameFromObject(t));
                    node.childrenIDs.Add(GlTF_Node.GetIDFromObject(t));
                }
            }

            GlTF_Writer.nodeNames.Add(node.name);
            GlTF_Writer.nodeIDs.Add(node.id);
            GlTF_Writer.nodes.Add(node);
            // Debug.Log(node.name + "_" + node.id + "_" + nbIndex++);
        }

        if (GlTF_Writer.meshes.Count == 0)
        {
            Debug.Log("No visible objects have been exported. Aboring export");
            yield return(false);
        }

        writer.OpenFiles(path);
        writer.Write();
        writer.CloseFiles();

        if (nbDisabledObjects > 0)
        {
            Debug.Log(nbDisabledObjects + " disabled object ignored during export");
        }

        Debug.Log("Scene has been exported to " + path);
        EditorUtility.DisplayDialog("状态", "导出成功", "Ok");
        done = true;

        yield return(true);
    }