/// <summary> /// Setup constructor /// </summary> /// <param name="camera">Camera, used to determine patch error</param> /// <param name="generator">Object used to generate the patch vertices</param> /// <param name="patch">Terrain patch</param> /// <param name="calculatePatchError">If true, the maximum error between the patch geometry and the terrain model is calculated</param> private unsafe TerrainPatchBuildItem( IProjectionCamera camera, ITerrainPatchGenerator generator, ITerrainPatch patch, bool calculatePatchError ) { m_Camera = camera; m_Generator = generator; m_Patch = patch; m_CalculatePatchError = calculatePatchError; }
/// <summary> /// Allocates a terrain patch build item from an internal pool /// </summary> public static TerrainPatchBuildItem Allocate( IProjectionCamera camera, ITerrainPatchGenerator generator, ITerrainPatch patch, bool calculatePatchError ) { if ( s_BuildItems.Count == 0 ) { return new TerrainPatchBuildItem( camera, generator, patch, calculatePatchError ); } TerrainPatchBuildItem item = s_BuildItems[ 0 ]; s_BuildItems.RemoveAt( 0 ); item.m_Camera = camera; item.m_Generator = generator; item.m_Patch = patch; item.m_CalculatePatchError = calculatePatchError; return item; }
private void ReduceDetail( ITerrainPatchGenerator generator, IProjectionCamera camera ) { Build( generator, camera ); }
/// <summary> /// Increases the detail of this paqtch /// </summary> private void IncreaseDetail( ITerrainPatchGenerator generator, IProjectionCamera camera ) { if ( m_CachedChildren != null ) { // Child nodes have already been created - they just need new vertex buffers m_PendingChildren = m_CachedChildren; m_CachedChildren = null; } else { Vector3 uOffset = m_LocalUAxis * 0.5f; Vector3 vOffset = m_LocalVAxis * 0.5f; float error = m_PatchError / 2; // float error = float.MaxValue;// Use this value to force a recalculation of the patch error float uvRes = m_UvRes / 2; Point2 tlUv = m_Uv; Point2 trUv = m_Uv + new Vector2( uvRes, 0 ); Point2 brUv = m_Uv + new Vector2( uvRes, uvRes ); Point2 blUv = m_Uv + new Vector2( 0, uvRes ); TerrainPatch tl = new TerrainPatch( this, m_Vertices, m_LocalOrigin, uOffset, vOffset, error, tlUv,uvRes ); TerrainPatch tr = new TerrainPatch( this, m_Vertices, m_LocalOrigin + uOffset, uOffset, vOffset, error, trUv, uvRes ); TerrainPatch bl = new TerrainPatch( this, m_Vertices, m_LocalOrigin + vOffset, uOffset, vOffset, error, blUv, uvRes ); TerrainPatch br = new TerrainPatch( this, m_Vertices, m_LocalOrigin + uOffset + vOffset, uOffset, vOffset, error, brUv, uvRes ); m_PendingChildren = new TerrainPatch[] { tl, tr, bl, br }; } foreach ( TerrainPatch patch in m_PendingChildren ) { patch.Build( generator, camera ); } }
/// <summary> /// Queues up a work item to builds this patch's vertex and index buffers /// </summary> private void Build( ITerrainPatchGenerator generator, IProjectionCamera camera ) { m_Building = true; TerrainPatchBuildItem builder = TerrainPatchBuildItem.Allocate( camera, generator, this, ( PatchError == float.MaxValue ) ); TerrainPatchBuilder.QueueWork( builder ); }
/// <summary> /// Updates the level of detail of this patch. /// </summary> public void UpdateLod( Point3 cameraPos, ITerrainPatchGenerator generator, IProjectionCamera camera ) { if ( m_IncreaseDetailDistance == float.MaxValue ) { // Detail up distance has not been calculated for this patch yet - exit return; } float distanceToPatch = AccurateDistanceToPatch( cameraPos, PatchCentre, m_Radius ); m_DistToPatch = distanceToPatch; if ( distanceToPatch < m_IncreaseDetailDistance ) { if ( IsLeafNode ) { IncreaseDetail( generator, camera ); } else if ( m_Children != null ) { foreach ( TerrainPatch childPatch in m_Children ) { childPatch.UpdateLod( cameraPos, generator, camera ); } } } else if ( distanceToPatch > m_IncreaseDetailDistance ) { if ( !IsLeafNode && CanReduceDetail ) { ReduceDetail( generator, camera ); } } }
/// <summary> /// Updates this patch /// </summary> public void Update( IProjectionCamera camera, ITerrainPatchGenerator generator ) { if ( m_Children != null ) { foreach ( TerrainPatch childPatch in m_Children ) { childPatch.Update( camera, generator ); } } else { // Bodge to generate vertices (blocking) on the first frame if ( m_Parent == null && m_VbIndex == -1 && m_IncreaseDetailDistance == float.MaxValue ) { TerrainPatchBuildItem builder = TerrainPatchBuildItem.Allocate( camera, generator, this, ( PatchError == float.MaxValue ) ); builder.Build( ); } } }