public void Combine(AABB a, AABB b) { m_Min = a.m_Min; m_Min.Min(b.m_Min); m_Max = a.m_Max; m_Max.Max(b.m_Max); }
public Mesh(Scene _Owner, idTech5Map.Map.Entity _Entity) : base(_Owner, _Entity) { // BUild primitives and local space BBox m_Primitives = new Primitive[_Entity.m_Model.m_Surfaces.Length]; m_BBoxMin_Local = float.MaxValue * float3.One; m_BBoxMax_Local = -float.MaxValue * float3.One; int PrimitiveIndex = 0; foreach (idTech5Map.Model.Surface S in _Entity.m_Model.m_Surfaces) { m_Primitives[PrimitiveIndex] = new Primitive(this, S); m_BBoxMin_Local.Min(m_Primitives[PrimitiveIndex].m_BBoxMin); m_BBoxMax_Local.Max(m_Primitives[PrimitiveIndex].m_BBoxMax); PrimitiveIndex++; } // Convert BBox to world space m_BBoxMin_World = float.MaxValue * float3.One; m_BBoxMax_World = -float.MaxValue * float3.One; for (int CornerIndex = 0; CornerIndex < 8; CornerIndex++) { float X = (CornerIndex >> 0) & 1; float Y = (CornerIndex >> 0) & 1; float Z = (CornerIndex >> 0) & 1; float3 D = m_BBoxMax_Local - m_BBoxMin_Local; float3 lsCorner = m_BBoxMin_Local + new float3(X * D.x, Y * D.y, Z * D.z); float3 wsCorner = (float3)(new float4(lsCorner, 1.0f) * m_Local2Parent); m_BBoxMin_World.Min(wsCorner); m_BBoxMax_World.Max(wsCorner); } }
/// <summary> /// Inserts an AABB in the tree, ensuring leaf-containing tree cells have at most the minimum dimension of the AABB /// </summary> /// <param name="_Min">The minimum corner of the AABB</param> /// <param name="_Max">The maximum corner of the AABB</param> /// <returns></returns> internal void InsertAABB(float3 _Min, float3 _Max) { float3 Dim = _Max - _Min; float MinSize = Dim.Min(); if (m_Size < MinSize || m_Size <= MIN_CELL_SIZE) { return; // This cell is already too small } // Recurse through children float ChildSize = 0.5f * m_Size; float3 P; for (int Z = 0; Z < 2; Z++) { P.z = m_Min.z + Z * ChildSize; float nz = P.z + ChildSize; if (_Min.z >= nz || _Max.z < P.z) { continue; // Easy early out } for (int Y = 0; Y < 2; Y++) { P.y = m_Min.y + Y * ChildSize; float ny = P.y + ChildSize; if (_Min.y >= ny || _Max.y < P.y) { continue; // Easy early out } for (int X = 0; X < 2; X++) { P.x = m_Min.x + X * ChildSize; float nx = P.x + ChildSize; if (_Min.x >= nx || _Max.x < P.x) { continue; // Easy early out } if (m_Children[X, Y, Z] == null) { // Create the child Cell Child = new Cell() { m_Parent = this, m_Min = P, m_Size = ChildSize, }; m_Children[X, Y, Z] = Child; } // Recurse m_Children[X, Y, Z].InsertAABB(_Min, _Max); } } } }
void TestSHRGBEEncoding() { float3[] coeffs = null; System.IO.FileInfo coeffsFileName = new System.IO.FileInfo("SHCoeffs.sh3"); using (System.IO.FileStream S = coeffsFileName.OpenRead()) using (System.IO.BinaryReader R = new System.IO.BinaryReader(S)) { uint coeffsCount = R.ReadUInt32(); coeffs = new float3[coeffsCount * 9]; for (int i = 0; i < 9 * coeffsCount; i++) { coeffs[i] = new float3(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); // The exponent bias allows us to support up to 512 in luminance! //coeffs[i] *= 5.0f; } } uint test1_packed = EncodeRGBE(new float3(1, 0, 1.5f)); float3 test1_unpacked = DecodeRGBE(test1_packed); // float3 coeffMin = new float3( float.MaxValue, float.MaxValue, float.MaxValue ); float3 coeffMax = new float3(-float.MaxValue, -float.MaxValue, -float.MaxValue); float3 coeffMinAbs = new float3(float.MaxValue, float.MaxValue, float.MaxValue); int coeffsWithDifferentSignsInRGBCount = 0; for (int i = 0; i < coeffs.Length; i++) { float3 coeff = coeffs[i]; float3 absCoeff = new float3(Math.Abs(coeff.x), Math.Abs(coeff.y), Math.Abs(coeff.z)); if (coeff.x * coeff.y < 0.0f || coeff.x * coeff.z < 0.0f || coeff.y * coeff.z < 0.0f) { coeffsWithDifferentSignsInRGBCount++; } // coeffMin.Min( coeff ); coeffMax.Max(absCoeff); if (absCoeff.x > 0.0f) { coeffMinAbs.x = Math.Min(coeffMinAbs.x, absCoeff.x); } if (absCoeff.y > 0.0f) { coeffMinAbs.y = Math.Min(coeffMinAbs.y, absCoeff.y); } if (absCoeff.z > 0.0f) { coeffMinAbs.z = Math.Min(coeffMinAbs.z, absCoeff.z); } } double expMin = Math.Min(Math.Min(Math.Log(coeffMinAbs.x) / Math.Log(2), Math.Log(coeffMinAbs.y) / Math.Log(2)), Math.Log(coeffMinAbs.z) / Math.Log(2)); double expMax = Math.Max(Math.Max(Math.Log(coeffMax.x) / Math.Log(2), Math.Log(coeffMax.y) / Math.Log(2)), Math.Log(coeffMax.z) / Math.Log(2)); // Measure discrepancies after RGBE encoding // float3 errorAbsMin = new float3( +float.MaxValue, +float.MaxValue, +float.MaxValue ); // float3 errorAbsMax = new float3( -float.MaxValue, -float.MaxValue, -float.MaxValue ); float3 errorRelMin = new float3(+float.MaxValue, +float.MaxValue, +float.MaxValue); float3 errorRelMax = new float3(-float.MaxValue, -float.MaxValue, -float.MaxValue); int minExponent = +int.MaxValue, maxExponent = -int.MaxValue; int largeRelativeErrorsCount = 0; for (int i = 0; i < coeffs.Length; i++) { float3 originalRGB = coeffs[i]; uint RGBE = EncodeRGBE(originalRGB); float3 decodedRGB = DecodeRGBE(RGBE); // Compute absolute error // float3 delta = decodedRGB - originalRGB; // float3 distanceFromOriginal = new float3( Math.Abs( delta.x ), Math.Abs( delta.y ), Math.Abs( delta.z ) ); // errorAbsMin.Min( distanceFromOriginal ); // errorAbsMax.Max( distanceFromOriginal ); // Compute relative error float3 errorRel = new float3(Math.Abs(originalRGB.x) > 0.0f ? Math.Abs(decodedRGB.x / originalRGB.x - 1.0f) : 0.0f, Math.Abs(originalRGB.y) > 0.0f ? Math.Abs(decodedRGB.y / originalRGB.y - 1.0f) : 0.0f, Math.Abs(originalRGB.z) > 0.0f ? Math.Abs(decodedRGB.z / originalRGB.z - 1.0f) : 0.0f); // Scale the relative error by the magnitude of each component as compared to the maximum component // This way, if we happen to have a "large" relative error on a component that is super small compared to the component with maximum amplitude then we can safely drop that small component (it's insignificant compared to the largest contribution) float maxComponent = Math.Max(Math.Max(Math.Abs(originalRGB.x), Math.Abs(originalRGB.y)), Math.Abs(originalRGB.z)); float3 magnitudeScale = maxComponent > 0.0f ? new float3(Math.Abs(originalRGB.x) / maxComponent, Math.Abs(originalRGB.y) / maxComponent, Math.Abs(originalRGB.z) / maxComponent) : float3.Zero; errorRel *= magnitudeScale; // Don't account for dernomalization // if ( decodedRGB.x == 0.0 && originalRGB.x != 0.0f ) errorRel.x = 0.0f; // if ( decodedRGB.y == 0.0 && originalRGB.y != 0.0f ) errorRel.y = 0.0f; // if ( decodedRGB.z == 0.0 && originalRGB.z != 0.0f ) errorRel.z = 0.0f; const float errorThreshold = 0.2f; if (Math.Abs(errorRel.x) > errorThreshold || Math.Abs(errorRel.y) > errorThreshold || Math.Abs(errorRel.z) > errorThreshold) { largeRelativeErrorsCount++; } errorRelMin.Min(errorRel); errorRelMax.Max(errorRel); int exp = (int)((RGBE >> 24) & 31) - EXPONENT_BIAS; minExponent = Math.Min(minExponent, exp); maxExponent = Math.Max(maxExponent, exp); } }
public Primitive(Mesh _Owner, FBX.Scene.Nodes.Mesh.Primitive _Primitive) { m_Owner = _Owner; m_MaterialID = (ushort)_Primitive.MaterialParms.ID; m_Faces = new Face[_Primitive.FacesCount]; m_Vertices = new Vertex[_Primitive.VerticesCount]; // Retrieve streams FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE[] Usages = { FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.POSITION, FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.NORMAL, FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TANGENT, FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.BITANGENT, FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TEXCOORDS, }; FBX.Scene.Nodes.Mesh.Primitive.VertexStream[][] Streams = new FBX.Scene.Nodes.Mesh.Primitive.VertexStream[Usages.Length][]; for (int UsageIndex = 0; UsageIndex < Usages.Length; UsageIndex++) { Streams[UsageIndex] = _Primitive.FindStreamsByUsage(Usages[UsageIndex]); if (Streams[UsageIndex].Length == 0) { throw new Exception("No stream for usage " + Usages[UsageIndex] + "! Can't complete target vertex format!"); } } // Build local space bounding box float3 Temp = new float3(); WMath.Vector[] VertexPositions = Streams[0][0].Content as WMath.Vector[]; foreach (WMath.Vector VertexPosition in VertexPositions) { Temp.FromVector3(VertexPosition); m_BBoxMin.Min(Temp); m_BBoxMax.Max(Temp); } // Build faces int FaceIndex = 0; foreach (FBX.Scene.Nodes.Mesh.Primitive.Face F in _Primitive.Faces) { m_Faces[FaceIndex].V0 = F.V0; m_Faces[FaceIndex].V1 = F.V1; m_Faces[FaceIndex].V2 = F.V2; FaceIndex++; } // Build vertices for (int VertexIndex = 0; VertexIndex < m_Vertices.Length; VertexIndex++) { for (int UsageIndex = 0; UsageIndex < Usages.Length; UsageIndex++) { FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE Usage = Usages[UsageIndex]; switch (Usage) { case FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.POSITION: { float3[] Stream = Streams[UsageIndex][0].Content as float3[]; m_Vertices[VertexIndex].P = Stream[VertexIndex]; break; } case FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.NORMAL: { float3[] Stream = Streams[UsageIndex][0].Content as float3[]; m_Vertices[VertexIndex].N = Stream[VertexIndex]; break; } case FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TANGENT: { float3[] Stream = Streams[UsageIndex][0].Content as float3[]; m_Vertices[VertexIndex].G = Stream[VertexIndex]; break; } case FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.BITANGENT: { float3[] Stream = Streams[UsageIndex][0].Content as float3[]; m_Vertices[VertexIndex].B = Stream[VertexIndex]; break; } case FBX.Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TEXCOORDS: { float2[] Stream = Streams[UsageIndex][0].Content as float2[]; m_Vertices[VertexIndex].T = Stream[VertexIndex]; break; } } } } }
public void Combine(AABB _Other) { m_Min.Min(_Other.m_Min); m_Max.Max(_Other.m_Max); }
void TestSHRGBEEncoding() { float3[] coeffs = null; System.IO.FileInfo coeffsFileName = new System.IO.FileInfo( "SHCoeffs.sh3" ); using ( System.IO.FileStream S = coeffsFileName.OpenRead() ) using ( System.IO.BinaryReader R = new System.IO.BinaryReader( S ) ) { uint coeffsCount = R.ReadUInt32(); coeffs = new float3[coeffsCount * 9]; for ( int i=0; i < 9*coeffsCount; i++ ) { coeffs[i] = new float3( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); // The exponent bias allows us to support up to 512 in luminance! //coeffs[i] *= 5.0f; } } uint test1_packed = EncodeRGBE( new float3( 1, 0, 1.5f ) ); float3 test1_unpacked = DecodeRGBE( test1_packed ); // float3 coeffMin = new float3( float.MaxValue, float.MaxValue, float.MaxValue ); float3 coeffMax = new float3( -float.MaxValue, -float.MaxValue, -float.MaxValue ); float3 coeffMinAbs = new float3( float.MaxValue, float.MaxValue, float.MaxValue ); int coeffsWithDifferentSignsInRGBCount = 0; for ( int i=0; i < coeffs.Length; i++ ) { float3 coeff = coeffs[i]; float3 absCoeff = new float3( Math.Abs( coeff.x ), Math.Abs( coeff.y ), Math.Abs( coeff.z ) ); if ( coeff.x * coeff.y < 0.0f || coeff.x * coeff.z < 0.0f || coeff.y * coeff.z < 0.0f ) coeffsWithDifferentSignsInRGBCount++; // coeffMin.Min( coeff ); coeffMax.Max( absCoeff ); if ( absCoeff.x > 0.0f ) coeffMinAbs.x = Math.Min( coeffMinAbs.x, absCoeff.x ); if ( absCoeff.y > 0.0f ) coeffMinAbs.y = Math.Min( coeffMinAbs.y, absCoeff.y ); if ( absCoeff.z > 0.0f ) coeffMinAbs.z = Math.Min( coeffMinAbs.z, absCoeff.z ); } double expMin = Math.Min( Math.Min( Math.Log( coeffMinAbs.x ) / Math.Log(2), Math.Log( coeffMinAbs.y ) / Math.Log(2) ), Math.Log( coeffMinAbs.z ) / Math.Log(2) ); double expMax = Math.Max( Math.Max( Math.Log( coeffMax.x ) / Math.Log(2), Math.Log( coeffMax.y ) / Math.Log(2) ), Math.Log( coeffMax.z ) / Math.Log(2) ); // Measure discrepancies after RGBE encoding // float3 errorAbsMin = new float3( +float.MaxValue, +float.MaxValue, +float.MaxValue ); // float3 errorAbsMax = new float3( -float.MaxValue, -float.MaxValue, -float.MaxValue ); float3 errorRelMin = new float3( +float.MaxValue, +float.MaxValue, +float.MaxValue ); float3 errorRelMax = new float3( -float.MaxValue, -float.MaxValue, -float.MaxValue ); int minExponent = +int.MaxValue, maxExponent = -int.MaxValue; int largeRelativeErrorsCount = 0; for ( int i=0; i < coeffs.Length; i++ ) { float3 originalRGB = coeffs[i]; uint RGBE = EncodeRGBE( originalRGB ); float3 decodedRGB = DecodeRGBE( RGBE ); // Compute absolute error // float3 delta = decodedRGB - originalRGB; // float3 distanceFromOriginal = new float3( Math.Abs( delta.x ), Math.Abs( delta.y ), Math.Abs( delta.z ) ); // errorAbsMin.Min( distanceFromOriginal ); // errorAbsMax.Max( distanceFromOriginal ); // Compute relative error float3 errorRel = new float3( Math.Abs( originalRGB.x ) > 0.0f ? Math.Abs( decodedRGB.x / originalRGB.x - 1.0f ) : 0.0f, Math.Abs( originalRGB.y ) > 0.0f ? Math.Abs( decodedRGB.y / originalRGB.y - 1.0f ) : 0.0f, Math.Abs( originalRGB.z ) > 0.0f ? Math.Abs( decodedRGB.z / originalRGB.z - 1.0f ) : 0.0f ); // Scale the relative error by the magnitude of each component as compared to the maximum component // This way, if we happen to have a "large" relative error on a component that is super small compared to the component with maximum amplitude then we can safely drop that small component (it's insignificant compared to the largest contribution) float maxComponent = Math.Max( Math.Max( Math.Abs( originalRGB.x ), Math.Abs( originalRGB.y ) ), Math.Abs( originalRGB.z ) ); float3 magnitudeScale = maxComponent > 0.0f ? new float3( Math.Abs( originalRGB.x ) / maxComponent, Math.Abs( originalRGB.y ) / maxComponent, Math.Abs( originalRGB.z ) / maxComponent ) : float3.Zero; errorRel *= magnitudeScale; // Don't account for dernomalization // if ( decodedRGB.x == 0.0 && originalRGB.x != 0.0f ) errorRel.x = 0.0f; // if ( decodedRGB.y == 0.0 && originalRGB.y != 0.0f ) errorRel.y = 0.0f; // if ( decodedRGB.z == 0.0 && originalRGB.z != 0.0f ) errorRel.z = 0.0f; const float errorThreshold = 0.2f; if ( Math.Abs( errorRel.x ) > errorThreshold || Math.Abs( errorRel.y ) > errorThreshold || Math.Abs( errorRel.z ) > errorThreshold ) largeRelativeErrorsCount++; errorRelMin.Min( errorRel ); errorRelMax.Max( errorRel ); int exp = (int) ((RGBE >> 24) & 31) - EXPONENT_BIAS; minExponent = Math.Min( minExponent, exp ); maxExponent = Math.Max( maxExponent, exp ); } }
public void Combine( AABB a, AABB b ) { m_Min = a.m_Min; m_Min.Min( b.m_Min ); m_Max = a.m_Max; m_Max.Max( b.m_Max ); }
public Mesh( Scene _Owner, idTech5Map.Map.Entity _Entity ) : base(_Owner, _Entity) { // BUild primitives and local space BBox m_Primitives = new Primitive[_Entity.m_Model.m_Surfaces.Length]; m_BBoxMin_Local = float.MaxValue * float3.One; m_BBoxMax_Local = -float.MaxValue * float3.One; int PrimitiveIndex = 0; foreach ( idTech5Map.Model.Surface S in _Entity.m_Model.m_Surfaces ) { m_Primitives[PrimitiveIndex] = new Primitive( this, S ); m_BBoxMin_Local.Min( m_Primitives[PrimitiveIndex].m_BBoxMin ); m_BBoxMax_Local.Max( m_Primitives[PrimitiveIndex].m_BBoxMax ); PrimitiveIndex++; } // Convert BBox to world space m_BBoxMin_World = float.MaxValue * float3.One; m_BBoxMax_World = -float.MaxValue * float3.One; for ( int CornerIndex=0; CornerIndex < 8; CornerIndex++ ) { float X = (CornerIndex >> 0) & 1; float Y = (CornerIndex >> 0) & 1; float Z = (CornerIndex >> 0) & 1; float3 D = m_BBoxMax_Local - m_BBoxMin_Local; float3 lsCorner = m_BBoxMin_Local + new float3( X * D.x, Y * D.y, Z * D.z ); float3 wsCorner = (float3) (new float4( lsCorner, 1.0f ) * m_Local2Parent); m_BBoxMin_World.Min( wsCorner ); m_BBoxMax_World.Max( wsCorner ); } }