/// <summary> /// Gets the tangent plane at the specified position /// </summary> public Plane3 GetTangentPlaneUnderPoint( UniPoint3 pos, out Point3 pointOnPlane ) { Vector3 normal = Planet.Transform.Position.VectorTo( pos ).MakeNormal( ); Vector3 vec = normal * ( Planet.Model.Radius + m_GeometryRadius ).ToRenderUnits; pointOnPlane = vec.ToPoint3( ); return new Plane3( pointOnPlane, normal ); }
/// <summary> /// Setup constructor, from basis vectors and a translation /// </summary> public InvariantMatrix44( Vector3 xAxis, Vector3 yAxis, Vector3 zAxis, Point3 pos ) { m_Elements[ 0 ] = xAxis.X; m_Elements[ 1 ] = xAxis.Y; m_Elements[ 2 ] = xAxis.Z; m_Elements[ 3 ] = 0; m_Elements[ 4 ] = yAxis.X; m_Elements[ 5 ] = yAxis.Y; m_Elements[ 6 ] = yAxis.Z; m_Elements[ 7 ] = 0; m_Elements[ 8 ] = zAxis.X; m_Elements[ 9 ] = zAxis.Y; m_Elements[ 10 ] = zAxis.Z; m_Elements[ 11 ] = 0; m_Elements[ 12 ] = pos.X; m_Elements[ 13 ] = pos.Y; m_Elements[ 14 ] = pos.Z; m_Elements[ 15 ] = 1; }
public Collision( Point3 pt, Vector3 normal, float dist, float t ) { m_Point = pt; m_Normal = normal; m_Distance = dist; m_T = t; }
/// <summary> /// Sets up this modifier /// </summary> /// <param name="owner">Positioning interface of the game object</param> /// <param name="pos">Position to place the new object at</param> public PositionModifier( object owner, Point3 pos ) { m_Owner = owner; Position = pos; IRayCastService rayCaster = EditorState.Instance.CurrentScene.GetService< IRayCastService >( ); rayCaster.AddIntersector( RayCastLayers.Entity, this ); }
/// <summary> /// Sets up this modifier /// </summary> /// <param name="owner">Positioning interface of the game object</param> /// <param name="pos">Position to place the new object at</param> /// <param name="angle">Initial angle</param> public AngleModifier( object owner, Point3 pos, float angle ) { m_Owner = owner; m_Centre = pos; m_Angle = angle; m_Spinner = CalculateSpinnerPosition( ); IRayCastService rayCaster = EditorState.Instance.CurrentScene.GetService< IRayCastService >( ); rayCaster.AddIntersector( RayCastLayers.Entity, this ); }
public AtmosphereCalculator( Point3 cameraPos, AtmosphereCalculatorModel model ) { m_CameraPos = cameraPos; m_Model = model; m_Inner = new Sphere3( Point3.Origin, model.PlanetRadius ); m_Outer = new Sphere3( Point3.Origin, model.AtmosphereRadius ); float heightRange = model.AtmosphereRadius - model.PlanetRadius; m_InvRH0 = -1.0f / ( heightRange * model.RayleighDensityScaleHeightFraction ); m_InvMH0 = -1.0f / ( heightRange * model.MieDensityScaleHeightFraction ); }
/// <summary> /// Sets up the path walk state /// </summary> /// <param name="path">Path to walk</param> /// <param name="pt">Position of the object about to walk the path</param> /// <exception cref="ArgumentNullException">Thrown if path is null</exception> public PathWalkState( IPath path, Point3 pt ) { if ( path == null ) { throw new ArgumentNullException( "path" ); } m_Path = path; m_T = path.GetClosestPoint( pt ); path.GetFrame( m_T, out m_Point, out m_Direction ); }
public Projectile( Scene scene, Point3 start, Vector3 dir, float speed ) { m_Pos.Set( start ); m_Dir = dir; m_Speed = speed; m_Scene = scene; m_Scene.Renderables.Add( this ); IUpdateService updater = scene.GetService< IUpdateService >( ); updater[ "updateClock" ].Subscribe( Update ); }
/// <summary> /// Returns a time value on the line that minimises the distance to pt /// </summary> public static float GetClosestTimeOnLine( Point3 start, Point3 end, Point3 pt ) { Vector3 lineVec = end - start; float sqrLength = lineVec.SqrLength; float t = 0.0f; if ( sqrLength != 0.0f ) { t = Utils.Clamp( ( pt - start).Dot( lineVec ) / sqrLength, 0.0f, 1.0f ); } return t; }
/// <summary> /// Creates a pick ray from a screen position /// </summary> /// <param name="x">Screen X position</param> /// <param name="y">Screen Y position</param> /// <returns>Returns world ray</returns> public Ray3 PickRay( int x, int y ) { Matrix44 matrix = m_InvProjView; float width = Graphics.Renderer.Viewport.Width; float height = Graphics.Renderer.Viewport.Height; Point3 pt = new Point3( ( 2 * x / width ) - 1, ( 2 * ( height - y ) / height ) - 1, 1.0f ); Point3 invPt = matrix.HomogenousMultiply( pt ); Point3 camPos = Frame.Translation; Ray3 result = new Ray3( camPos, ( invPt - camPos ).MakeNormal( ) ); return result; }
/// <summary> /// Creates 8 corner points for a cube with a half-width of hDim /// </summary> private static Point3[] CreateCubeCorners( float hDim ) { Point3[] corners = new Point3[] { new Point3( -hDim, -hDim, -hDim ), new Point3( +hDim, -hDim, -hDim ), new Point3( +hDim, +hDim, -hDim ), new Point3( -hDim, +hDim, -hDim ), new Point3( -hDim, -hDim, +hDim ), new Point3( +hDim, -hDim, +hDim ), new Point3( +hDim, +hDim, +hDim ), new Point3( -hDim, +hDim, +hDim ), }; return corners; }
public Collision CheckMovement( Point3 pos, Vector3 move ) { if ( m_Root == null ) { return null; } Point3 end3 = pos + move; Point2 start = new Point2( pos.X, pos.Z ); Point2 end = new Point2( end3.X, end3.Z ); float collisionT = 0; Vector2 collisionNormal = Vector2.XAxis; if ( !m_Root.Check( start, end, 0, 1, ref collisionT, ref collisionNormal ) ) { return null; } return new Collision( pos + move * collisionT, new Vector3( collisionNormal.X, 0, collisionNormal.Y ), move.Length * collisionT, collisionT ); }
/// <summary> /// Gets the position and tangent on the path at time t /// </summary> public void GetFrame( float t, out Point3 pt, out Vector3 dir ) { int ptIndex = ( int )t; if ( ptIndex == m_Points.Length - 1 ) { pt = m_Points[ ptIndex ]; dir = ( m_Points[ ptIndex ] - m_Points[ ptIndex - 1 ] ).MakeNormal( ); return; } float localT = t - ptIndex; Point3 start = m_Points[ ptIndex ]; Point3 end = m_Points[ ptIndex + 1 ]; pt = LineSegment3.GetPointOnLine( start, end, localT ); dir = ( end - start ).MakeNormal( ); }
/// <summary> /// Adds patches that cover the side of a cube /// </summary> /// <param name="res">Patch resolution (res*res patches cover the cube side)</param> /// <param name="topLeft">The top left corner of the cube side</param> /// <param name="topRight">The top right corner of the cube side</param> /// <param name="bottomLeft">The bottom left corner of the cube side</param> /// <param name="uvRes">The UV resolution of the cube patch</param> private void AddCubeSidePatches( int res, Point3 topLeft, Point3 topRight, Point3 bottomLeft, float uvRes ) { Vector3 xAxis = ( topRight - topLeft ); Vector3 yAxis = ( bottomLeft - topLeft ); Vector3 xInc = xAxis / res; Vector3 yInc = yAxis / res; Point3 rowStart = topLeft; for ( int row = 0; row < res; ++row ) { Point3 curPos = rowStart; for ( int col = 0; col < res; ++col ) { TerrainPatch newPatch = new TerrainPatch( Vertices, curPos, xInc, yInc, new Point2( 0, 0 ), uvRes ); RootPatches.Add( newPatch ); curPos += xInc; } rowStart += yInc; } }
/// <summary> /// Gets the closest point to pt on the path /// </summary> public float GetClosestPoint( Point3 pt ) { float closestDistance = float.MaxValue; float closestT = 0; for ( int pointIndex = 0; pointIndex < m_Points.Length - 1; ++pointIndex ) { Point3 start = m_Points[ pointIndex ]; Point3 end = m_Points[ pointIndex + 1 ]; float t = LineSegment3.GetClosestTimeOnLine( start, end, pt ); float distance = LineSegment3.GetPointOnLine( start, end, t ).DistanceTo( pt ); if ( distance < closestDistance ) { closestDistance = distance; closestT = ( pointIndex - 1 ) + t; } } return closestT; }
/// <summary> /// Called when a edge list is finished /// </summary> protected override void OnFinished( Point3[] points, bool loop ) { try { LevelGeometry level = LevelGeometry.FromCurrentScene( ); Point2[] points2 = new Point2[ points.Length ]; for ( int ptIndex = 0; ptIndex < points.Length; ++ptIndex ) { points2[ ptIndex ] = new Point2( points[ ptIndex ].X, points[ ptIndex ].Z ); } UiPolygon brush = new UiPolygon( "", points2 ); level.Add( brush, false, false ); AppLog.Info( "Combined brush with current level geometry" ); } catch ( Exception ex ) { AppLog.Exception( ex, "Failed to combine brush with current level geometry" ); ErrorMessageBox.Show( Resources.FailedToCombineCsgBrush ); } }
public void SetBounds( Point3 topLeft, Point3 topRight, Point3 bottomLeft ) { m_TopLeft = topLeft; m_TopRight = topRight; m_BottomLeft = bottomLeft; m_PatchXDir = m_TopRight - m_TopLeft; m_PatchZDir = m_BottomLeft - m_TopLeft; m_PatchWidth = m_PatchXDir.Length; m_PatchHeight = m_PatchZDir.Length; m_PatchXDir /= m_PatchWidth; m_PatchZDir /= m_PatchHeight; }
/// <summary> /// Sets up the node /// </summary> /// <param name="parent">Node parent</param> /// <param name="edge">Node edge</param> public BspNode( BspNode parent, Edge edge ) { m_Parent = parent; m_Edge = edge; m_Quad[ 0 ] = new Point3( edge.P0.X, 0, edge.P0.Y ); m_Quad[ 1 ] = new Point3( edge.P1.X, 0, edge.P1.Y ); m_Quad[ 2 ] = new Point3( edge.P1.X, 5, edge.P1.Y ); m_Quad[ 3 ] = new Point3( edge.P0.X, 5, edge.P0.Y ); }
private float Height( Point3 pt ) { return Utils.Clamp( pt.DistanceTo( Point3.Origin ) - m_InnerRadius, 0, m_OuterRadius - m_InnerRadius ); }
private bool GetRayPlanetAndAtmosphereIntersection( Point3 origin, Vector3 dir, out Point3 intPt ) { // TODO: AP: Optimise ray intersection code (origin is always outside inner sphere, inside outer sphere) Ray3 ray = new Ray3( origin, dir ); Line3Intersection innerIntersection = Intersections3.GetRayIntersection( ray, m_InnerSphere ); Line3Intersection outerIntersection = Intersections3.GetRayIntersection( ray, m_OuterSphere ); if ( innerIntersection == null ) { if ( outerIntersection == null ) { // This should not happen, but there may be an edge condition intPt = Point3.Origin; return false; } intPt = outerIntersection.IntersectionPosition; return true; } if ( ( outerIntersection == null ) || ( innerIntersection.Distance < outerIntersection.Distance ) ) { intPt = innerIntersection.IntersectionPosition; return true; } intPt = outerIntersection.IntersectionPosition; return true; }
private bool GetRayAtmosphereIntersection( Point3 origin, Vector3 dir, out Point3 intPt ) { intPt = origin; float factor = 0.0001f; float fRadius = m_OuterSphere.Radius * factor; float fSqrRadius = fRadius * fRadius; Vector3 originToCentre = new Vector3( origin.X * factor, origin.Y * factor, origin.Z * factor ); float a0 = originToCentre.SqrLength - fSqrRadius; if ( a0 > 0 ) { return false; } // 1 intersection: The origin of the ray is inside the sphere float a1 = dir.Dot( originToCentre ); float discriminant = ( a1 * a1 ) - a0; float t = -a1 + Functions.Sqrt( discriminant ); intPt = origin + dir * ( t / factor ); return true; }
/// <summary> /// Computes the in-scattering term for a given sun angle, viewer orientation, and height. Stores /// the result in a 3-component voxel /// </summary> private unsafe void ComputeScattering( Vector3 viewDir, Vector3 sunDir, float height, byte* voxel ) { // Iv(t) = Is(t) (K.Fr(s)/t^4) E(i=0..k) p.exp(-Tl-Tv) // Where: // t = wavelength of incident light at viewpoint // s = scattering angle between viewer and incident light // Iv = Intensity of light of given wavelength at viewer // Is = Intensity of incident light of given wavelength // K = Constant molecular density at sea level: // 2pi^2(n^2 - 1)^2/3.Ns // Where: // n = Index of refraction of the air // Ns = Molecular number density of the standard atmosphere // Fr(s) = Scattering phase function // 3/4(1 + cos2(s)) // p = Density ratio: // exp(-h/H0) // Where: // h = height // H0 = 7994m (thickness of atmosphere if density is uniform) // k = number of samples to take along view vector // // // Alternative phase function (Henyey-Greenstein function): // F(th, g) = 3(1-g^2)/(2(2+g^2)) . (1+cos^2(th))/(1+g^2 - 2.g.cos(th))^3/2 // // g is asymmetry factor: // g = 5/9u - (4/3 - 25/81u^2)x^-1/3 + x^1/3 // // x = 5/u + 125/729u^3 + (64/27 - 325/243u^2 + 1250/2187u^4)^1/2 // u = haze factor and wavelength (0.7-0.85) // float cosSunAngle = Functions.Cos( sunAngle ); Point3 viewPos = new Point3( 0, height, 0 ); Point3 viewEnd; GetRayPlanetAndAtmosphereIntersection( viewPos, viewDir, out viewEnd ); // GetRayAtmosphereIntersection( viewPos, viewDir, out viewEnd ); // The summation of attenuation is a Reimann sum approximation of the integral // of atmospheric density . Vector3 vecToPt = viewEnd - viewPos; Vector3 sampleStep = vecToPt / m_AttenuationSamples; float mul = sampleStep.Length * m_InscatterDistanceFudgeFactor; if ( mul < 0.00001f ) { voxel[ 0 ] = voxel[ 1 ] = voxel[ 2 ] = voxel[ 3 ] = 0; return; } float* rAccum = stackalloc float[ 3 ]; float* mAccum = stackalloc float[ 3 ]; float* rViewOutScatter = stackalloc float[ 3 ]; float* mViewOutScatter = stackalloc float[ 3 ]; float* rSunOutScatter = stackalloc float[ 3 ]; float* mSunOutScatter = stackalloc float[ 3 ]; Point3 samplePos = viewPos + sampleStep; for ( int sampleCount = 1; sampleCount < m_AttenuationSamples; ++sampleCount, samplePos += sampleStep ) { // Cast a ray to the sun Point3 sunPt; if ( !GetRayPlanetAndAtmosphereIntersection( samplePos, sunDir, out sunPt ) ) // if ( !GetRayAtmosphereIntersection( samplePos, sunDir, out sunPt ) ) { continue; } float sampleHeight = Height( samplePos ); float pRCoeff = Functions.Exp( sampleHeight * m_InvRH0 ) * mul; float pMCoeff = Functions.Exp( sampleHeight * m_InvMH0 ) * mul; // Calculate (wavelength-dependent) out-scatter terms Vector3 viewStep = ( viewPos - samplePos ) / m_AttenuationSamples; Vector3 sunStep = ( sunPt - samplePos ) / m_AttenuationSamples; CalculateOutScatter( samplePos, sunStep, rSunOutScatter, mSunOutScatter ); CalculateOutScatter( samplePos, viewStep, rViewOutScatter, mViewOutScatter ); for ( int i = 0; i < 3; ++i ) { float outScatterR = Functions.Exp( ( -rViewOutScatter[ i ] - rSunOutScatter[ i ] ) ); float outScatterM = Functions.Exp( ( -mViewOutScatter[ i ] - mSunOutScatter[ i ] ) ); mAccum[ i ] += pMCoeff * outScatterM; rAccum[ i ] += pRCoeff * outScatterR; } } float tR = ( float )Math.Sqrt( rAccum[ 0 ] * m_RayleighCoefficients[ 0 ] ); float tG = ( float )Math.Sqrt( rAccum[ 1 ] * m_RayleighCoefficients[ 1 ] ); float tB = ( float )Math.Sqrt( rAccum[ 2 ] * m_RayleighCoefficients[ 2 ] ); float tA = ( float )Math.Sqrt( ( ( mAccum[ 0 ] * m_MieCoefficients[ 0 ] ) + ( mAccum[ 1 ] * m_MieCoefficients[ 1 ] ) + ( mAccum[ 2 ] * m_MieCoefficients[ 2 ] ) ) / 3 ); // TODO: AP: Fix stupid backwards textures :( voxel[ 3 ] = ( byte )Utils.Clamp( tR * 255, 0, 255 ); voxel[ 2 ] = ( byte )Utils.Clamp( tG * 255, 0, 255 ); voxel[ 1 ] = ( byte )Utils.Clamp( tB * 255, 0, 255 ); voxel[ 0 ] = ( byte )Utils.Clamp( tA * 255, 0, 255 ); }
private unsafe void CalculateOutScatter( Point3 startPt, Vector3 step, float* rOutScatter, float* mOutScatter ) { float mul = step.Length * m_OutscatterDistanceFudgeFactor; Point3 samplePt = startPt; float rAccum = 0; float mAccum = 0; for ( int sample = 0; sample < m_AttenuationSamples; ++sample ) { // float samplePtHeight = samplePt.DistanceTo( Point3.Origin ) - m_Inner.Radius; // samplePtHeight = Utils.Max( samplePtHeight, 0 ); float samplePtHeight = Height( samplePt ); float samplePtRCoeff = Functions.Exp( samplePtHeight * m_InvRH0 ); float samplePtMCoeff = Functions.Exp( samplePtHeight * m_InvMH0 ); rAccum += samplePtRCoeff * mul; mAccum += samplePtMCoeff * mul; samplePt += step; } for ( int i = 0; i < 3; ++i ) { rOutScatter[ i ] = m_RayleighCoefficients[ i ] * rAccum; mOutScatter[ i ] = m_MieCoefficients[ i ] * mAccum; } }
/// <summary> /// Builds a 2D lookup texture containing optical depth for a paramerization of the view frame /// </summary> /// <param name="buildParams">Atmosphere build parameters</param> /// <param name="pixels">Atmosphere texture pixels</param> /// <param name="progress">Progress indicator</param> /// <returns>Returns true if the build completed (wasn't cancelled)</returns> private unsafe bool BuildOpticalDepthTexture( AtmosphereBuildParameters buildParams, byte* pixels, AtmosphereBuildProgress progress ) { // TODO: AP: Because we know that the view to pos angle range will never be > pi, can optimise this later int viewSamples = buildParams.OpticalDepthResolution; int heightSamples = buildParams.OpticalDepthResolution; float viewAngleInc = Constants.Pi / ( viewSamples - 1 ); float heightRange = ( m_OuterRadius - m_InnerRadius ); float heightInc = ( heightRange * 0.9999f ) / ( heightSamples - 1 ); // Push height range in slightly to allow simplification of sphere intersections float* rAccum = stackalloc float[ 3 ]; float* mAccum = stackalloc float[ 3 ]; float height = m_InnerRadius; for ( int heightSample = 0; heightSample < heightSamples; ++heightSample, height += heightInc ) { Point3 pos = new Point3( 0, height, 0 ); // Start the view angle at pi, and count down to 0. This is because it is quickest to address // the 2D texture using the dot of the view vector and the view position, saving a (1-th) operation float viewAngle = Constants.Pi; Point3 lastAtmInt = pos; for ( int viewSample = 0; viewSample < viewSamples; ++viewSample, viewAngle -= viewAngleInc ) { Vector3 viewDir = new Vector3( Functions.Sin( viewAngle ), Functions.Cos( viewAngle ), 0 ); // NOTE: If ray intersection fails, the previous intersection position is used... Point3 atmInt; // if ( !GetRayPlanetAndAtmosphereIntersection( pos, viewDir, out atmInt ) ) if ( !GetRayAtmosphereIntersection( pos, viewDir, out atmInt ) ) { atmInt = lastAtmInt; } else { lastAtmInt = atmInt; } Vector3 step = ( atmInt - pos ) / m_AttenuationSamples; rAccum[ 0 ] = rAccum[ 1 ] = rAccum[ 2 ] = 0; mAccum[ 0 ] = mAccum[ 1 ] = mAccum[ 2 ] = 0; CalculateOutScatter( pos, step, rAccum, mAccum ); // float oR = CalculateCombinedOutScatter( pos, step, m_RayleighCoefficients[ 0 ], m_MieCoefficients[ 0 ] ); // float oG = CalculateCombinedOutScatter( pos, step, m_RayleighCoefficients[ 1 ], m_MieCoefficients[ 1 ] ); // float oB = CalculateCombinedOutScatter( pos, step, m_RayleighCoefficients[ 2 ], m_MieCoefficients[ 2 ] ); float attR = ExtinctionCoefficient( rAccum[ 0 ], mAccum[ 0 ] ); float attG = ExtinctionCoefficient( rAccum[ 1 ], mAccum[ 1 ] ); float attB = ExtinctionCoefficient( rAccum[ 2 ], mAccum[ 2 ] ); pixels[ 2 ] = ( byte )( Utils.Clamp( attR, 0, 1 ) * 255.0f ); pixels[ 1 ] = ( byte )( Utils.Clamp( attG, 0, 1 ) * 255.0f ); pixels[ 0 ] = ( byte )( Utils.Clamp( attB, 0, 1 ) * 255.0f ); pixels += 3; } if ( progress != null ) { progress.OnSliceCompleted( heightSample / ( float )( heightSamples - 1 ) ); if ( progress.Cancel ) { return false; } } } return true; }
/// <summary> /// Gets a point on the line /// </summary> /// <param name="start">Start point of the line</param> /// <param name="end">End point of the line</param> /// <param name="t">Fraction along the line (0==start, 1==end)</param> /// <returns>Returns the evaluated point on the line</returns> public static Point3 GetPointOnLine( Point3 start, Point3 end, float t ) { return start + ( end - start ) * t; }
/// <summary> /// Setup initialisation (spotlight at pos, looking towards lookAt) /// </summary> public SpotLight( Point3 pos, Point3 lookAt ) { Position = pos; Direction = ( lookAt - pos ).MakeNormal( ); }
/// <summary> /// Setup initialisation (spotlight at pos, looking along direction) /// </summary> public SpotLight( Point3 pos, Vector3 direction ) { Position = pos; Direction = direction; }
/// <summary> /// Zero length line at the origin /// </summary> public LineSegment3( ) { m_Start = new Point3( ); m_End = new Point3( ); }
/// <summary> /// Setup initialisation (spotlight at pos, looking towards lookAt) /// </summary> public SpotLight( Point3 pos, Point3 lookAt, float arcDegrees ) { Position = pos; Direction = ( lookAt - pos ).MakeNormal( ); m_Arc = arcDegrees; }
/// <summary> /// Sets the start and end points of the line /// </summary> public LineSegment3( Point3 start, Point3 end ) { Set( start, end ); }