public Redefine ( Axiom.Math.Vector3 rkNormal, Axiom.Math.Vector3 rkPoint ) : void | ||
rkNormal | Axiom.Math.Vector3 | Normal vector |
rkPoint | Axiom.Math.Vector3 | Point vector |
return | void |
public void CalculateMinLevelDist2( Real C ) #endif { //level 0 has no delta. this.mMinLevelDistSqr[ 0 ] = 0; int i, j; for ( var level = 1; level < this.mOptions.maxGeoMipMapLevel; level++ ) { this.mMinLevelDistSqr[ level ] = 0; var step = 1 << level; // The step of the next higher LOD var higherstep = step >> 1; #if AXIOM_SAFE_ONLY ITypePointer<float> pDeltas = null; #else float* pDeltas = null; #endif BufferBase dataPtr; if ( this.mOptions.lodMorph ) { // Create a set of delta values (store at index - 1 since 0 has none) this.mDeltaBuffers[ level - 1 ] = CreateDeltaBuffer(); // Lock, but don't discard (we want the pre-initialised zeros) dataPtr = this.mDeltaBuffers[ level - 1 ].Lock( BufferLocking.Normal ); pDeltas = dataPtr.ToFloatPointer(); } for ( j = 0; j < this.mOptions.tileSize - step; j += step ) { for ( i = 0; i < this.mOptions.tileSize - step; i += step ) { /* Form planes relating to the lower detail tris to be produced For tri lists and even tri strip rows, they are this shape: x---x | / | x---x For odd tri strip rows, they are this shape: x---x | \ | x---x */ var v1 = new Vector3( Vertex( i, j, 0 ), Vertex( i, j, 1 ), Vertex( i, j, 2 ) ); var v2 = new Vector3( Vertex( i + step, j, 0 ), Vertex( i + step, j, 1 ), Vertex( i + step, j, 2 ) ); var v3 = new Vector3( Vertex( i, j + step, 0 ), Vertex( i, j + step, 1 ), Vertex( i, j + step, 2 ) ); var v4 = new Vector3( Vertex( i + step, j + step, 0 ), Vertex( i + step, j + step, 1 ), Vertex( i + step, j + step, 2 ) ); Plane t1, t2; t1 = new Plane(); t2 = new Plane(); var backwardTri = false; if ( !this.mOptions.useTriStrips || j%2 == 0 ) { t1.Redefine( v1, v3, v2 ); t2.Redefine( v2, v3, v4 ); } else { t1.Redefine( v1, v3, v4 ); t2.Redefine( v1, v4, v2 ); backwardTri = true; } // include the bottommost row of vertices if this is the last row var zubound = ( j == ( this.mOptions.tileSize - step ) ? step : step - 1 ); for ( var z = 0; z <= zubound; z++ ) { // include the rightmost col of vertices if this is the last col var xubound = ( i == ( this.mOptions.tileSize - step ) ? step : step - 1 ); for ( var x = 0; x <= xubound; x++ ) { var fulldetailx = i + x; var fulldetailz = j + z; if ( fulldetailx%step == 0 && fulldetailz%step == 0 ) { // Skip, this one is a vertex at this level continue; } var zpct = (Real)z/(Real)step; var xpct = (Real)x/(Real)step; //interpolated height var actualPos = new Vector3( Vertex( fulldetailx, fulldetailz, 0 ), Vertex( fulldetailx, fulldetailz, 1 ), Vertex( fulldetailx, fulldetailz, 2 ) ); Real interp_h; // Determine which tri we're on if ( ( xpct + zpct <= 1.0f && !backwardTri ) || ( xpct + ( 1 - zpct ) <= 1.0f && backwardTri ) ) { // Solve for x/z interp_h = ( -( t1.Normal.x*actualPos.x ) - t1.Normal.z*actualPos.z - t1.D )/t1.Normal.y; } else { // Second tri interp_h = ( -( t2.Normal.x*actualPos.x ) - t2.Normal.z*actualPos.z - t2.D )/t2.Normal.y; } Real actual_h = Vertex( fulldetailx, fulldetailz, 1 ); //Check: not sure about fabs used here... Real delta = Math.Abs( interp_h - actual_h ); var D2 = delta*delta*C*C; if ( this.mMinLevelDistSqr[ level ] < D2 ) { this.mMinLevelDistSqr[ level ] = D2; } // Should be save height difference? // Don't morph along edges if ( this.mOptions.lodMorph && fulldetailx != 0 && fulldetailx != ( this.mOptions.tileSize - 1 ) && fulldetailz != 0 && fulldetailz != ( this.mOptions.tileSize - 1 ) ) { // Save height difference pDeltas[ (int)( fulldetailx + ( fulldetailz*this.mOptions.tileSize ) ) ] = interp_h - actual_h; } } } } } // Unlock morph deltas if required if ( this.mOptions.lodMorph ) { this.mDeltaBuffers[ level - 1 ].Unlock(); } } // Post validate the whole set for ( i = 1; i < this.mOptions.maxGeoMipMapLevel; i++ ) { // Make sure no LOD transition within the tile // This is especially a problem when using large tiles with flat areas /* Hmm, this can look bad on some areas, disable for now Vector3 delta(_vertex(0,0,0), mCenter.y, _vertex(0,0,2)); delta = delta - mCenter; Real minDist = delta.squaredLength(); mMinLevelDistSqr[ i ] = std::max(mMinLevelDistSqr[ i ], minDist); */ //make sure the levels are increasing... if ( this.mMinLevelDistSqr[ i ] < this.mMinLevelDistSqr[ i - 1 ] ) { this.mMinLevelDistSqr[ i ] = this.mMinLevelDistSqr[ i - 1 ]; } } // Now reverse traverse the list setting the 'next level down' Real lastDist = -1; var lastIndex = 0; for ( i = this.mOptions.maxGeoMipMapLevel - 1; i >= 0; --i ) { if ( i == this.mOptions.maxGeoMipMapLevel - 1 ) { // Last one is always 0 lastIndex = i; lastDist = this.mMinLevelDistSqr[ i ]; this.mNextLevelDown[ i ] = 0; } else { this.mNextLevelDown[ i ] = lastIndex; if ( this.mMinLevelDistSqr[ i ] != lastDist ) { lastIndex = i; lastDist = this.mMinLevelDistSqr[ i ]; } } } }
public void WidenRectByVector( Vector3 vec, Rectangle inRect, Real minHeight, Real maxHeight, ref Rectangle outRect ) { outRect = inRect; var p = new Plane(); switch ( Alignment ) { case Alignment.Align_X_Y: p.Redefine( Vector3.UnitZ, new Vector3( 0, 0, vec.z < 0.0f ? minHeight : maxHeight ) ); break; case Alignment.Align_X_Z: p.Redefine( Vector3.UnitY, new Vector3( 0, vec.y < 0.0f ? minHeight : maxHeight, 0 ) ); break; case Alignment.Align_Y_Z: p.Redefine( Vector3.UnitX, new Vector3( vec.x < 0.0f ? minHeight : maxHeight, 0, 0 ) ); break; } var verticalVal = vec.Dot( p.Normal ); if ( Utility.RealEqual( verticalVal, 0.0f ) ) { return; } var corners = new Vector3[4]; var startHeight = verticalVal < 0.0f ? maxHeight : minHeight; GetPoint( inRect.Left, inRect.Top, startHeight, ref corners[ 0 ] ); GetPoint( inRect.Right - 1, inRect.Top, startHeight, ref corners[ 1 ] ); GetPoint( inRect.Left, inRect.Bottom - 1, startHeight, ref corners[ 2 ] ); GetPoint( inRect.Right - 1, inRect.Bottom - 1, startHeight, ref corners[ 3 ] ); for ( int i = 0; i < 4; ++i ) { var ray = new Ray( corners[ i ] + this.mPos, vec ); var rayHit = ray.Intersects( p ); if ( rayHit.Hit ) { var pt = ray.GetPoint( rayHit.Distance ); // convert back to terrain point var terrainHitPos = Vector3.Zero; GetTerrainPosition( pt, ref terrainHitPos ); // build rectangle which has rounded down & rounded up values // remember right & bottom are exclusive var mergeRect = new Rectangle( (long)terrainHitPos.x*( this.mSize - 1 ), (long)terrainHitPos.y*( this.mSize - 1 ), (long)( terrainHitPos.x*(float)( this.mSize - 1 ) + 0.5f ) + 1, (long)( terrainHitPos.y*(float)( this.mSize - 1 ) + 0.5f ) + 1 ); outRect.Merge( mergeRect ); } } }
public PixelBox CalculateNormals( Rectangle rect, ref Rectangle outFinalRect ) { // Widen the rectangle by 1 element in all directions since height // changes affect neighbours normals var widenedRect = new Rectangle( Utility.Max( 0L, rect.Left - 1L ), Utility.Max( 0L, rect.Top - 1L ), Utility.Min( (long)this.mSize, rect.Right + 1L ), Utility.Min( (long)this.mSize, rect.Bottom + 1L ) ); // allocate memory for RGB var pData = new byte[widenedRect.Width*widenedRect.Height*3]; var pixbox = new PixelBox( (int)widenedRect.Width, (int)widenedRect.Height, 1, PixelFormat.BYTE_RGB, BufferBase.Wrap( pData ) ); // Evaluate normal like this // 3---2---1 // | \ | / | // 4---P---0 // | / | \ | // 5---6---7 var plane = new Plane(); for ( var y = widenedRect.Top; y < widenedRect.Bottom; ++y ) { for ( var x = widenedRect.Left; x < widenedRect.Right; ++x ) { var cumulativeNormal = Vector3.Zero; // Build points to sample var centrePoint = Vector3.Zero; var adjacentPoints = new Vector3[8]; GetPointFromSelfOrNeighbour( x, y, ref centrePoint ); GetPointFromSelfOrNeighbour( x + 1, y, ref adjacentPoints[ 0 ] ); GetPointFromSelfOrNeighbour( x + 1, y + 1, ref adjacentPoints[ 1 ] ); GetPointFromSelfOrNeighbour( x, y + 1, ref adjacentPoints[ 2 ] ); GetPointFromSelfOrNeighbour( x - 1, y + 1, ref adjacentPoints[ 3 ] ); GetPointFromSelfOrNeighbour( x - 1, y, ref adjacentPoints[ 4 ] ); GetPointFromSelfOrNeighbour( x - 1, y - 1, ref adjacentPoints[ 5 ] ); GetPointFromSelfOrNeighbour( x, y - 1, ref adjacentPoints[ 6 ] ); GetPointFromSelfOrNeighbour( x + 1, y - 1, ref adjacentPoints[ 7 ] ); for ( var i = 0; i < 8; ++i ) { plane.Redefine( centrePoint, adjacentPoints[ i ], adjacentPoints[ ( i + 1 )%8 ] ); cumulativeNormal += plane.Normal; } // normalise & store normal cumulativeNormal.Normalize(); // encode as RGB, object space // invert the Y to deal with image space var storeX = x - widenedRect.Left; var storeY = widenedRect.Bottom - y - 1; var pStore = ( ( storeY*widenedRect.Width ) + storeX )*3; pData[ pStore++ ] = (byte)( ( cumulativeNormal.x + 1.0f )*0.5f*255.0f ); pData[ pStore++ ] = (byte)( ( cumulativeNormal.y + 1.0f )*0.5f*255.0f ); pData[ pStore++ ] = (byte)( ( cumulativeNormal.z + 1.0f )*0.5f*255.0f ); } //x } //y outFinalRect = widenedRect; return pixbox; }
protected KeyValuePair<bool, Vector3> CheckQuadIntersection( int x, int z, Ray ray ) { // build the two planes belonging to the quad's triangles Vector3 v1 = new Vector3( x, this.mHeightData[ z + this.mSize*x ], z ), v2 = new Vector3( x + 1, this.mHeightData[ z + this.mSize*( x + 1 ) ], z ), v3 = new Vector3( x, this.mHeightData[ ( z + 1 ) + this.mSize*x ], z + 1 ), v4 = new Vector3( x + 1, this.mHeightData[ ( z + 1 ) + this.mSize*( x + 1 ) ], z + 1 ); Plane p1 = new Plane(), p2 = new Plane(); var oddRow = false; if ( z%2 != 0 ) { /* odd 3---4 | \ | 1---2 */ p1.Redefine( v2, v4, v3 ); p2.Redefine( v1, v2, v3 ); oddRow = true; } else { /* even 3---4 | / | 1---2 */ p1.Redefine( v1, v2, v4 ); p2.Redefine( v1, v4, v3 ); } // Test for intersection with the two planes. // Then test that the intersection points are actually // still inside the triangle (with a small error margin) // Also check which triangle it is in var planeInt = ray.Intersects( p1 ); if ( planeInt.Hit ) { var where = ray.GetPoint( planeInt.Distance ); var rel = where - v1; if ( rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 // quad bounds && ( ( rel.x >= rel.z && !oddRow ) || ( rel.x >= ( 1 - rel.z ) && oddRow ) ) ) // triangle bounds { return new KeyValuePair<bool, Vector3>( true, where ); } } planeInt = ray.Intersects( p2 ); if ( planeInt.Hit ) { var where = ray.GetPoint( planeInt.Distance ); var rel = where - v1; if ( rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 // quad bounds && ( ( rel.x <= rel.z && !oddRow ) || ( rel.x <= ( 1 - rel.z ) && oddRow ) ) ) // triangle bounds { return new KeyValuePair<bool, Vector3>( true, where ); } } return new KeyValuePair<bool, Vector3>( false, Vector3.Zero ); }
public Rectangle CalculateHeightDeltas( Rectangle rect ) { var clampedRect = new Rectangle( rect ); clampedRect.Left = Utility.Max( 0L, clampedRect.Left ); clampedRect.Top = Utility.Max( 0L, clampedRect.Top ); clampedRect.Right = Utility.Min( (long)this.mSize, clampedRect.Right ); clampedRect.Bottom = Utility.Min( (long)this.mSize, clampedRect.Bottom ); var finalRect = new Rectangle( clampedRect ); QuadTree.PreDeltaCalculation( clampedRect ); // Iterate over target levels, for ( var targetLevel = 1; targetLevel < NumLodLevels; ++targetLevel ) { var sourceLevel = targetLevel - 1; var step = 1 << targetLevel; // need to widen the dirty rectangle since change will affect surrounding // vertices at lower LOD var widendRect = rect; widendRect.Left = Utility.Max( 0L, widendRect.Left - step ); widendRect.Top = Utility.Max( 0L, widendRect.Top - step ); widendRect.Right = Utility.Min( (long)this.mSize, widendRect.Right + step ); widendRect.Bottom = Utility.Min( (long)this.mSize, widendRect.Bottom + step ); // keep a merge of the widest finalRect = finalRect.Merge( widendRect ); // now round the rectangle at this level so that it starts & ends on // the step boundaries var lodRect = new Rectangle( widendRect ); lodRect.Left -= lodRect.Left%step; lodRect.Top -= lodRect.Top%step; if ( lodRect.Right%step != 0 ) { lodRect.Right += step - ( lodRect.Right%step ); } if ( lodRect.Bottom%step != 0 ) { lodRect.Bottom += step - ( lodRect.Bottom%step ); } for ( var j = (int)lodRect.Top; j < lodRect.Bottom - step; j += step ) { for ( var i = (int)lodRect.Left; i < lodRect.Right - step; i += step ) { // Form planes relating to the lower detail tris to be produced // For even tri strip rows, they are this shape: // 2---3 // | / | // 0---1 // For odd tri strip rows, they are this shape: // 2---3 // | \ | // 0---1 var v0 = Vector3.Zero; var v1 = Vector3.Zero; var v2 = Vector3.Zero; var v3 = Vector3.Zero; GetPointAlign( i, j, Alignment.Align_X_Y, ref v0 ); GetPointAlign( i + step, j, Alignment.Align_X_Y, ref v1 ); GetPointAlign( i, j + step, Alignment.Align_X_Y, ref v2 ); GetPointAlign( i + step, j + step, Alignment.Align_X_Y, ref v3 ); var t1 = new Plane(); var t2 = new Plane(); var backwardTri = false; // Odd or even in terms of target level if ( ( j/step )%2 == 0 ) { t1.Redefine( v0, v1, v3 ); t2.Redefine( v0, v3, v2 ); } else { t1.Redefine( v1, v3, v2 ); t2.Redefine( v0, v1, v2 ); backwardTri = true; } //include the bottommost row of vertices if this is the last row var yubound = ( j == ( this.mSize - step ) ? step : step - 1 ); for ( var y = 0; y <= yubound; y++ ) { // include the rightmost col of vertices if this is the last col var xubound = ( i == ( this.mSize - step ) ? step : step - 1 ); for ( var x = 0; x <= xubound; x++ ) { var fulldetailx = i + x; var fulldetaily = j + y; if ( fulldetailx%step == 0 && fulldetaily%step == 0 ) { // Skip, this one is a vertex at this level continue; } var ypct = (Real)y/(Real)step; var xpct = (Real)x/(Real)step; //interpolated height var actualPos = Vector3.Zero; GetPointAlign( fulldetailx, fulldetaily, Alignment.Align_X_Y, ref actualPos ); Real interp_h = 0; // Determine which tri we're on if ( ( xpct > ypct && !backwardTri ) || ( xpct > ( 1 - ypct ) && backwardTri ) ) { // Solve for x/z interp_h = ( -t1.Normal.x*actualPos.x - t1.Normal.y*actualPos.y - t1.D )/t1.Normal.z; } else { // Second tri interp_h = ( -t2.Normal.x*actualPos.x - t2.Normal.y*actualPos.y - t2.D )/t2.Normal.z; } var actual_h = actualPos.z; var delta = interp_h - actual_h; // max(delta) is the worst case scenario at this LOD // compared to the original heightmap if ( delta == float.NaN ) { } // tell the quadtree about this QuadTree.NotifyDelta( (ushort)fulldetailx, (ushort)fulldetaily, (ushort)sourceLevel, delta ); // If this vertex is being removed at this LOD, // then save the height difference since that's the move // it will need to make. Vertices to be removed at this LOD // are halfway between the steps, but exclude those that // would have been eliminated at earlier levels int halfStep = step/2; if ( ( ( fulldetailx%step ) == halfStep && ( fulldetaily%halfStep ) == 0 ) || ( ( fulldetaily%step ) == halfStep && ( fulldetailx%halfStep ) == 0 ) ) { #if !AXIOM_SAFE_ONLY unsafe #endif { // Save height difference var pDest = GetDeltaData( fulldetailx, fulldetaily ).ToFloatPointer(); pDest[ 0 ] = delta; } } } //x } //y } } //j } //targetlevel QuadTree.PostDeltaCalculation( clampedRect ); return finalRect; }
public float GetHeightAtTerrainPosition( Real x, Real y ) { // get left / bottom points (rounded down) Real factor = this.mSize - 1; Real invFactor = 1.0f/factor; var startX = (long)( x*factor ); var startY = (long)( y*factor ); var endX = startX + 1; var endY = startY + 1; // now get points in terrain space (effectively rounding them to boundaries) // note that we do not clamp! We need a valid plane Real startXTS = startX*invFactor; Real startYTS = startY*invFactor; Real endXTS = endX*invFactor; Real endYTS = endY*invFactor; //now clamp endX = Utility.Min( endX, (long)this.mSize - 1 ); endY = Utility.Min( endY, (long)this.mSize - 1 ); // get parametric from start coord to next point Real xParam = ( x - startXTS )/invFactor; Real yParam = ( y - startYTS )/invFactor; /* For even / odd tri strip rows, triangles are this shape: even odd 3---2 3---2 | / | | \ | 0---1 0---1 */ // Build all 4 positions in terrain space, using point-sampled height var v0 = new Vector3( startXTS, startYTS, GetHeightAtPoint( startX, startY ) ); var v1 = new Vector3( endXTS, startYTS, GetHeightAtPoint( endX, startY ) ); var v2 = new Vector3( endXTS, endYTS, GetHeightAtPoint( endX, endY ) ); var v3 = new Vector3( startXTS, endYTS, GetHeightAtPoint( startX, endY ) ); //define this plane in terrain space var plane = new Plane(); if ( startY%2 != 0 ) { //odd row var secondTri = ( ( 1.0f - yParam ) > xParam ); if ( secondTri ) { plane.Redefine( v0, v1, v3 ); } else { plane.Redefine( v1, v2, v3 ); } } else { //even row var secondtri = ( yParam > xParam ); if ( secondtri ) { plane.Redefine( v0, v2, v3 ); } else { plane.Redefine( v0, v1, v2 ); } } //solve plane quation for z return ( -plane.Normal.x*x - plane.Normal.y*y - plane.D )/plane.Normal.z; }