Пример #1
0
        // Protected so that derived classes can access it, but users derive their own classes so we hide it from the docs.
        /// \cond
        protected virtual void Synchronize()
        {
            if (flushRequested)
            {
                FlushInternalData();
                flushRequested = false;
            }

            // Check whether the gameObject has been moved to a new layer.
            if (gameObject.layer != previousLayer)
            {
                // If so we update the children to match and then clear the flag.
                gameObject.SetLayerRecursively(gameObject.layer);
                previousLayer = gameObject.layer;
            }

            // NOTE - The following line passes transform.worldToLocalMatrix as a shader parameter. This is explicitly
            // forbidden by the Unity docs which say:
            //
            //   IMPORTANT: If you're setting shader parameters you MUST use Renderer.worldToLocalMatrix instead.
            //
            // However, we don't have a renderer on this game object as the rendering is handled by the child OctreeNodes.
            // The Unity doc's do not say why this is the case, but my best guess is that it is related to secret scaling
            // which Unity may perform before sending data to the GPU (probably to avoid precision problems). See here:
            //
            //   http://forum.unity3d.com/threads/153328-How-to-reproduce-_Object2World
            //
            // It seems to work in our case, even with non-uniform scaling applied to the volume. Perhaps we are just geting
            // lucky, pehaps it just works on our platform, or perhaps it is actually valid for some other reason. Just be aware.
            VolumeRenderer volumeRenderer = gameObject.GetComponent <VolumeRenderer>();

            if (volumeRenderer != null)
            {
                if (volumeRenderer.material != null)
                {
                    volumeRenderer.material.SetMatrix("_World2Volume", transform.worldToLocalMatrix);
                }
            }
        }
        /// \cond
        protected override bool SynchronizeOctree(uint availableSyncOperations)
        {
            VolumeRenderer volumeRenderer = gameObject.GetComponent <VolumeRenderer>();
            VolumeCollider volumeCollider = gameObject.GetComponent <VolumeCollider>();

            Vector3 camPos = CameraUtils.getCurrentCameraPosition();

            // This is messy - perhaps the LOD thresold shold not be a parameter to update. Instead it could be passed
            // as a parameter during traversal, so different traversal could retrieve differnt LODs. We then wouldn't
            // want a single 'renderThisNode' member of Cubiquity nodes, but instead some threshold we could compare to.
            float lodThreshold = GetComponent <VolumeRenderer>() ? GetComponent <VolumeRenderer>().lodThreshold : 1.0f;

            int minimumLOD = GetComponent <VolumeRenderer>() ? GetComponent <VolumeRenderer>().minimumLOD : 0;

            // Although the LOD system is partially functional I don't feel it's ready for release yet.
            // The following line disables it by forcing the highest level of detail to always be used.
            minimumLOD = 0;

            // Next line commented out so the system starts up with LOD disabled.
            //if (volumeRenderer.hasChanged)
            {
                CubiquityDLL.SetLodRange(data.volumeHandle.Value, minimumLOD, 0);
            }

            bool cubiquityUpToDate = CubiquityDLL.UpdateVolume(data.volumeHandle.Value, camPos.x, camPos.y, camPos.z, lodThreshold);

            if (CubiquityDLL.HasRootOctreeNode(data.volumeHandle.Value) == 1)
            {
                uint rootNodeHandle = CubiquityDLL.GetRootOctreeNode(data.volumeHandle.Value);

                if (rootOctreeNodeGameObject == null)
                {
                    rootOctreeNodeGameObject = OctreeNode.CreateOctreeNode(rootNodeHandle, gameObject);
                }

                OctreeNode.syncNode(ref availableSyncOperations, rootOctreeNodeGameObject, rootNodeHandle, gameObject);

                if (volumeRenderer != null && volumeRenderer.hasChanged)
                {
                    OctreeNode.syncNodeWithVolumeRenderer(rootOctreeNodeGameObject, volumeRenderer, true);
                }

                if (volumeCollider != null && volumeCollider.hasChanged)
                {
                    OctreeNode.syncNodeWithVolumeCollider(rootOctreeNodeGameObject, volumeCollider, true);
                }
            }

            // These properties might have to be synced with the volume (e.g. LOD settings) or with components
            // (e.g. shadow/material settings). Therefore we don't clear the flags until all syncing is completed.
            if (volumeRenderer != null)
            {
                volumeRenderer.hasChanged = false;
            }
            if (volumeCollider != null)
            {
                volumeCollider.hasChanged = false;
            }

            // If there were still sync operations available then there was no more syncing to be done with the
            // Cubiquity octree. So if the Cubiquity octree was also up to date then we have synced everything.
            return(cubiquityUpToDate && availableSyncOperations > 0);
        }
Пример #3
0
        private void Update()
        {
            if (flushRequested)
            {
                FlushInternalData();
                flushRequested = false;

                // It seems prudent to return at this point, and leave the actual updating to the next call of this function.
                // This is because we've just destroyed a bunch of stuff by flushing and Unity actually defers Destroy() until
                // later in the frame. It actually seems t work ok without the return, but it makes me feel a little safer.
                return;
            }

            // Check whether the gameObject has been moved to a new layer.
            if (gameObject.layer != previousLayer)
            {
                // If so we update the children to match and then clear the flag.
                gameObject.SetLayerRecursively(gameObject.layer);
                previousLayer = gameObject.layer;
            }

            // Set shader parameters.
            VolumeRenderer volumeRenderer = gameObject.GetComponent <VolumeRenderer>();

            if (volumeRenderer != null)
            {
                if (volumeRenderer.material != null && data)
                {
                    Vector3i volumeSize = (data.enclosingRegion.upperCorner - data.enclosingRegion.lowerCorner);
                    volumeSize.x++; volumeSize.y++; volumeSize.z++;
                    volumeRenderer.material.SetVector("_VolumeSize", (Vector3)volumeSize);

                    // NOTE - The following line passes transform.worldToLocalMatrix as a shader parameter. This is explicitly
                    // forbidden by the Unity docs which say:
                    //
                    //   IMPORTANT: If you're setting shader parameters you MUST use Renderer.worldToLocalMatrix instead.
                    //
                    // However, we don't have a renderer on this game object as the rendering is handled by the child OctreeNodes.
                    // The Unity doc's do not say why this is the case, but my best guess is that it is related to secret scaling
                    // which Unity may perform before sending data to the GPU (probably to avoid precision problems). See here:
                    //
                    //   http://forum.unity3d.com/threads/153328-How-to-reproduce-_Object2World
                    //
                    // It seems to work in our case, even with non-uniform scaling applied to the volume. Perhaps we are just geting
                    // lucky, pehaps it just works on our platform, or perhaps it is actually valid for some other reason. Just be aware.
                    volumeRenderer.material.SetMatrix("_World2Volume", transform.worldToLocalMatrix);
                }
            }

            if (data != null && data.volumeHandle.HasValue)
            {
                // When we are in game mode we limit the number of nodes which we update per frame, to maintain a nice.
                // framerate The Update() method is called repeatedly and so over time the whole mesh gets syncronized.
                if (Application.isPlaying)
                {
                    isMeshSyncronized = SynchronizeOctree(maxSyncOperationsInPlayMode);
                }
                else
                {
                    isMeshSyncronized = SynchronizeOctree(maxSyncOperationsInEditMode);
                }
            }
        }