// 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); }
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); } } }