示例#1
0
        public void RegisterUdonBehaviour(UdonBehaviour udonBehaviour)
        {
            GameObject udonBehaviourGameObject = udonBehaviour.gameObject;
            Scene      udonBehaviourScene      = udonBehaviourGameObject.scene;

            if (!_sceneUdonBehaviourDirectories.TryGetValue(udonBehaviourScene, out Dictionary <GameObject, HashSet <UdonBehaviour> > sceneUdonBehaviourDirectory))
            {
                return;
            }

            if (!sceneUdonBehaviourDirectory.TryGetValue(udonBehaviourGameObject, out HashSet <UdonBehaviour> gameObjectUdonBehaviours))
            {
                gameObjectUdonBehaviours = new HashSet <UdonBehaviour>();
                sceneUdonBehaviourDirectory.Add(udonBehaviourGameObject, gameObjectUdonBehaviours);
                return;
            }

            if (!gameObjectUdonBehaviours.Contains(udonBehaviour))
            {
                gameObjectUdonBehaviours.Add(udonBehaviour);
            }
        }
 public abstract void RunEditorUpdate(UdonBehaviour udonBehaviour, ref bool dirty);
    private void ImportActorChildren(AssetImportContext ctx, GameObject parentObject, XmlNode containerNode)
    {
        foreach (XmlNode node in containerNode.ChildNodes)
        {
            if (!(node.Name == "Actor" || node.Name == "ActorMesh" || node.Name == "Light"))
            {
                continue; // Only examine supported nodes
            }
            String     objName = node.Attributes["label"].Value + "_" + node.Attributes["name"].Value;
            GameObject obj     = new GameObject(objName);
            obj.transform.SetParent(parentObject.transform, /*worldPositionStays=*/ false);
            //Do NOT call ctx.AddObjectToAsset on these GameObjects. It should only be called on the root GameObject of the hierarchy (which the Unity manual fails to mention, of course.)
            // Calling ctx.AddObjectToAsset on the child GameObjects will cause Unity to crash when changing importer settings.

            {
                XmlNode xfNode = node.SelectSingleNode("child::Transform");
                if (xfNode != null)
                {
                    // Transform position and rotation are stored in an absolute coordinate space. TODO: not sure if Scale will be applied correctly
                    // Datasmith units are cm, while Unity units are m; we adjust the scale of mesh vertices and of incoming Transform nodes to match.

                    obj.transform.position = new Vector3(
                        Single.Parse(xfNode.Attributes["tx"].Value) * 0.01f,
                        Single.Parse(xfNode.Attributes["ty"].Value) * 0.01f,
                        Single.Parse(xfNode.Attributes["tz"].Value) * 0.01f);
                    obj.transform.localScale = new Vector3(
                        Single.Parse(xfNode.Attributes["sx"].Value),
                        Single.Parse(xfNode.Attributes["sy"].Value),
                        Single.Parse(xfNode.Attributes["sz"].Value));
                    obj.transform.rotation = new Quaternion(
                        Single.Parse(xfNode.Attributes["qx"].Value),
                        Single.Parse(xfNode.Attributes["qy"].Value),
                        Single.Parse(xfNode.Attributes["qz"].Value),
                        Single.Parse(xfNode.Attributes["qw"].Value));
                }
            } // transform processing

            if (node.Name == "ActorMesh")
            {
                XmlNode meshNode = node.SelectSingleNode("child::mesh");
                if (meshNode != null)
                {
                    String        meshName = meshNode.Attributes["name"].Value;
                    UdsStaticMesh mesh;

                    staticMeshElements.TryGetValue(meshName, out mesh);
                    Debug.Assert(mesh != null, String.Format("Missing StaticMesh node for \"{0}\" referenced from ActorMesh node \"{1}\"", meshName, node.Attributes["name"].Value));
                    if (mesh.assetRef)
                    {
                        MeshFilter mf = obj.AddComponent <MeshFilter>();
                        mf.sharedMesh = mesh.assetRef;

                        Material[] mats = new Material[mesh.assetRef.subMeshCount];
                        for (int materialIdx = 0; materialIdx < mesh.assetRef.subMeshCount; ++materialIdx)
                        {
                            mats[materialIdx] = mesh.materialRefs[materialIdx].assetRef;
                        }

                        MeshRenderer mr = obj.AddComponent <MeshRenderer>();
                        mr.sharedMaterials = mats;

                        String RevitLayer = node.Attributes["layer"].Value;
                        //Dictionary<String, String> metadata = new Dictionary<string, string>();
                        //actorMetadata.TryGetValue(node.Attributes["name"].Value, out metadata);

                        // Process imported metadata and try to do something reasonable with it
                        {
                            //String RevitCategory;
                            //metadata.TryGetValue("Element_Category", out RevitCategory);
                            if (RevitLayer != null)
                            {
                                if (Regex.Match(RevitLayer, @"Ceilings", RegexOptions.IgnoreCase).Success)
                                {
                                    // Apply ceiling height offset
                                    Vector3 p = obj.transform.position;
                                    p.z += m_CeilingHeightOffset;
                                    obj.transform.position = p;
                                }

                                if (Regex.Match(RevitLayer, @"Floors", RegexOptions.IgnoreCase).Success)
                                {
                                    // Apply floor height offset
                                    Vector3 p = obj.transform.position;
                                    p.z += m_FloorHeightOffset;
                                    obj.transform.position = p;
                                }


                                if (Regex.Match(RevitLayer, m_IgnoredLayerRegex, RegexOptions.IgnoreCase).Success)
                                {
                                    // Default-hidden objects. For example, "Entourage" and "Planting" objects are not exported correctly by Datasmith (no materials/textures), so we hide them.
                                    obj.SetActive(false);
                                }
                                else if (Regex.Match(RevitLayer, m_StaticTangibleLayerRegex, RegexOptions.IgnoreCase).Success)
                                {
                                    // Completely static objects that should be lightmapped and have collision enabled
                                    GameObjectUtility.SetStaticEditorFlags(obj, StaticEditorFlags.LightmapStatic | StaticEditorFlags.OccludeeStatic | StaticEditorFlags.OccluderStatic | StaticEditorFlags.BatchingStatic | StaticEditorFlags.ReflectionProbeStatic);

                                    // Collision
                                    MeshCollider collider = obj.AddComponent <MeshCollider>();
                                    collider.cookingOptions = (MeshColliderCookingOptions.CookForFasterSimulation | MeshColliderCookingOptions.EnableMeshCleaning | MeshColliderCookingOptions.WeldColocatedVertices);
                                }
                                else if (Regex.Match(RevitLayer, m_StaticIntangibleLayerRegex, RegexOptions.IgnoreCase).Success)
                                {
                                    // Completely static objects that should be lightmapped, but don't need collision
                                    GameObjectUtility.SetStaticEditorFlags(obj, StaticEditorFlags.LightmapStatic | StaticEditorFlags.OccludeeStatic | StaticEditorFlags.OccluderStatic | StaticEditorFlags.BatchingStatic | StaticEditorFlags.ReflectionProbeStatic);
                                }
                                else if (Regex.Match(RevitLayer, m_PhysicsPropsLayerRegex).Success)
                                {
                                    // Clutter that can be physics-enabled

                                    MeshCollider collider = obj.AddComponent <MeshCollider>();
                                    collider.cookingOptions = (MeshColliderCookingOptions.CookForFasterSimulation | MeshColliderCookingOptions.EnableMeshCleaning | MeshColliderCookingOptions.WeldColocatedVertices);

#if USE_VRC_SDK3
                                    if (m_SetupPhysicsProps)
                                    {
                                        collider.convex = true;

                                        Rigidbody rb = obj.AddComponent <Rigidbody>();
                                        // rb.collisionDetectionMode = CollisionDetectionMode.Continuous; // Higher quality collision detection, but slower.

                                        // Add VRCPickup component to make the object interactable
                                        VRC.SDK3.Components.VRCPickup pickup = obj.AddComponent <VRC.SDK3.Components.VRCPickup>();

                                        pickup.pickupable = true;
                                        pickup.allowManipulationWhenEquipped = true;

                                        // Add UdonBehaviour component to replicate the object's position
                                        VRC.Udon.UdonBehaviour udon = obj.AddComponent <VRC.Udon.UdonBehaviour>();
                                        udon.SynchronizePosition = true;

                                        // TODO see if it's possible to only enable gravity on objects the first time they're picked up (so wall/ceiling fixtures can remain in place until grabbed)
                                    }
#endif
                                }
                                else
                                {
                                    ctx.LogImportWarning(String.Format("Unhandled Layer \"{0}\" -- ActorMesh \"{1}\" will not have physics and lighting behaviours automatically mapped", RevitLayer, objName));
                                }

                                if (Regex.Match(RevitLayer, @"Lighting").Success)
                                {
                                    // Turn off shadow casting on light fixtures. Light sources are usually placed inside the fixture body and we don't want the fixture geometry to block them.
                                    mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
                                }
                            }
                        }
                    }
                    else
                    {
                        ctx.LogImportError(String.Format("ActorMesh {0} mesh {1} assetRef is NULL", obj.name, meshName));
                    }
                }
            } // ActorMesh

            if (node.Name == "Light" && m_ImportLights)
            {
                Light light = obj.AddComponent <Light>();
                if (node.Attributes["type"].Value == "PointLight")
                {
                    light.type = LightType.Point;
                }
                else
                {
                    ctx.LogImportWarning(String.Format("Light {0}: Unhandled \"type\" \"{1}\", defaulting to Point", objName, node.Attributes["type"].Value));
                }

                { // Color temperature or RGB color
                    XmlNode colorNode = node.SelectSingleNode("child::Color");
                    if (colorNode != null)
                    {
                        if (Int32.Parse(colorNode.Attributes["usetemp"].Value) != 0)
                        {
                            float colorTemperature = Single.Parse(colorNode.Attributes["temperature"].Value);
                            // There doesn't appear to be a way to turn on color temperature mode on the Light programmatically (why?)
                            // Convert it to RGB; algorithm borrowed from https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html

                            float tmpKelvin = Mathf.Clamp(colorTemperature, 1000.0f, 40000.0f) / 100.0f;
                            // Note: The R-squared values for each approximation follow each calculation
                            float r = tmpKelvin <= 66.0f ? 255.0f :
                                      Mathf.Clamp(329.698727446f * (Mathf.Pow(tmpKelvin - 60.0f, -0.1332047592f)), 0.0f, 255.0f); // .988

                            float g = tmpKelvin <= 66 ?
                                      Mathf.Clamp(99.4708025861f * Mathf.Log(tmpKelvin) - 161.1195681661f, 0.0f, 255.0f) :         // .996
                                      Mathf.Clamp(288.1221695283f * (Mathf.Pow(tmpKelvin - 60.0f, -0.0755148492f)), 0.0f, 255.0f); // .987

                            float b = tmpKelvin >= 66 ? 255 :
                                      tmpKelvin <= 19 ? 0 :
                                      Mathf.Clamp(138.5177312231f * Mathf.Log(tmpKelvin - 10.0f) - 305.0447927307f, 0.0f, 255.0f); // .998

                            light.color = new Color(r / 255.0f, g / 255.0f, b / 255.0f);
                        }
                        else
                        {
                            float r = Single.Parse(colorNode.Attributes["R"].Value);
                            float g = Single.Parse(colorNode.Attributes["G"].Value);
                            float b = Single.Parse(colorNode.Attributes["B"].Value);
                            light.color = new Color(r, g, b);
                        }
                    }
                }

                // Common light parameters
                if (m_SetupLightmapBaking)
                {
                    light.lightmapBakeType = LightmapBakeType.Baked;
                }

                GameObjectUtility.SetStaticEditorFlags(obj, StaticEditorFlags.LightmapStatic | StaticEditorFlags.OccludeeStatic | StaticEditorFlags.OccluderStatic | StaticEditorFlags.BatchingStatic | StaticEditorFlags.ReflectionProbeStatic);
            }

            { // children node processing
                XmlNode childrenNode = node.SelectSingleNode("child::children");
                if (childrenNode != null)
                {
                    // TODO obey visible="true" / visible="false" attribute on children node
                    ImportActorChildren(ctx, obj, childrenNode);
                }
            } // children node processing
        }     // child loop
    }