void BuildNoiseTextures() { PixelsBuffer Content = new PixelsBuffer(NOISE_SIZE * NOISE_SIZE * NOISE_SIZE * 4); PixelsBuffer Content4D = new PixelsBuffer(NOISE_SIZE * NOISE_SIZE * NOISE_SIZE * 16); WMath.SimpleRNG.SetSeed(521288629, 362436069); float4 V = float4.Zero; using (BinaryWriter W = Content.OpenStreamWrite()) { using (BinaryWriter W2 = Content4D.OpenStreamWrite()) { for (int Z = 0; Z < NOISE_SIZE; Z++) { for (int Y = 0; Y < NOISE_SIZE; Y++) { for (int X = 0; X < NOISE_SIZE; X++) { V.Set((float)WMath.SimpleRNG.GetUniform(), (float)WMath.SimpleRNG.GetUniform(), (float)WMath.SimpleRNG.GetUniform(), (float)WMath.SimpleRNG.GetUniform()); W.Write(V.x); W2.Write(V.x); W2.Write(V.y); W2.Write(V.z); W2.Write(V.w); } } } } } m_Tex_Noise = new Texture3D(m_Device, NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, 1, PIXEL_FORMAT.R8_UNORM, false, false, new PixelsBuffer[] { Content }); m_Tex_Noise4D = new Texture3D(m_Device, NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, 1, PIXEL_FORMAT.RGBA8_UNORM, false, false, new PixelsBuffer[] { Content4D }); }
private void Build3DDensityField() { PixelsBuffer DensityField = new PixelsBuffer(DENSITY_FIELD_SIZE * DENSITY_FIELD_SIZE * DENSITY_FIELD_HEIGHT); byte D; float3 P; float3 C = new float3(0.5f, 0.5f, 0.5f); using (System.IO.BinaryWriter W = DensityField.OpenStreamWrite()) for (int X = 0; X < DENSITY_FIELD_SIZE; X++) { P.x = (0.5f + X) / DENSITY_FIELD_SIZE; for (int Y = 0; Y < DENSITY_FIELD_HEIGHT; Y++) { P.y = (0.5f + Y) / DENSITY_FIELD_HEIGHT; for (int Z = 0; Z < DENSITY_FIELD_SIZE; Z++) { P.z = (0.5f + Z) / DENSITY_FIELD_SIZE; // D = 0; // Empty for now: photons should go straight through! D = (byte)((P - C).LengthSquared < 0.125f ? 255 : 0); W.Write(D); } } } Reg(m_Tex_DensityField = new Texture3D(m_Device, DENSITY_FIELD_SIZE, DENSITY_FIELD_HEIGHT, DENSITY_FIELD_SIZE, 1, PIXEL_FORMAT.R8_UNORM, false, false, new PixelsBuffer[] { DensityField })); DensityField.Dispose(); }
/// <summary> /// Loads the LTC table used in Unity /// </summary> /// <returns></returns> Texture2D LoadUnityLTC() { uint S = (uint)UnityEngine.Experimental.Rendering.HDPipeline.LTCAreaLight.k_LtcLUTResolution; PixelsBuffer content = new PixelsBuffer(S * S * 16); using (BinaryWriter W = content.OpenStreamWrite()) { for (uint Y = 0; Y < S; Y++) { for (uint X = 0; X < S; X++) { uint i = S * Y + X; float m11 = (float)UnityEngine.Experimental.Rendering.HDPipeline.LTCAreaLight.s_LtcGGXMatrixData[i, 0]; float m13 = (float)UnityEngine.Experimental.Rendering.HDPipeline.LTCAreaLight.s_LtcGGXMatrixData[i, 2]; float m22 = (float)UnityEngine.Experimental.Rendering.HDPipeline.LTCAreaLight.s_LtcGGXMatrixData[i, 4]; float m31 = (float)UnityEngine.Experimental.Rendering.HDPipeline.LTCAreaLight.s_LtcGGXMatrixData[i, 6]; W.Write(m11); W.Write(m13); W.Write(m22); W.Write(m31); } } } Texture2D T = new Texture2D(m_device, S, S, 1, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content }); return(T); }
public Texture2D Image2Texture(int _Width, int _Height, byte[] _Content) { using (PixelsBuffer Buff = new PixelsBuffer(_Content.Length)) { using (System.IO.BinaryWriter W = Buff.OpenStreamWrite()) W.Write(_Content); return(Image2Texture(_Width, _Height, Buff)); } }
void BuildFont() { string charSet = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~éèêëôöàçÔÖÂÊÉœûüù"; m_fontRectangles = new Rectangle[charSet.Length]; for (int charIndex = 0; charIndex < charSet.Length; charIndex++) { char C = charSet[charIndex]; int index = (int)C; m_char2Index[index] = charIndex; } // Load atlas & rectangles using (ImageUtility.ImageFile file = new ImageUtility.ImageFile(new FileInfo("Atlas.png"))) { ImageUtility.ImageFile file2 = new ImageUtility.ImageFile(file, ImageUtility.PIXEL_FORMAT.RGBA8); using (ImageUtility.ImagesMatrix M = new ImageUtility.ImagesMatrix(file2, ImageUtility.ImagesMatrix.IMAGE_TYPE.sRGB)) { m_tex_FontAtlas = new Texture2D(m_device, M, ImageUtility.COMPONENT_FORMAT.UNORM_sRGB); } } using (FileStream S = new FileInfo("Atlas.rect").OpenRead()) using (BinaryReader R = new BinaryReader(S)) { // Read both CPU and GPU versions float recW = 1.0f / m_tex_FontAtlas.Width; float recH = 1.0f / m_tex_FontAtlas.Height; using (PixelsBuffer content = new PixelsBuffer((uint)(16 * m_fontRectangles.Length))) { using (BinaryWriter W = content.OpenStreamWrite()) { for (int i = 0; i < m_fontRectangles.Length; i++) { m_fontRectangles[i].X = R.ReadInt32(); m_fontRectangles[i].Y = R.ReadInt32(); m_fontRectangles[i].Width = R.ReadInt32(); m_fontRectangles[i].Height = R.ReadInt32(); W.Write(recW * (float)m_fontRectangles[i].X); W.Write(recH * (float)m_fontRectangles[i].Y); W.Write(recW * (float)m_fontRectangles[i].Width); W.Write(recH * (float)m_fontRectangles[i].Height); } } m_tex_FontRectangle = new Texture2D(m_device, (uint)m_fontRectangles.Length, 1, 1, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content }); } } }
private void FFT_CPUInOut(Complex[,] _input, Complex[,] _output, float _sign) { try { ////////////////////////////////////////////////////////////////////////// // Load initial content PixelsBuffer loadingBuffer = m_texBufferCPU.MapWrite(0, 0); System.IO.BinaryWriter W = loadingBuffer.OpenStreamWrite(); for (int Y = 0; Y < m_size; Y++) { for (int X = 0; X < m_size; X++) { W.Write((float)_input[X, Y].r); W.Write((float)_input[X, Y].i); } } loadingBuffer.CloseStream(); m_texBufferCPU.UnMap(loadingBuffer); m_texBufferIn.CopyFrom(m_texBufferCPU); ////////////////////////////////////////////////////////////////////////// // Apply multiple shader passes FFT_GPUInOut(_sign); ////////////////////////////////////////////////////////////////////////// // Read back content m_texBufferCPU.CopyFrom(m_texBufferOut); PixelsBuffer resultBuffer = m_texBufferCPU.MapRead(0, 0); System.IO.BinaryReader R = resultBuffer.OpenStreamRead(); for (int Y = 0; Y < m_size; Y++) { for (int X = 0; X < m_size; X++) { _output[X, Y].Set(R.ReadSingle(), R.ReadSingle()); } } resultBuffer.CloseStream(); m_texBufferCPU.UnMap(resultBuffer); } catch (Exception _e) { throw new Exception("An error occurred while performing the FFT!", _e); } }
// ACTUALLY, THESE ARE GENERATED IN MATHEMATICA NOW!! // // const uint COS_THETA_SUBDIVS_COUNT = 128; // const uint ROUGHNESS_SUBDIVS_COUNT = 128; // // float[,] m_GGX_E = new float[COS_THETA_SUBDIVS_COUNT,ROUGHNESS_SUBDIVS_COUNT]; // float[] m_GGX_Eavg = new float[ROUGHNESS_SUBDIVS_COUNT]; // // void BuildMSBRDF( DirectoryInfo _targetDirectory ) { // // FileInfo MSBRDFFileName = new FileInfo( Path.Combine( _targetDirectory.FullName, "MSBRDF_E" + COS_THETA_SUBDIVS_COUNT + "x" + ROUGHNESS_SUBDIVS_COUNT + ".float" ) ); // FileInfo MSBRDFFileName2 = new FileInfo( Path.Combine( _targetDirectory.FullName, "MSBRDF_Eavg" + ROUGHNESS_SUBDIVS_COUNT + ".float" ) ); // // #if PRECOMPUTE_BRDF // // ACTUALLY, THESE ARE GENERATED IN MATHEMATICA NOW!! // Don't expect this code to work! // // { // const uint PHI_SUBDIVS_COUNT = 2*512; // const uint THETA_SUBDIVS_COUNT = 64; // // const float dPhi = Mathf.TWOPI / PHI_SUBDIVS_COUNT; // const float dTheta = Mathf.HALFPI / THETA_SUBDIVS_COUNT; // const float dMu = 1.0f / THETA_SUBDIVS_COUNT; // // string dumpMathematica = "{"; // for ( uint Y=0; Y < ROUGHNESS_SUBDIVS_COUNT; Y++ ) { // // //Y = 5; // // float m = (float) Y / (ROUGHNESS_SUBDIVS_COUNT-1); // float m2 = Math.Max( 0.01f, m*m ); // // float m2 = Math.Max( 0.01f, (float) Y / (ROUGHNESS_SUBDIVS_COUNT-1) ); // // float m = Mathf.Sqrt( m2 ); // // // dumpMathematica += "{ "; // Start a new roughness line // for ( uint X=0; X < COS_THETA_SUBDIVS_COUNT; X++ ) { // // //X = 17; // // float cosThetaO = (float) X / (COS_THETA_SUBDIVS_COUNT-1); // float sinThetaO = Mathf.Sqrt( 1 - cosThetaO*cosThetaO ); // // float NdotV = cosThetaO; // // float integral = 0.0f; // // float integralNDF = 0.0f; // for ( uint THETA=0; THETA < THETA_SUBDIVS_COUNT; THETA++ ) { // // float thetaI = Mathf.HALFPI * (0.5f+THETA) / THETA_SUBDIVS_COUNT; // // float cosThetaI = Mathf.Cos( thetaI ); // // float sinThetaI = Mathf.Sin( thetaI ); // // // Use cosine-weighted sampling // float sqCosThetaI = (0.5f+THETA) / THETA_SUBDIVS_COUNT; // float cosThetaI = Mathf.Sqrt( sqCosThetaI ); // float sinThetaI = Mathf.Sqrt( 1 - sqCosThetaI ); // // float NdotL = cosThetaI; // // for ( uint PHI=0; PHI < PHI_SUBDIVS_COUNT; PHI++ ) { // float phi = Mathf.TWOPI * PHI / PHI_SUBDIVS_COUNT; // // // Compute cos(theta_h) = Omega_h.N where Omega_h = (Omega_i + Omega_o) / ||Omega_i + Omega_o|| is the half vector and N the surface normal // float cosThetaH = (cosThetaI + cosThetaO) / Mathf.Sqrt( 2 * (1 + cosThetaO * cosThetaI + sinThetaO * sinThetaI * Mathf.Cos( phi )) ); // // float3 omega_i = new float3( sinThetaI * Mathf.Cos( phi ), sinThetaI * Mathf.Sin( phi ), cosThetaI ); // // float3 omega_o = new float3( sinThetaO, 0, cosThetaO ); // // float3 omega_h = (omega_i + omega_o).Normalized; // // float cosThetaH = omega_h.z; // // // Compute GGX NDF // float den = 1 - cosThetaH*cosThetaH * (1 - m2); // float NDF = m2 / (Mathf.PI * den*den); // // // Compute Smith shadowing/masking // float Smith_i_den = NdotL + Mathf.Sqrt( m2 + (1-m2) * NdotL*NdotL ); // // // Full BRDF is thus... // float GGX = NDF / Smith_i_den; // // // integral += GGX * cosThetaI * sinThetaI; // integral += GGX; // } // // // integralNDF += Mathf.TWOPI * m2 * cosThetaI * sinThetaI / (Mathf.PI * Mathf.Pow( cosThetaI*cosThetaI * (m2 - 1) + 1, 2.0f )); // } // // // Finalize // float Smith_o_den = NdotV + Mathf.Sqrt( m2 + (1-m2) * NdotV*NdotV ); // integral /= Smith_o_den; // // // integral *= dTheta * dPhi; // integral *= 0.5f * dMu * dPhi; // Cosine-weighted sampling has a 0.5 factor! // // integralNDF *= dTheta; // // m_GGX_E[X,Y] = integral; // dumpMathematica += "{ " + cosThetaO + ", " + m + ", " + integral + "}, "; // } // } // // dumpMathematica = dumpMathematica.Remove( dumpMathematica.Length-2 ); // Remove last comma // dumpMathematica += " };"; // // // Dump as binary // using ( FileStream S = MSBRDFFileName.Create() ) // using ( BinaryWriter W = new BinaryWriter( S ) ) { // for ( uint Y=0; Y < ROUGHNESS_SUBDIVS_COUNT; Y++ ) // for ( uint X=0; X < COS_THETA_SUBDIVS_COUNT; X++ ) // W.Write( m_GGX_E[X,Y] ); // } // // ////////////////////////////////////////////////////////////////////////// // // Compute average irradiance based on roughness, re-using the previously computed results // const uint THETA_SUBDIVS_COUNT2 = 512; // // float dTheta2 = Mathf.HALFPI / THETA_SUBDIVS_COUNT2; // // for ( uint X=0; X < ROUGHNESS_SUBDIVS_COUNT; X++ ) { // // float integral = 0.0f; // for ( uint THETA=0; THETA < THETA_SUBDIVS_COUNT2; THETA++ ) { // float thetaO = Mathf.HALFPI * (0.5f+THETA) / THETA_SUBDIVS_COUNT2; // float cosThetaO = Mathf.Cos( thetaO ); // float sinThetaO = Mathf.Sin( thetaO ); // // // Sample previously computed table // float i = cosThetaO * COS_THETA_SUBDIVS_COUNT; // uint i0 = Math.Min( COS_THETA_SUBDIVS_COUNT-1, (uint) Mathf.Floor( i ) ); // uint i1 = Math.Min( COS_THETA_SUBDIVS_COUNT-1, i0 + 1 ); // float E = (1-i) * m_GGX_E[i0,X] + i * m_GGX_E[i1,X]; // // integral += E * cosThetaO * sinThetaO; // } // // // Finalize // integral *= Mathf.TWOPI * dTheta2; // // m_GGX_Eavg[X] = integral; // } // // // Dump as binary // using ( FileStream S = MSBRDFFileName2.Create() ) // using ( BinaryWriter W = new BinaryWriter( S ) ) { // for ( uint X=0; X < ROUGHNESS_SUBDIVS_COUNT; X++ ) // W.Write( m_GGX_Eavg[X] ); // } // } // // #endif // // // // Build irradiance complement texture // // using ( PixelsBuffer content = new PixelsBuffer( COS_THETA_SUBDIVS_COUNT * ROUGHNESS_SUBDIVS_COUNT * 4 ) ) { // // using ( FileStream S = MSBRDFFileName.OpenRead() ) // // using ( BinaryReader R = new BinaryReader( S ) ) // // using ( BinaryWriter W = content.OpenStreamWrite() ) { // // for ( uint Y=0; Y < ROUGHNESS_SUBDIVS_COUNT; Y++ ) { // // for ( uint X=0; X < COS_THETA_SUBDIVS_COUNT; X++ ) { // // float V = R.ReadSingle(); // // m_GGX_E[X,Y] = V; // // W.Write( V ); // // } // // } // // } // // // // m_tex_IrradianceComplement = new Texture2D( m_device, COS_THETA_SUBDIVS_COUNT, ROUGHNESS_SUBDIVS_COUNT, 1, 1, ImageUtility.PIXEL_FORMAT.R32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content } ); // // } // // // // // Build average irradiance texture // // using ( PixelsBuffer content = new PixelsBuffer( ROUGHNESS_SUBDIVS_COUNT * 4 ) ) { // // using ( FileStream S = MSBRDFFileName2.OpenRead() ) // // using ( BinaryReader R = new BinaryReader( S ) ) // // using ( BinaryWriter W = content.OpenStreamWrite() ) { // // for ( uint X=0; X < ROUGHNESS_SUBDIVS_COUNT; X++ ) { // // float V = R.ReadSingle(); // // m_GGX_Eavg[X] = V; // // W.Write( V ); // // } // // } // // // // m_tex_IrradianceAverage = new Texture2D( m_device, ROUGHNESS_SUBDIVS_COUNT, 1, 1, 1, ImageUtility.PIXEL_FORMAT.R32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content } ); // // } // // // ////////////////////////////////////////////////////////////////////////// // // Check single-scattering and multiple-scattering BRDFs are actual complements // // // /* // float3[,] integralChecks = new float3[COS_THETA_SUBDIVS_COUNT,ROUGHNESS_SUBDIVS_COUNT]; // for ( uint Y=0; Y < ROUGHNESS_SUBDIVS_COUNT; Y++ ) { // float m = (float) Y / (ROUGHNESS_SUBDIVS_COUNT-1); // float m2 = Math.Max( 0.01f, m*m ); // // float Eavg = SampleEavg( m ); // // for ( uint X=0; X < COS_THETA_SUBDIVS_COUNT; X++ ) { // float cosThetaO = (float) X / (COS_THETA_SUBDIVS_COUNT-1); // float sinThetaO = Mathf.Sqrt( 1 - cosThetaO*cosThetaO ); // // float NdotV = cosThetaO; // // float Eo = SampleE( cosThetaO, m ); // // const uint CHECK_THETA_SUBDIVS_COUNT = 128; // const uint CHECK_PHI_SUBDIVS_COUNT = 2*128; // // const float dPhi = Mathf.TWOPI / CHECK_PHI_SUBDIVS_COUNT; // const float dTheta = Mathf.HALFPI / CHECK_THETA_SUBDIVS_COUNT; // // float integralSS = 0.0f; // float integralMS = 0.0f; // for ( uint THETA=0; THETA < CHECK_THETA_SUBDIVS_COUNT; THETA++ ) { // // // Use regular sampling // float thetaI = Mathf.HALFPI * (0.5f+THETA) / CHECK_THETA_SUBDIVS_COUNT; // float cosThetaI = Mathf.Cos( thetaI ); // float sinThetaI = Mathf.Sin( thetaI ); // // // // Use cosine-weighted sampling // // float sqCosThetaI = (0.5f+THETA) / CHECK_THETA_SUBDIVS_COUNT; // // float cosThetaI = Mathf.Sqrt( sqCosThetaI ); // // float sinThetaI = Mathf.Sqrt( 1 - sqCosThetaI ); // // float NdotL = cosThetaI; // // for ( uint PHI=0; PHI < CHECK_PHI_SUBDIVS_COUNT; PHI++ ) { // float phi = Mathf.TWOPI * PHI / CHECK_PHI_SUBDIVS_COUNT; // // ////////////////////////////////////////////////////////////////////////// // // Single-scattering part // // // Compute cos(theta_h) = Omega_h.N where Omega_h = (Omega_i + Omega_o) / ||Omega_i + Omega_o|| is the half vector and N the surface normal // float cosThetaH = (cosThetaI + cosThetaO) / Mathf.Sqrt( 2 * (1 + cosThetaO * cosThetaI + sinThetaO * sinThetaI * Mathf.Sin( phi )) ); // // float3 omega_i = new float3( sinThetaI * Mathf.Cos( phi ), sinThetaI * Mathf.Sin( phi ), cosThetaI ); // // float3 omega_o = new float3( sinThetaO, 0, cosThetaO ); // // float3 omega_h = (omega_i + omega_o).Normalized; // // float cosThetaH = omega_h.z; // // // Compute GGX NDF // float den = 1 - cosThetaH*cosThetaH * (1 - m2); // float NDF = m2 / (Mathf.PI * den*den); // // // Compute Smith shadowing/masking // float Smith_i_den = NdotL + Mathf.Sqrt( m2 + (1-m2) * NdotL*NdotL ); // float Smith_o_den = NdotV + Mathf.Sqrt( m2 + (1-m2) * NdotV*NdotV ); // // // Full BRDF is thus... // float GGX = NDF / (Smith_i_den * Smith_o_den); // // integralSS += GGX * cosThetaI * sinThetaI; // // integralSS += GGX; // // ////////////////////////////////////////////////////////////////////////// // // Multiple-scattering part // float Ei = SampleE( cosThetaI, m ); // // float GGX_ms = Eo * Ei / Eavg; // // integralMS += GGX_ms * cosThetaI * sinThetaI; // } // } // // // Finalize // integralSS *= dTheta * dPhi; // integralMS *= dTheta * dPhi; // // integralChecks[X,Y] = new float3( integralSS, integralMS, integralSS + integralMS ); // } // } // //*/ // ////////////////////////////////////////////////////////////////////////// // // // // verify BRDF + BRDFms integration = 1 // //cube map + integration // } // // float SampleE( float _cosTheta, float _roughness ) { // _cosTheta *= COS_THETA_SUBDIVS_COUNT; // _roughness *= ROUGHNESS_SUBDIVS_COUNT; // // float X = Mathf.Floor( _cosTheta ); // float x = _cosTheta - X; // uint X0 = Mathf.Min( COS_THETA_SUBDIVS_COUNT-1, (uint) X ); // uint X1 = Mathf.Min( COS_THETA_SUBDIVS_COUNT-1, X0+1 ); // // float Y = Mathf.Floor( _roughness ); // float y = _roughness - Y; // uint Y0 = Mathf.Min( ROUGHNESS_SUBDIVS_COUNT-1, (uint) Y ); // uint Y1 = Mathf.Min( ROUGHNESS_SUBDIVS_COUNT-1, Y0+1 ); // // float V00 = m_GGX_E[X0,Y0]; // float V10 = m_GGX_E[X1,Y0]; // float V01 = m_GGX_E[X0,Y1]; // float V11 = m_GGX_E[X1,Y1]; // // float V0 = (1.0f - x) * V00 + x * V10; // float V1 = (1.0f - x) * V01 + x * V11; // float V = (1.0f - y) * V0 + y * V1; // return V; // } // float SampleEavg( float _roughness ) { // _roughness *= ROUGHNESS_SUBDIVS_COUNT; // float X = Mathf.Floor( _roughness ); // float x = _roughness - X; // uint X0 = Mathf.Min( ROUGHNESS_SUBDIVS_COUNT-1, (uint) X ); // uint X1 = Mathf.Min( ROUGHNESS_SUBDIVS_COUNT-1, X0+1 ); // // float V0 = m_GGX_Eavg[X0]; // float V1 = m_GGX_Eavg[X1]; // float V = (1.0f - x) * V0 + x * V1; // return V; // } void LoadMSBRDF(int _size, FileInfo _irradianceTableName, FileInfo _whiteFurnaceTableName, out Texture2D _irradianceTexture, out Texture2D _whiteFurnaceTexture) { // Read irradiance table float[,] irradianceTable = new float[_size, _size]; PixelsBuffer contentIrradiance = new PixelsBuffer((uint)(_size * _size * 4)); using (FileStream S = _irradianceTableName.OpenRead()) using (BinaryReader R = new BinaryReader(S)) { using (BinaryWriter W = contentIrradiance.OpenStreamWrite()) { for (int Y = 0; Y < _size; Y++) { for (int X = 0; X < _size; X++) { float V = R.ReadSingle(); irradianceTable[X, Y] = V; W.Write(V); } } } } // Read white furnace table float[] whiteFurnaceTable = new float[_size]; PixelsBuffer contentWhiteFurnace = new PixelsBuffer((uint)(_size * 4)); using (FileStream S = _whiteFurnaceTableName.OpenRead()) using (BinaryReader R = new BinaryReader(S)) { using (BinaryWriter W = contentWhiteFurnace.OpenStreamWrite()) { for (int Y = 0; Y < _size; Y++) { float V = R.ReadSingle(); whiteFurnaceTable[Y] = V; W.Write(V); } } } // Create textures _irradianceTexture = new Texture2D(m_device, (uint)_size, (uint)_size, 1, 1, ImageUtility.PIXEL_FORMAT.R32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, true, new PixelsBuffer[] { contentIrradiance }); _whiteFurnaceTexture = new Texture2D(m_device, (uint)_size, 1, 1, 1, ImageUtility.PIXEL_FORMAT.R32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, true, new PixelsBuffer[] { contentWhiteFurnace }); }
void BuildNoiseTextures() { PixelsBuffer Content = new PixelsBuffer(NOISE_SIZE * NOISE_SIZE * NOISE_SIZE * 4); PixelsBuffer Content4D = new PixelsBuffer(NOISE_SIZE * NOISE_SIZE * NOISE_SIZE * 16); SimpleRNG.SetSeed(521288629, 362436069); float4 V = float4.Zero; using (BinaryWriter W = Content.OpenStreamWrite()) { using (BinaryWriter W2 = Content4D.OpenStreamWrite()) { for (int Z = 0; Z < NOISE_SIZE; Z++) { for (int Y = 0; Y < NOISE_SIZE; Y++) { for (int X = 0; X < NOISE_SIZE; X++) { V.Set((float)SimpleRNG.GetUniform(), (float)SimpleRNG.GetUniform(), (float)SimpleRNG.GetUniform(), (float)SimpleRNG.GetUniform()); W.Write(V.x); W2.Write(V.x); W2.Write(V.y); W2.Write(V.z); W2.Write(V.w); } } } } } m_tex_Noise = new Texture3D(m_device, NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, 1, ImageUtility.PIXEL_FORMAT.R8, ImageUtility.COMPONENT_FORMAT.UNORM, false, false, new PixelsBuffer[] { Content }); m_tex_Noise4D = new Texture3D(m_device, NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, 1, ImageUtility.PIXEL_FORMAT.RGBA8, ImageUtility.COMPONENT_FORMAT.UNORM, false, false, new PixelsBuffer[] { Content4D }); // Load blue noise using (ImageUtility.ImageFile I = new ImageUtility.ImageFile(new FileInfo("BlueNoise64x64_16bits.png"))) { ImageUtility.ImagesMatrix M = new ImageUtility.ImagesMatrix(new ImageUtility.ImageFile[, ] { { I } }); m_tex_BlueNoise = new Texture2D(m_device, M, ImageUtility.COMPONENT_FORMAT.UNORM); } }
void BuildNoiseTextures() { PixelsBuffer Content = new PixelsBuffer( NOISE_SIZE*NOISE_SIZE*NOISE_SIZE*4 ); PixelsBuffer Content4D = new PixelsBuffer( NOISE_SIZE*NOISE_SIZE*NOISE_SIZE*16 ); WMath.SimpleRNG.SetSeed( 521288629, 362436069 ); float4 V = float4.Zero; using ( BinaryWriter W = Content.OpenStreamWrite() ) { using ( BinaryWriter W2 = Content4D.OpenStreamWrite() ) { for ( int Z=0; Z < NOISE_SIZE; Z++ ) for ( int Y=0; Y < NOISE_SIZE; Y++ ) for ( int X=0; X < NOISE_SIZE; X++ ) { V.Set( (float) WMath.SimpleRNG.GetUniform(), (float) WMath.SimpleRNG.GetUniform(), (float) WMath.SimpleRNG.GetUniform(), (float) WMath.SimpleRNG.GetUniform() ); W.Write( V.x ); W2.Write( V.x ); W2.Write( V.y ); W2.Write( V.z ); W2.Write( V.w ); } } } m_Tex_Noise = new Texture3D( m_Device, NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, 1, PIXEL_FORMAT.R8_UNORM, false, false, new PixelsBuffer[] { Content } ); m_Tex_Noise4D = new Texture3D( m_Device, NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, 1, PIXEL_FORMAT.RGBA8_UNORM, false, false, new PixelsBuffer[] { Content4D } ); }
private void LoadResults( System.IO.FileInfo _FileName ) { try { groupBoxOptions.Enabled = false; // Dispose of existing resources if ( m_TextureTargets[0][0] != null ) { m_TextureTargets[0][0].Dispose(); m_TextureTargets[0][1].Dispose(); m_TextureTargets[1][0].Dispose(); m_TextureTargets[1][1].Dispose(); m_TextureTargets[2][0].Dispose(); m_TextureTargets[2][1].Dispose(); m_TextureTargetCombined.Dispose(); } m_TextureTargets[0][0] = null; m_TextureTargets[0][1] = null; m_TextureTargets[1][0] = null; m_TextureTargets[1][1] = null; m_TextureTargets[2][0] = null; m_TextureTargets[2][1] = null; m_TextureTargetCombined = null; if ( m_imageResults[0] != null ) m_imageResults[0].Dispose(); if ( m_imageResults[1] != null ) m_imageResults[1].Dispose(); if ( m_imageResults[2] != null ) m_imageResults[2].Dispose(); if ( m_imageResultCombined != null ) m_imageResultCombined.Dispose(); // m_imageResults[0] = new ImageUtility.ImageFile( W, H, ImageUtility.ImageFile.PIXEL_FORMAT.R8, m_sRGBProfile ); // m_imageResults[1] = new ImageUtility.ImageFile( W, H, ImageUtility.ImageFile.PIXEL_FORMAT.R8, m_sRGBProfile ); // m_imageResults[2] = new ImageUtility.ImageFile( W, H, ImageUtility.ImageFile.PIXEL_FORMAT.R8, m_sRGBProfile ); // m_imageResultCombined = new ImageUtility.ImageFile( W, H, ImageUtility.ImageFile.PIXEL_FORMAT.RGBA8, m_sRGBProfile ); m_imageResults[0] = new ImageUtility.ImageFile(); m_imageResults[1] = new ImageUtility.ImageFile(); m_imageResults[2] = new ImageUtility.ImageFile(); m_imageResultCombined = new ImageUtility.ImageFile(); // Load the result images assuming it's in sRGB space string[] FileNames = new string[4] { System.IO.Path.Combine( System.IO.Path.GetDirectoryName( _FileName.FullName ), System.IO.Path.GetFileNameWithoutExtension( _FileName.FullName ) + "_translucency0.png" ), System.IO.Path.Combine( System.IO.Path.GetDirectoryName( _FileName.FullName ), System.IO.Path.GetFileNameWithoutExtension( _FileName.FullName ) + "_translucency1.png" ), System.IO.Path.Combine( System.IO.Path.GetDirectoryName( _FileName.FullName ), System.IO.Path.GetFileNameWithoutExtension( _FileName.FullName ) + "_translucency2.png" ), System.IO.Path.Combine( System.IO.Path.GetDirectoryName( _FileName.FullName ), System.IO.Path.GetFileNameWithoutExtension( _FileName.FullName ) + "_translucency.png" ), }; ImageUtility.ImageFile[] images = new ImageUtility.ImageFile[] { m_imageResults[0], m_imageResults[1], m_imageResults[2], m_imageResultCombined }; Texture2D[] Results = new Texture2D[] { m_TextureTargets[0][0], m_TextureTargets[1][0], m_TextureTargets[2][0], m_TextureTargetCombined, }; ImagePanel[] Panels = new ImagePanel[] { imagePanelResult0, imagePanelResult1, imagePanelResult2, imagePanelResult3, }; for ( int i=0; i < 4; i++ ) { ImageUtility.ImageFile B = images[i]; B.Load( new System.IO.FileInfo( FileNames[i] ) ); Panels[i].Image = B; // Build the texture assuming sRGB sources float4[] scanline = new float4[B.Width]; float4 linearRGB = float4.Zero; PixelsBuffer sourceMap = new PixelsBuffer( B.Width*B.Height*16 ); using ( System.IO.BinaryWriter Wr = sourceMap.OpenStreamWrite() ) for ( uint Y=0; Y < B.Height; Y++ ) { B.ReadScanline( Y, scanline ); for ( uint X=0; X < B.Width; X++ ) { m_sRGBProfile.GammaRGB2LinearRGB( scanline[X], ref linearRGB ); Wr.Write( linearRGB.x ); Wr.Write( linearRGB.y ); Wr.Write( linearRGB.z ); Wr.Write( linearRGB.w ); } } Results[i] = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, true, new PixelsBuffer[] { sourceMap } ); } m_TextureTargets[0][0] = Results[0]; m_TextureTargets[0][1] = Results[0]; m_TextureTargets[1][0] = Results[1]; m_TextureTargets[1][1] = Results[1]; m_TextureTargets[2][0] = Results[2]; m_TextureTargets[2][1] = Results[2]; m_TextureTargetCombined = Results[3]; } catch ( Exception _e ) { MessageBox( "An error occurred while opening the result maps \"" + _FileName.FullName + "\":\n\n", _e ); } }
private void LoadNormalMap( System.IO.FileInfo _FileName ) { try { // Dispose of existing resources if ( m_imageSourceNormal != null ) m_imageSourceNormal.Dispose(); m_imageSourceNormal = null; if ( m_TextureSourceNormal != null ) m_TextureSourceNormal.Dispose(); m_TextureSourceNormal = null; // Load the source image m_imageSourceNormal = new ImageUtility.ImageFile( _FileName ); imagePanelNormalMap.Image = m_imageSourceNormal; uint W = m_imageSourceNormal.Width; uint H = m_imageSourceNormal.Height; // Build the source texture assuming the image is in linear space float4[] scanline = new float4[W]; PixelsBuffer sourceNormalMap = new PixelsBuffer( W*H*16 ); using ( System.IO.BinaryWriter Wr = sourceNormalMap.OpenStreamWrite() ) for ( uint Y=0; Y < H; Y++ ) { m_imageSourceNormal.ReadScanline( Y, scanline ); for ( uint X=0; X < W; X++ ) { Wr.Write( scanline[X].x ); Wr.Write( scanline[X].y ); Wr.Write( scanline[X].z ); Wr.Write( 1.0f ); } } m_TextureSourceNormal = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, false, new PixelsBuffer[] { sourceNormalMap } ); } catch ( Exception _e ) { MessageBox( "An error occurred while opening the normal map \"" + _FileName.FullName + "\":\n\n", _e ); } }
public Texture2D Pipi2Texture( System.IO.FileInfo _FileName ) { using ( System.IO.FileStream S = _FileName.OpenRead() ) using ( System.IO.BinaryReader R = new System.IO.BinaryReader( S ) ) { int MipLevels = R.ReadInt32(); PixelsBuffer[] Mips = new PixelsBuffer[MipLevels]; int ImageWidth = 0, ImageHeight = 0; for ( int MipLevel=0; MipLevel < MipLevels; MipLevel++ ) { int W, H; W = R.ReadInt32(); H = R.ReadInt32(); if ( MipLevel == 0 ) { ImageWidth = W; ImageHeight = H; } PixelsBuffer Buff = new PixelsBuffer( (uint) (4 * W * H * 4) ); Mips[MipLevel] = Buff; using ( System.IO.BinaryWriter Wr = Buff.OpenStreamWrite() ) { float4 C = new float4(); for ( int Y=0; Y < H; Y++ ) { for ( int X=0; X < W; X++ ) { C.x = R.ReadSingle(); C.y = R.ReadSingle(); C.z = R.ReadSingle(); C.w = R.ReadSingle(); Wr.Write( C.x ); Wr.Write( C.y ); Wr.Write( C.z ); Wr.Write( C.w ); } } } } return Image2Texture( (uint) ImageWidth, (uint) ImageHeight, PIXEL_FORMAT.RGBA32_FLOAT, Mips ); } }
void LoadProbePixels(FileInfo _FileName) { if (m_Tex_CubeMap != null) { m_Tex_CubeMap.Dispose(); m_Tex_CubeMap = null; } if (m_SB_Samples != null) { m_SB_Samples.Dispose(); m_SB_Samples = null; } if (m_SB_EmissiveSurfaces != null) { m_SB_EmissiveSurfaces.Dispose(); m_SB_EmissiveSurfaces = null; } using (FileStream S = _FileName.OpenRead()) using (BinaryReader R = new BinaryReader(S)) { ////////////////////////////////////////////////////////////////// // Read pixels Pixel[][,] CubeMapFaces = new Pixel[6][, ]; int CubeMapSize = R.ReadInt32(); for (int CubeMapFaceIndex = 0; CubeMapFaceIndex < 6; CubeMapFaceIndex++) { Pixel[,] Face = new Pixel[CubeMapSize, CubeMapSize]; CubeMapFaces[CubeMapFaceIndex] = Face; for (int Y = 0; Y < CubeMapSize; Y++) { for (int X = 0; X < CubeMapSize; X++) { Face[X, Y].ParentSampleIndex = R.ReadUInt32(); Face[X, Y].UsedForSampling = R.ReadBoolean(); Face[X, Y].Position.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); Face[X, Y].Normal.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); Face[X, Y].Albedo.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); Face[X, Y].F0.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); Face[X, Y].StaticLitColor.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); Face[X, Y].SmoothedStaticLitColor.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); Face[X, Y].FaceIndex = R.ReadUInt32(); Face[X, Y].EmissiveMatID = R.ReadUInt32(); Face[X, Y].NeighborProbeID = R.ReadUInt32(); Face[X, Y].NeighborProbeDistance = R.ReadSingle(); Face[X, Y].VoronoiProbeID = R.ReadUInt32(); Face[X, Y].Importance = R.ReadDouble(); Face[X, Y].Distance = R.ReadSingle(); Face[X, Y].SmoothedDistance = R.ReadSingle(); Face[X, Y].Infinity = R.ReadByte() != 0; Face[X, Y].SmoothedInfinity = R.ReadSingle(); } } } List <PixelsBuffer> Content = new List <PixelsBuffer>(); float4 Value = new float4(); for (int CubeIndex = 0; CubeIndex < 8; CubeIndex++) { for (int CubeMapFaceIndex = 0; CubeMapFaceIndex < 6; CubeMapFaceIndex++) { PixelsBuffer Buff = new PixelsBuffer(CubeMapSize * CubeMapSize * 16); Content.Add(Buff); using (BinaryWriter W = Buff.OpenStreamWrite()) { for (int Y = 0; Y < CubeMapSize; Y++) { for (int X = 0; X < CubeMapSize; X++) { Pixel P = CubeMapFaces[CubeMapFaceIndex][X, Y]; switch (CubeIndex) { case 0: Value.Set(P.Position, P.Distance); break; case 1: Value.Set(P.Normal, P.SmoothedDistance); break; case 2: Value.Set(P.Albedo, P.SmoothedInfinity); break; case 3: Value.Set(P.StaticLitColor, (float)P.ParentSampleIndex); break; case 4: Value.Set(P.SmoothedStaticLitColor, (float)P.Importance); break; case 5: Value.Set(P.UsedForSampling ? 1 : 0, P.Infinity ? 1 : 0, (float)P.FaceIndex, (float)P.VoronoiProbeID); break; case 6: Value.Set(P.F0, (float)P.NeighborProbeID); break; case 7: Value.Set(P.NeighborProbeDistance, 0, 0, 0); break; } W.Write(Value.x); W.Write(Value.y); W.Write(Value.z); W.Write(Value.w); } } } } } m_Tex_CubeMap = new Texture2D(m_Device, CubeMapSize, CubeMapSize, -6 * 8, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, false, Content.ToArray()); ////////////////////////////////////////////////////////////////// // Read samples int SamplesCount = (int)R.ReadUInt32(); m_SB_Samples = new StructuredBuffer <SB_Sample>(m_Device, SamplesCount, true); for (int SampleIndex = 0; SampleIndex < SamplesCount; SampleIndex++) { m_SB_Samples.m[SampleIndex].ID = (uint)SampleIndex; m_SB_Samples.m[SampleIndex].Position.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); m_SB_Samples.m[SampleIndex].Normal.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); m_SB_Samples.m[SampleIndex].Albedo.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); m_SB_Samples.m[SampleIndex].F0.Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); m_SB_Samples.m[SampleIndex].PixelsCount = R.ReadUInt32(); m_SB_Samples.m[SampleIndex].SHFactor = R.ReadSingle(); m_SB_Samples.m[SampleIndex].SH0.Set((float)R.ReadDouble(), (float)R.ReadDouble(), (float)R.ReadDouble()); m_SB_Samples.m[SampleIndex].SH1.Set((float)R.ReadDouble(), (float)R.ReadDouble(), (float)R.ReadDouble()); m_SB_Samples.m[SampleIndex].SH2.Set((float)R.ReadDouble(), (float)R.ReadDouble(), (float)R.ReadDouble()); } m_SB_Samples.Write(); } }
protected override void OnLoad(EventArgs e) { base.OnLoad(e); try { // Initialize the device m_device = new Device(); m_device.Init(graphPanel.Handle, false, true); // Create the render shaders try { Shader.WarningAsError = false; m_shader_RenderSphere = new Shader(m_device, new System.IO.FileInfo(@"./Shaders/RenderSphere.hlsl"), VERTEX_FORMAT.Pt4, "VS", null, "PS"); m_shader_RenderScene = new Shader(m_device, new System.IO.FileInfo(@"./Shaders/RenderScene.hlsl"), VERTEX_FORMAT.Pt4, "VS", null, "PS"); m_shader_RenderLDR = new Shader(m_device, new System.IO.FileInfo(@"./Shaders/RenderLDR.hlsl"), VERTEX_FORMAT.Pt4, "VS", null, "PS"); } catch (Exception _e) { throw new Exception("Failed to compile shader! " + _e.Message); } // Create CB m_CB_Render = new ConstantBuffer <CB_Main>(m_device, 0); // Create textures LoadHDRImage(); m_Tex_HDRBuffer = new Texture2D(m_device, (uint)graphPanel.Width, (uint)graphPanel.Height, 2, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, null); { // Build noise texture SimpleRNG.SetSeed(1U); PixelsBuffer content = new PixelsBuffer(256 * 256 * 16); using (System.IO.BinaryWriter W = content.OpenStreamWrite()) for (int i = 0; i < 256 * 256; i++) { W.Write((float)SimpleRNG.GetUniform()); W.Write((float)SimpleRNG.GetUniform()); W.Write((float)SimpleRNG.GetUniform()); W.Write((float)SimpleRNG.GetUniform()); } m_Tex_Noise = new Texture2D(m_device, 256, 256, 1, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content }); } // Build SH coeffs const int ORDERS = 20; { const int TABLE_SIZE = 64; // Load A coeffs into a texture array float[,,] A = new float[TABLE_SIZE, TABLE_SIZE, ORDERS]; // using ( System.IO.FileStream S = new System.IO.FileInfo( @"ConeTable_cosAO_order20.float" ).OpenRead() ) using (System.IO.FileStream S = new System.IO.FileInfo(@"ConeTable_cosTheta_order20.float").OpenRead()) using (System.IO.BinaryReader R = new System.IO.BinaryReader(S)) { for (int thetaIndex = 0; thetaIndex < TABLE_SIZE; thetaIndex++) { for (int AOIndex = 0; AOIndex < TABLE_SIZE; AOIndex++) { for (int order = 0; order < ORDERS; order++) { A[thetaIndex, AOIndex, order] = R.ReadSingle(); } } } } PixelsBuffer[] coeffSlices = new PixelsBuffer[5]; // 5 slices of 4 coeffs each to get our 20 orders for (int sliceIndex = 0; sliceIndex < coeffSlices.Length; sliceIndex++) { PixelsBuffer coeffSlice = new PixelsBuffer(TABLE_SIZE * TABLE_SIZE * 16); coeffSlices[sliceIndex] = coeffSlice; using (System.IO.BinaryWriter W = coeffSlice.OpenStreamWrite()) { for (int thetaIndex = 0; thetaIndex < TABLE_SIZE; thetaIndex++) { for (int AOIndex = 0; AOIndex < TABLE_SIZE; AOIndex++) { W.Write(A[thetaIndex, AOIndex, 4 * sliceIndex + 0]); W.Write(A[thetaIndex, AOIndex, 4 * sliceIndex + 1]); W.Write(A[thetaIndex, AOIndex, 4 * sliceIndex + 2]); W.Write(A[thetaIndex, AOIndex, 4 * sliceIndex + 3]); } } } } m_Tex_ACoeffs = new Texture2D(m_device, 64, 64, coeffSlices.Length, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, coeffSlices); } { // Load environment coeffs into a constant buffer float3[] coeffs = new float3[ORDERS * ORDERS]; using (System.IO.FileStream S = new System.IO.FileInfo(@"Ennis_order20.float3").OpenRead()) using (System.IO.BinaryReader R = new System.IO.BinaryReader(S)) for (int coeffIndex = 0; coeffIndex < ORDERS * ORDERS; coeffIndex++) { coeffs[coeffIndex].Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); } // Write into a raw byte[] byte[] rawContent = new byte[400 * 4 * 4]; using (System.IO.MemoryStream MS = new System.IO.MemoryStream(rawContent)) using (System.IO.BinaryWriter W = new System.IO.BinaryWriter(MS)) { for (int coeffIndex = 0; coeffIndex < ORDERS * ORDERS; coeffIndex++) { W.Write(coeffs[coeffIndex].x); W.Write(coeffs[coeffIndex].y); W.Write(coeffs[coeffIndex].z); W.Write(0.0f); } } m_CB_Coeffs = new RawConstantBuffer(m_device, 1, rawContent.Length); m_CB_Coeffs.UpdateData(rawContent); } // Create camera + manipulator m_camera.CreatePerspectiveCamera(0.5f * (float)Math.PI, (float)graphPanel.Width / graphPanel.Height, 0.01f, 100.0f); m_camera.CameraTransformChanged += m_camera_CameraTransformChanged; m_cameraManipulator.Attach(graphPanel, m_camera); m_cameraManipulator.InitializeCamera(-2.0f * float3.UnitZ, float3.Zero, float3.UnitY); m_camera_CameraTransformChanged(null, EventArgs.Empty); // Start rendering Application.Idle += Application_Idle; } catch (Exception _e) { MessageBox.Show("Failed to initialize D3D renderer!\r\nReason: " + _e.Message); } }
void LoadProbePixels( FileInfo _FileName ) { if ( m_Tex_CubeMap != null ) { m_Tex_CubeMap.Dispose(); m_Tex_CubeMap = null; } if ( m_SB_Samples != null ) { m_SB_Samples.Dispose(); m_SB_Samples = null; } if ( m_SB_EmissiveSurfaces != null ) { m_SB_EmissiveSurfaces.Dispose(); m_SB_EmissiveSurfaces = null; } using ( FileStream S = _FileName.OpenRead() ) using ( BinaryReader R = new BinaryReader( S ) ) { ////////////////////////////////////////////////////////////////// // Read pixels Pixel[][,] CubeMapFaces = new Pixel[6][,]; int CubeMapSize = R.ReadInt32(); for ( int CubeMapFaceIndex=0; CubeMapFaceIndex < 6; CubeMapFaceIndex++ ) { Pixel[,] Face = new Pixel[CubeMapSize,CubeMapSize]; CubeMapFaces[CubeMapFaceIndex] = Face; for ( int Y=0; Y < CubeMapSize; Y++ ) for ( int X=0; X < CubeMapSize; X++ ) { Face[X,Y].ParentSampleIndex = R.ReadUInt32(); Face[X,Y].UsedForSampling = R.ReadBoolean(); Face[X,Y].Position.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); Face[X,Y].Normal.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); Face[X,Y].Albedo.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); Face[X,Y].F0.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); Face[X,Y].StaticLitColor.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); Face[X,Y].SmoothedStaticLitColor.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); Face[X,Y].FaceIndex = R.ReadUInt32(); Face[X,Y].EmissiveMatID = R.ReadUInt32(); Face[X,Y].NeighborProbeID = R.ReadUInt32(); Face[X,Y].NeighborProbeDistance = R.ReadSingle(); Face[X,Y].VoronoiProbeID = R.ReadUInt32(); Face[X,Y].Importance = R.ReadDouble(); Face[X,Y].Distance = R.ReadSingle(); Face[X,Y].SmoothedDistance = R.ReadSingle(); Face[X,Y].Infinity = R.ReadByte() != 0; Face[X,Y].SmoothedInfinity = R.ReadSingle(); } } List<PixelsBuffer> Content = new List<PixelsBuffer>(); float4 Value = new float4(); for ( int CubeIndex=0; CubeIndex < 8; CubeIndex++ ) { for ( int CubeMapFaceIndex=0; CubeMapFaceIndex < 6; CubeMapFaceIndex++ ) { PixelsBuffer Buff = new PixelsBuffer( CubeMapSize*CubeMapSize * 16 ); Content.Add( Buff ); using ( BinaryWriter W = Buff.OpenStreamWrite() ) { for ( int Y=0; Y < CubeMapSize; Y++ ) for ( int X=0; X < CubeMapSize; X++ ) { Pixel P = CubeMapFaces[CubeMapFaceIndex][X,Y]; switch ( CubeIndex ) { case 0: Value.Set( P.Position, P.Distance ); break; case 1: Value.Set( P.Normal, P.SmoothedDistance ); break; case 2: Value.Set( P.Albedo, P.SmoothedInfinity ); break; case 3: Value.Set( P.StaticLitColor, (float) P.ParentSampleIndex ); break; case 4: Value.Set( P.SmoothedStaticLitColor, (float) P.Importance ); break; case 5: Value.Set( P.UsedForSampling ? 1 : 0, P.Infinity ? 1 : 0, (float) P.FaceIndex, (float) P.VoronoiProbeID ); break; case 6: Value.Set( P.F0, (float) P.NeighborProbeID ); break; case 7: Value.Set( P.NeighborProbeDistance, 0, 0, 0 ); break; } W.Write( Value.x ); W.Write( Value.y ); W.Write( Value.z ); W.Write( Value.w ); } } } } m_Tex_CubeMap = new Texture2D( m_Device, CubeMapSize, CubeMapSize, -6*8, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, false, Content.ToArray() ); ////////////////////////////////////////////////////////////////// // Read samples int SamplesCount = (int) R.ReadUInt32(); m_SB_Samples = new StructuredBuffer<SB_Sample>( m_Device, SamplesCount, true ); for ( int SampleIndex=0; SampleIndex < SamplesCount; SampleIndex++ ) { m_SB_Samples.m[SampleIndex].ID = (uint) SampleIndex; m_SB_Samples.m[SampleIndex].Position.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); m_SB_Samples.m[SampleIndex].Normal.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); m_SB_Samples.m[SampleIndex].Albedo.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); m_SB_Samples.m[SampleIndex].F0.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); m_SB_Samples.m[SampleIndex].PixelsCount = R.ReadUInt32(); m_SB_Samples.m[SampleIndex].SHFactor = R.ReadSingle(); m_SB_Samples.m[SampleIndex].SH0.Set( (float) R.ReadDouble(), (float) R.ReadDouble(), (float) R.ReadDouble() ); m_SB_Samples.m[SampleIndex].SH1.Set( (float) R.ReadDouble(), (float) R.ReadDouble(), (float) R.ReadDouble() ); m_SB_Samples.m[SampleIndex].SH2.Set( (float) R.ReadDouble(), (float) R.ReadDouble(), (float) R.ReadDouble() ); } m_SB_Samples.Write(); } }
/// <summary> /// Builds the surface texture from an actual image file /// </summary> /// <param name="_textureFileName"></param> /// <param name="_pixelSize">Size of a pixel, assuming the maximum height is 1</param> public unsafe void BuildSurfaceFromTexture( string _textureFileName, float _pixelSize ) { if ( m_Tex_Heightfield != null ) m_Tex_Heightfield.Dispose(); // We will create a new one so dispose of the old one... // Read the bitmap int W, H; float4[,] Content = null; using ( Bitmap BM = Bitmap.FromFile( _textureFileName ) as Bitmap ) { W = BM.Width; H = BM.Height; Content = new float4[W,H]; BitmapData LockedBitmap = BM.LockBits( new Rectangle( 0, 0, W, H ), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb ); byte R, G, B, A; for ( int Y=0; Y < H; Y++ ) { byte* pScanline = (byte*) LockedBitmap.Scan0.ToPointer() + Y*LockedBitmap.Stride; for ( int X=0; X < W; X++ ) { // Read in shitty order B = *pScanline++; G = *pScanline++; R = *pScanline++; A = *pScanline++; // Use this if you really need RGBA data // Content[X,Y].Set( R / 255.0f, G / 255.0f, B / 255.0f, A / 255.0f ); // But assuming it's a height field, we only store one component into alpha Content[X,Y].Set( 0, 0, 0, R / 255.0f ); // Use Red as height } } BM.UnlockBits( LockedBitmap ); } // Build normal (shitty version) float Hx0, Hx1, Hy0, Hy1; float3 dNx = new float3( 2.0f * _pixelSize, 0, 0 ); float3 dNy = new float3( 0, 2.0f * _pixelSize, 0 ); float3 N; for ( int Y=0; Y < H; Y++ ) { int pY = (Y+H-1) % H; int nY = (Y+1) % H; for ( int X=0; X < W; X++ ) { int pX = (X+W-1) % W; int nX = (X+1) % W; Hx0 = Content[pX,Y].w; Hx1 = Content[nX,Y].w; Hy0 = Content[X,pY].w; Hy1 = Content[X,nY].w; dNx.z = Hx1 - Hx0; dNy.z = Hy0 - Hy1; // Assuming +Y is upward N = dNx.Cross( dNy ); N = N.Normalized; Content[X,Y].x = N.x; Content[X,Y].y = N.y; Content[X,Y].z = N.z; } } // Build the texture from the array PixelsBuffer Buf = new PixelsBuffer( W*H*16 ); using ( BinaryWriter Writer = Buf.OpenStreamWrite() ) for ( int Y=0; Y < H; Y++ ) for ( int X=0; X < W; X++ ) { float4 pixel = Content[X,Y]; Writer.Write( pixel.x ); Writer.Write( pixel.y ); Writer.Write( pixel.z ); Writer.Write( pixel.w ); } Buf.CloseStream(); m_Tex_Heightfield = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, false, new PixelsBuffer[] { Buf } ); }
/// <summary> /// Builds a heightfield whose heights are distributed according to the following probability (a.k.a. the normal distribution with sigma=1 and µ=0): /// p(height) = exp( -0.5*height^2 ) / sqrt(2PI) /// /// From "2015 Heitz - Generating Procedural Beckmann Surfaces" /// </summary> /// <param name="_roughness"></param> /// <remarks>Only isotropic roughness is supported</remarks> public void BuildBeckmannSurfaceTexture( float _roughness ) { m_internalChange = true; // Shouldn't happen but modifying the slider value may trigger a call to this function again, this flag prevents it // Mirror current roughness floatTrackbarControlBeckmannRoughness.Value = _roughness; // Precompute stuff that resemble a lot to the Box-Muller algorithm to generate normal distribution random values WMath.SimpleRNG.SetSeed( 521288629, 362436069 ); for ( int i=0; i < m_SB_Beckmann.m.Length; i++ ) { double U0 = WMath.SimpleRNG.GetUniform(); double U1 = WMath.SimpleRNG.GetUniform(); double U2 = WMath.SimpleRNG.GetUniform(); m_SB_Beckmann.m[i].m_phase = (float) (2.0 * Math.PI * U0); // Phase double theta = 2.0 * Math.PI * U1; double radius = Math.Sqrt( -Math.Log( U2 ) ); m_SB_Beckmann.m[i].m_frequencyX = (float) (radius * Math.Cos( theta ) * _roughness); // Frequency in X direction m_SB_Beckmann.m[i].m_frequencyY = (float) (radius * Math.Sin( theta ) * _roughness); // Frequency in Y direction } m_SB_Beckmann.Write(); m_SB_Beckmann.SetInput( 0 ); #if true if ( m_Tex_Heightfield == null ) m_Tex_Heightfield = new Texture2D( m_Device, HEIGHTFIELD_SIZE, HEIGHTFIELD_SIZE, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, true, null ); // Run the CS if ( m_Shader_ComputeBeckmannSurface.Use() ) { m_Tex_Heightfield.SetCSUAV( 0 ); float size = floatTrackbarControlBeckmannSizeFactor.Value * HEIGHTFIELD_SIZE; // m_CB_ComputeBeckmann.m._Position_Size.Set( -128.0f, -128.0f, 256.0f, 256.0f ); m_CB_ComputeBeckmann.m._Position_Size.Set( -0.5f * size, -0.5f * size, size, size ); m_CB_ComputeBeckmann.m._HeightFieldResolution = HEIGHTFIELD_SIZE; m_CB_ComputeBeckmann.m._SamplesCount = (uint) m_SB_Beckmann.m.Length; m_CB_ComputeBeckmann.UpdateData(); m_Shader_ComputeBeckmannSurface.Dispatch( HEIGHTFIELD_SIZE >> 4, HEIGHTFIELD_SIZE >> 4, 1 ); m_Tex_Heightfield.RemoveFromLastAssignedSlotUAV(); } #else // CPU version PixelsBuffer Content = new PixelsBuffer( HEIGHTFIELD_SIZE*HEIGHTFIELD_SIZE*System.Runtime.InteropServices.Marshal.SizeOf(typeof(float)) ); double scale = Math.Sqrt( 2.0 / N ); // Generate heights float range = 128.0f; float2 pos; float height; float minHeight = float.MaxValue, maxHeight = -float.MaxValue; double accum; using ( BinaryWriter W = Content.OpenStreamWrite() ) { for ( int Y=0; Y < HEIGHTFIELD_SIZE; Y++ ) { pos.y = range * (2.0f * Y / (HEIGHTFIELD_SIZE-1) - 1.0f); for ( int X=0; X < HEIGHTFIELD_SIZE; X++ ) { pos.x = range * (2.0f * X / (HEIGHTFIELD_SIZE-1) - 1.0f); // height = (float) WMath.SimpleRNG.GetNormal(); // height = (float) GenerateNormalDistributionHeight(); accum = 0.0; for ( int i=0; i < N; i++ ) { accum += Math.Cos( m_phi[i] + pos.x * m_fx[i] + pos.y * m_fy[i] ); } height = (float) (scale * accum); minHeight = Math.Min( minHeight, height ); maxHeight = Math.Max( maxHeight, height ); W.Write( height ); } } } Content.CloseStream(); m_Tex_Heightfield = new Texture2D( m_Device, HEIGHTFIELD_SIZE, HEIGHTFIELD_SIZE, 1, 1, PIXEL_FORMAT.R32_FLOAT, false, false, new PixelsBuffer[] { Content } ); #endif m_internalChange = false; }
protected override void OnLoad( EventArgs e ) { base.OnLoad( e ); try { // Initialize the device m_device = new Device(); m_device.Init( graphPanel.Handle, false, true ); // Create the render shaders try { Shader.WarningAsError = false; m_shader_RenderSphere = new Shader( m_device, new System.IO.FileInfo( @"./Shaders/RenderSphere.hlsl" ), VERTEX_FORMAT.Pt4, "VS", null, "PS", null ); m_shader_RenderScene = new Shader( m_device, new System.IO.FileInfo( @"./Shaders/RenderScene.hlsl" ), VERTEX_FORMAT.Pt4, "VS", null, "PS", null ); m_shader_RenderLDR = new Shader( m_device, new System.IO.FileInfo( @"./Shaders/RenderLDR.hlsl" ), VERTEX_FORMAT.Pt4, "VS", null, "PS", null ); } catch ( Exception _e ) { throw new Exception( "Failed to compile shader! " + _e.Message ); } // Create CB m_CB_Render = new ConstantBuffer< CB_Main >( m_device, 0 ); // Create textures LoadHDRImage(); m_Tex_HDRBuffer = new Texture2D( m_device, (uint) graphPanel.Width, (uint) graphPanel.Height, 2, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, false, null ); { // Build noise texture SimpleRNG.SetSeed( 1U ); PixelsBuffer content = new PixelsBuffer( 256*256*16 ); using ( System.IO.BinaryWriter W = content.OpenStreamWrite() ) for ( int i=0; i < 256*256; i++ ) { W.Write( (float) SimpleRNG.GetUniform() ); W.Write( (float) SimpleRNG.GetUniform() ); W.Write( (float) SimpleRNG.GetUniform() ); W.Write( (float) SimpleRNG.GetUniform() ); } m_Tex_Noise = new Texture2D( m_device, 256, 256, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, false, new PixelsBuffer[] { content } ); } // Build SH coeffs const int ORDERS = 20; { const int TABLE_SIZE = 64; // Load A coeffs into a texture array float[,,] A = new float[TABLE_SIZE,TABLE_SIZE,ORDERS]; // using ( System.IO.FileStream S = new System.IO.FileInfo( @"ConeTable_cosAO_order20.float" ).OpenRead() ) using ( System.IO.FileStream S = new System.IO.FileInfo( @"ConeTable_cosTheta_order20.float" ).OpenRead() ) using ( System.IO.BinaryReader R = new System.IO.BinaryReader( S ) ) { for ( int thetaIndex=0; thetaIndex < TABLE_SIZE; thetaIndex++ ) for ( int AOIndex=0; AOIndex < TABLE_SIZE; AOIndex++ ) { for ( int order=0; order < ORDERS; order++ ) A[thetaIndex,AOIndex,order] = R.ReadSingle(); } } PixelsBuffer[] coeffSlices = new PixelsBuffer[5]; // 5 slices of 4 coeffs each to get our 20 orders for ( int sliceIndex=0; sliceIndex < coeffSlices.Length; sliceIndex++ ) { PixelsBuffer coeffSlice = new PixelsBuffer( TABLE_SIZE*TABLE_SIZE*16 ); coeffSlices[sliceIndex] = coeffSlice; using ( System.IO.BinaryWriter W = coeffSlice.OpenStreamWrite() ) { for ( int thetaIndex=0; thetaIndex < TABLE_SIZE; thetaIndex++ ) for ( int AOIndex=0; AOIndex < TABLE_SIZE; AOIndex++ ) { W.Write( A[thetaIndex,AOIndex,4*sliceIndex+0] ); W.Write( A[thetaIndex,AOIndex,4*sliceIndex+1] ); W.Write( A[thetaIndex,AOIndex,4*sliceIndex+2] ); W.Write( A[thetaIndex,AOIndex,4*sliceIndex+3] ); } } } m_Tex_ACoeffs = new Texture2D( m_device, 64, 64, coeffSlices.Length, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, false, coeffSlices ); } { // Load environment coeffs into a constant buffer float3[] coeffs = new float3[ORDERS*ORDERS]; using ( System.IO.FileStream S = new System.IO.FileInfo( @"Ennis_order20.float3" ).OpenRead() ) using ( System.IO.BinaryReader R = new System.IO.BinaryReader( S ) ) for ( int coeffIndex=0; coeffIndex < ORDERS*ORDERS; coeffIndex++ ) coeffs[coeffIndex].Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); // Write into a raw byte[] byte[] rawContent = new byte[400 * 4 * 4]; using ( System.IO.MemoryStream MS = new System.IO.MemoryStream( rawContent ) ) using ( System.IO.BinaryWriter W = new System.IO.BinaryWriter( MS ) ) { for ( int coeffIndex=0; coeffIndex < ORDERS*ORDERS; coeffIndex++ ) { W.Write( coeffs[coeffIndex].x ); W.Write( coeffs[coeffIndex].y ); W.Write( coeffs[coeffIndex].z ); W.Write( 0.0f ); } } m_CB_Coeffs = new RawConstantBuffer( m_device, 1, rawContent.Length ); m_CB_Coeffs.UpdateData( rawContent ); } // Create camera + manipulator m_camera.CreatePerspectiveCamera( 0.5f * (float) Math.PI, (float) graphPanel.Width / graphPanel.Height, 0.01f, 100.0f ); m_camera.CameraTransformChanged += m_camera_CameraTransformChanged; m_cameraManipulator.Attach( graphPanel, m_camera ); m_cameraManipulator.InitializeCamera( -2.0f * float3.UnitZ, float3.Zero, float3.UnitY ); m_camera_CameraTransformChanged( null, EventArgs.Empty ); // Start rendering Application.Idle += Application_Idle; } catch ( Exception _e ) { MessageBox.Show( "Failed to initialize D3D renderer!\r\nReason: " + _e.Message ); } }
public Texture2D PipoImage2Texture( System.IO.FileInfo _FileName ) { using ( System.IO.FileStream S = _FileName.OpenRead() ) using ( System.IO.BinaryReader R = new System.IO.BinaryReader( S ) ) { int W, H; W = R.ReadInt32(); H = R.ReadInt32(); PixelsBuffer Buff = new PixelsBuffer( (uint) (4 * W * H * 4) ); using ( System.IO.BinaryWriter Wr = Buff.OpenStreamWrite() ) { float4 C = new float4(); for ( int Y=0; Y < H; Y++ ) { for ( int X=0; X < W; X++ ) { C.x = R.ReadSingle(); C.y = R.ReadSingle(); C.z = R.ReadSingle(); C.w = R.ReadSingle(); Wr.Write( C.x ); Wr.Write( C.y ); Wr.Write( C.z ); Wr.Write( C.w ); } } } return Image2Texture( (uint) W, (uint) H, PIXEL_FORMAT.RGBA32_FLOAT, Buff ); } }
public Texture3D Pipu2Texture( System.IO.FileInfo _FileName ) { using ( System.IO.FileStream S = _FileName.OpenRead() ) using ( System.IO.BinaryReader R = new System.IO.BinaryReader( S ) ) { int SlicesCount = R.ReadInt32(); int W = R.ReadInt32(); int H = R.ReadInt32(); PixelsBuffer Slices = new PixelsBuffer( (uint) (4 * W * H * SlicesCount * 4) ); using ( System.IO.BinaryWriter Wr = Slices.OpenStreamWrite() ) { for ( int SliceIndex=0; SliceIndex < SlicesCount; SliceIndex++ ) { float4 C = new float4(); for ( int Y=0; Y < H; Y++ ) { for ( int X=0; X < W; X++ ) { C.x = R.ReadSingle(); C.y = R.ReadSingle(); C.z = R.ReadSingle(); C.w = R.ReadSingle(); Wr.Write( C.x ); Wr.Write( C.y ); Wr.Write( C.z ); Wr.Write( C.w ); } } } } return Image2Texture3D( (uint) W, (uint) H, (uint) SlicesCount, PIXEL_FORMAT.RGBA32_FLOAT, new PixelsBuffer[] { Slices } ); } }
private void Build3DDensityField() { PixelsBuffer DensityField = new PixelsBuffer( DENSITY_FIELD_SIZE*DENSITY_FIELD_SIZE*DENSITY_FIELD_HEIGHT ); byte D; float3 P; float3 C = new float3( 0.5f, 0.5f, 0.5f ); using ( System.IO.BinaryWriter W = DensityField.OpenStreamWrite() ) for ( int X=0; X < DENSITY_FIELD_SIZE; X++ ) { P.x = (0.5f+X) / DENSITY_FIELD_SIZE; for ( int Y=0; Y < DENSITY_FIELD_HEIGHT; Y++ ) { P.y = (0.5f+Y) / DENSITY_FIELD_HEIGHT; for ( int Z=0; Z < DENSITY_FIELD_SIZE; Z++ ) { P.z = (0.5f+Z) / DENSITY_FIELD_SIZE; // D = 0; // Empty for now: photons should go straight through! D = (byte) ((P - C).LengthSquared < 0.125f ? 255 : 0); W.Write( D ); } } } Reg( m_Tex_DensityField = new Texture3D( m_Device, DENSITY_FIELD_SIZE, DENSITY_FIELD_HEIGHT, DENSITY_FIELD_SIZE, 1, PIXEL_FORMAT.R8_UNORM, false, false, new PixelsBuffer[] { DensityField } ) ); DensityField.Dispose(); }
/* https://knarkowicz.wordpress.com/2014/12/27/analytical-dfg-term-for-ibl/ uint32_t ReverseBits( uint32_t v ) { v = ( ( v >> 1 ) & 0x55555555 ) | ( ( v & 0x55555555 ) << 1 ); v = ( ( v >> 2 ) & 0x33333333 ) | ( ( v & 0x33333333 ) << 2 ); v = ( ( v >> 4 ) & 0x0F0F0F0F ) | ( ( v & 0x0F0F0F0F ) << 4 ); v = ( ( v >> 8 ) & 0x00FF00FF ) | ( ( v & 0x00FF00FF ) << 8 ); v = ( v >> 16 ) | ( v << 16 ); return v; } float GSmith( float roughness, float ndotv, float ndotl ) { float const m2 = roughness * roughness; float const visV = ndotv + sqrt( ndotv * ( ndotv - ndotv * m2 ) + m2 ); float const visL = ndotl + sqrt( ndotl * ( ndotl - ndotl * m2 ) + m2 ); return 1.0f / ( visV * visL ); } int main() { float const MATH_PI = 3.14159f; unsigned const LUT_WIDTH = 128; unsigned const LUT_HEIGHT = 128; unsigned const sampleNum = 128; float lutData[ LUT_WIDTH * LUT_HEIGHT * 4 ]; for ( unsigned y = 0; y < LUT_HEIGHT; ++y ) { float const ndotv = ( y + 0.5f ) / LUT_WIDTH; for ( unsigned x = 0; x < LUT_WIDTH; ++x ) { float const gloss = ( x + 0.5f ) / LUT_HEIGHT; float const roughness = powf( 1.0f - gloss, 4.0f ); float const vx = sqrtf( 1.0f - ndotv * ndotv ); float const vy = 0.0f; float const vz = ndotv; float scale = 0.0f; float bias = 0.0f; for ( unsigned i = 0; i < sampleNum; ++i ) { float const e1 = (float) i / sampleNum; float const e2 = (float) ( (double) ReverseBits( i ) / (double) 0x100000000LL ); float const phi = 2.0f * MATH_PI * e1; float const cosPhi = cosf( phi ); float const sinPhi = sinf( phi ); float const cosTheta = sqrtf( ( 1.0f - e2 ) / ( 1.0f + ( roughness * roughness - 1.0f ) * e2 ) ); float const sinTheta = sqrtf( 1.0f - cosTheta * cosTheta ); float const hx = sinTheta * cosf( phi ); float const hy = sinTheta * sinf( phi ); float const hz = cosTheta; float const vdh = vx * hx + vy * hy + vz * hz; float const lx = 2.0f * vdh * hx - vx; float const ly = 2.0f * vdh * hy - vy; float const lz = 2.0f * vdh * hz - vz; float const ndotl = std::max( lz, 0.0f ); float const ndoth = std::max( hz, 0.0f ); float const vdoth = std::max( vdh, 0.0f ); if ( ndotl > 0.0f ) { float const gsmith = GSmith( roughness, ndotv, ndotl ); float const ndotlVisPDF = ndotl * gsmith * ( 4.0f * vdoth / ndoth ); float const fc = powf( 1.0f - vdoth, 5.0f ); scale += ndotlVisPDF * ( 1.0f - fc ); bias += ndotlVisPDF * fc; } } scale /= sampleNum; bias /= sampleNum; lutData[ x * 4 + y * LUT_WIDTH * 4 + 0 ] = scale; lutData[ x * 4 + y * LUT_WIDTH * 4 + 1 ] = bias; lutData[ x * 4 + y * LUT_WIDTH * 4 + 2 ] = 0.0f; lutData[ x * 4 + y * LUT_WIDTH * 4 + 3 ] = 0.0f; } } } */ #endif Texture2D BuildBRDFTexture( System.IO.FileInfo _TableFileName, uint _TableSize ) { float2[,] Table = new float2[_TableSize,_TableSize]; float MinA = 1, MaxA = 0; float MinB = 1, MaxB = 0; using ( System.IO.FileStream S = _TableFileName.OpenRead() ) using ( System.IO.BinaryReader R = new System.IO.BinaryReader( S ) ) for ( int Y=0; Y < _TableSize; Y++ ) for ( int X=0; X < _TableSize; X++ ) { float A = R.ReadSingle(); float B = R.ReadSingle(); Table[X,Y].x = A; Table[X,Y].y = B; MinA = Math.Min( MinA, A ); MaxA = Math.Max( MaxA, A ); MinB = Math.Min( MinB, B ); MaxB = Math.Max( MaxB, B ); } // MaxA = 1 // MaxB = 0.00014996325546887346 // MaxA = 1.0; // MaxB = 1.0; // Create the texture // PixelsBuffer Content = new PixelsBuffer( _TableSize*_TableSize*4 ); PixelsBuffer Content = new PixelsBuffer( (uint) (_TableSize*_TableSize*2*4) ); using ( System.IO.BinaryWriter W = Content.OpenStreamWrite() ) for ( int Y=0; Y < _TableSize; Y++ ) for ( int X=0; X < _TableSize; X++ ) { // W.Write( (ushort) (65535.0 * Table[X,Y].x / MaxA) ); // W.Write( (ushort) (65535.0 * Table[X,Y].y / MaxB) ); W.Write( Table[X,Y].x ); W.Write( Table[X,Y].y ); } // Texture2D Result = new Texture2D( m_Device, _TableSize, _TableSize, 1, 1, PIXEL_FORMAT.RG16_UNORM, false, false, new PixelsBuffer[] { Content } ); Texture2D Result = new Texture2D( m_Device, _TableSize, _TableSize, 1, 1, PIXEL_FORMAT.RG32_FLOAT, false, false, new PixelsBuffer[] { Content } ); return Result; }
void UpdateGroundTruth(float3 _rho) { float4[][,] groundTruth = m_owner.GenerateGroundTruth(_rho, m_rotatedLightSH); if (groundTruth == m_lastGroundTruth) { return; // No change } m_lastGroundTruth = groundTruth; if (m_tex_GroundTruth != null) { m_tex_GroundTruth.Dispose(); } int slicesCount = groundTruth.Length; uint W = (uint)groundTruth[0].GetLength(0); uint H = (uint)groundTruth[0].GetLength(1); PixelsBuffer[] content = new PixelsBuffer[slicesCount]; for (int sliceIndex = 0; sliceIndex < slicesCount; sliceIndex++) { float4[,] sourceContent = groundTruth[sliceIndex]; PixelsBuffer sliceContent = new PixelsBuffer(W * H * 16); content[sliceIndex] = sliceContent; using (System.IO.BinaryWriter Wr = sliceContent.OpenStreamWrite()) { for (uint Y = 0; Y < H; Y++) { for (uint X = 0; X < W; X++) { Wr.Write(sourceContent[X, Y].x); Wr.Write(sourceContent[X, Y].y); Wr.Write(sourceContent[X, Y].z); Wr.Write(sourceContent[X, Y].w); } } } } m_tex_GroundTruth = new Texture2D(m_device, W, H, slicesCount, 1, PIXEL_FORMAT.RGBA32F, COMPONENT_FORMAT.AUTO, false, false, content); /* if ( m_tex_GroundTruth != null && _rho == m_groundTruthLastRho ) * return; // Already computed! * if ( m_indirectPixelIndices == null || m_imageNormal == null ) * return; * * m_groundTruthLastRho = _rho; * * if ( m_tex_GroundTruth != null ) * m_tex_GroundTruth.Dispose(); * m_tex_GroundTruth = null; * * uint W = m_width; * uint H = m_height; * uint X, Y, rayIndex, neighborIndex; * * float3[] rays = GeneratorForm.GenerateRays( (int) m_raysCount, Mathf.ToRad( 179.0f ) ); * float3 lsRayDirection, wsRayDirection; * float3 radiance = float3.Zero; * float3 irradiance = float3.Zero; * float3 T = float3.One, B = float3.One, N = float3.One; * * // IMPORTANT * _rho /= Mathf.PI; // We actually need rho/PI to integrate the radiance * // IMPORTANT * * * const int BOUNCES_COUNT = 20; * float3[][,] irradianceBounces = new float3[1+BOUNCES_COUNT][,]; * * * ////////////////////////////////////////////////////////////////////////// * // 1] Retrieve world normals * // * float3[,] normals = new float3[W,H]; * float3[,] tangents = new float3[W,H]; * float3[,] biTangents = new float3[W,H]; * m_imageNormal.ReadPixels( ( uint _X, uint _Y, ref float4 _color ) => { * N = new float3( 2.0f * _color.x - 1.0f, 2.0f * _color.y - 1.0f, 2.0f * _color.z - 1.0f ); * BuildOrthonormalBasis( N, ref T, ref B ); * normals[_X,_Y] = N; * tangents[_X,_Y] = T; * biTangents[_X,_Y] = B; * } ); * * * ////////////////////////////////////////////////////////////////////////// * // 2] Compute irradiance perceived directly * { * float3[,] E0 = new float3[W,H]; * irradianceBounces[0] = E0; * * float normalizer = 2.0f * Mathf.PI // This factor is here because are actually integrating over the entire hemisphere of directions * // and we only accounted for cosine-weighted distribution along theta, we need to account for phi as well! * / m_raysCount; * * neighborIndex = 0; * for ( Y=0; Y < H; Y++ ) { * for ( X=0; X < W; X++ ) { * T = tangents[X,Y]; * B = biTangents[X,Y]; * N = normals[X,Y]; * * irradiance = float3.Zero; * for ( rayIndex=0; rayIndex < m_raysCount; rayIndex++ ) { * uint packedNeighborPixelPosition = m_indirectPixelIndices[neighborIndex++]; * if ( packedNeighborPixelPosition != ~0U ) * continue; // Obstructed * * lsRayDirection = rays[rayIndex]; * wsRayDirection = lsRayDirection.x * T + lsRayDirection.y * B + lsRayDirection.z * N; * EvaluateSHRadiance( ref wsRayDirection, ref radiance ); * * irradiance += radiance * lsRayDirection.z; // L(x,Wi) * (N.Wi) * } * irradiance *= normalizer; * E0[X,Y] = irradiance; * } * } * } * * ////////////////////////////////////////////////////////////////////////// * // ] * PixelsBuffer content = new PixelsBuffer( W*H*4*4 ); * using ( System.IO.BinaryWriter Wr = content.OpenStreamWrite() ) { * for ( Y=0; Y < H; Y++ ) { * for ( X=0; X < W; X++ ) { * Wr.Write( irradianceBounces[0][X,Y].x ); * Wr.Write( irradianceBounces[0][X,Y].y ); * Wr.Write( irradianceBounces[0][X,Y].z ); * Wr.Write( 1 ); * } * } * } * m_tex_GroundTruth = new Texture2D( m_device, W, H, 1, 1, PIXEL_FORMAT.RGBA32F, COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content } ); */ }
void CheckAgainstFFTW() { if (m_FFTW_2D == null) { m_FFTW_2D = new fftwlib.FFT2D(SIGNAL_SIZE_2D, SIGNAL_SIZE_2D); m_test_CPU = new Texture2D(m_device2D, SIGNAL_SIZE_2D, SIGNAL_SIZE_2D, 1, 1, ImageUtility.PIXEL_FORMAT.RG32F, ImageUtility.COMPONENT_FORMAT.AUTO, true, false, null); m_FFTW2D_Output = new Texture2D(m_device2D, SIGNAL_SIZE_2D, SIGNAL_SIZE_2D, 1, 1, ImageUtility.PIXEL_FORMAT.RG32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, true, null); } // Retrieve input as CPU-accessible m_test_CPU.CopyFrom(m_FFT2D_GPU.Input); PixelsBuffer bufferIn = m_test_CPU.MapRead(0, 0); m_test_CPU.UnMap(bufferIn); float2[,] input_GPU = new float2[SIGNAL_SIZE_2D, SIGNAL_SIZE_2D]; using (System.IO.BinaryReader R = bufferIn.OpenStreamRead()) for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { input_GPU[X, Y].Set(R.ReadSingle(), R.ReadSingle()); } } bufferIn.Dispose(); // Apply FFT m_FFT2D_GPU.FFT_GPUInOut(-1.0f); // Retrieve output as CPU-accessible m_test_CPU.CopyFrom(m_FFT2D_GPU.Output); PixelsBuffer bufferOut = m_test_CPU.MapRead(0, 0); m_test_CPU.UnMap(bufferOut); float2[,] output_GPU = new float2[SIGNAL_SIZE_2D, SIGNAL_SIZE_2D]; using (System.IO.BinaryReader R = bufferOut.OpenStreamRead()) for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { output_GPU[X, Y].Set(R.ReadSingle(), R.ReadSingle()); } } bufferOut.Dispose(); // Process input with FFTW m_FFTW_2D.FillInputSpatial((int _x, int _y, out float _r, out float _i) => { _r = input_GPU[_x, _y].x; _i = input_GPU[_x, _y].y; }); m_FFTW_2D.Execute(fftwlib.FFT2D.Normalization.DIMENSIONS_PRODUCT); float2[,] output_FFTW = new float2[SIGNAL_SIZE_2D, SIGNAL_SIZE_2D]; m_FFTW_2D.GetOutput((int _x, int _y, float _r, float _i) => { output_FFTW[_x, _y].Set(_r, _i); }); // Upload FFTW output to GPU bufferOut = m_test_CPU.MapWrite(0, 0); using (System.IO.BinaryWriter W = bufferOut.OpenStreamWrite()) for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { W.Write(output_FFTW[X, Y].x); W.Write(output_FFTW[X, Y].y); } } m_test_CPU.UnMap(bufferOut); bufferOut.Dispose(); m_FFTW2D_Output.CopyFrom(m_test_CPU); // Compare float sumSqDiffR = 0.0f; float sumSqDiffI = 0.0f; for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { float2 GPU = output_GPU[X, Y]; float2 FFTW = output_FFTW[X, Y]; float2 diff = GPU - FFTW; sumSqDiffR += diff.x * diff.x; sumSqDiffI += diff.y * diff.y; } } labelDiff2D.Text = "SqDiff = " + sumSqDiffR.ToString("G3") + " , " + sumSqDiffI.ToString("G3"); }
void BuildMSBRDF(DirectoryInfo _targetDirectory) { const uint COS_THETA_SUBDIVS_COUNT = 32; const uint ROUGHNESS_SUBDIVS_COUNT = 32; FileInfo MSBRDFFileName = new FileInfo(Path.Combine(_targetDirectory.FullName, "MSBRDF_E" + COS_THETA_SUBDIVS_COUNT + "x" + ROUGHNESS_SUBDIVS_COUNT + ".float")); FileInfo MSBRDFFileName2 = new FileInfo(Path.Combine(_targetDirectory.FullName, "MSBRDF_Eavg" + ROUGHNESS_SUBDIVS_COUNT + ".float")); #if PRECOMPUTE_BRDF const uint PHI_SUBDIVS_COUNT = 2 * 512; const uint THETA_SUBDIVS_COUNT = 64; const float dPhi = Mathf.TWOPI / PHI_SUBDIVS_COUNT; const float dTheta = Mathf.HALFPI / THETA_SUBDIVS_COUNT; const float dMu = 1.0f / THETA_SUBDIVS_COUNT; float[,] result = new float[COS_THETA_SUBDIVS_COUNT, ROUGHNESS_SUBDIVS_COUNT]; string dumpMathematica = "{"; for (uint Y = 0; Y < ROUGHNESS_SUBDIVS_COUNT; Y++) { float m = (float)Y / (ROUGHNESS_SUBDIVS_COUNT - 1); float m2 = Math.Max(0.01f, m * m); // float m2 = Math.Max( 0.01f, (float) Y / (ROUGHNESS_SUBDIVS_COUNT-1) ); // float m = Mathf.Sqrt( m2 ); // dumpMathematica += "{ "; // Start a new roughness line for (uint X = 0; X < COS_THETA_SUBDIVS_COUNT; X++) { float cosThetaO = (float)X / (COS_THETA_SUBDIVS_COUNT - 1); float sinThetaO = Mathf.Sqrt(1 - cosThetaO * cosThetaO); float NdotV = cosThetaO; float integral = 0.0f; // float integralNDF = 0.0f; for (uint THETA = 0; THETA < THETA_SUBDIVS_COUNT; THETA++) { // float thetaI = Mathf.HALFPI * (0.5f+THETA) / THETA_SUBDIVS_COUNT; // float cosThetaI = Mathf.Cos( thetaI ); // float sinThetaI = Mathf.Sin( thetaI ); // Use cosine-weighted sampling float sqCosThetaI = (0.5f + THETA) / THETA_SUBDIVS_COUNT; float cosThetaI = Mathf.Sqrt(sqCosThetaI); float sinThetaI = Mathf.Sqrt(1 - sqCosThetaI); float NdotL = cosThetaI; for (uint PHI = 0; PHI < PHI_SUBDIVS_COUNT; PHI++) { float phi = Mathf.TWOPI * PHI / PHI_SUBDIVS_COUNT; // Compute cos(theta_h) = Omega_h.N where Omega_h = (Omega_i + Omega_o) / ||Omega_i + Omega_o|| is the half vector and N the surface normal float cosThetaH = (cosThetaI + cosThetaO) / Mathf.Sqrt(2 * (1 + cosThetaO * cosThetaI + sinThetaO * sinThetaI * Mathf.Sin(phi))); // float3 omega_i = new float3( sinThetaI * Mathf.Cos( phi ), sinThetaI * Mathf.Sin( phi ), cosThetaI ); // float3 omega_o = new float3( sinThetaO, 0, cosThetaO ); // float3 omega_h = (omega_i + omega_o).Normalized; // float cosThetaH = omega_h.z; // Compute GGX NDF float den = 1 - cosThetaH * cosThetaH * (1 - m2); float NDF = m2 / (Mathf.PI * den * den); // Compute Smith shadowing/masking float Smith_i_den = NdotL + Mathf.Sqrt(m2 + (1 - m2) * NdotL * NdotL); float Smith_o_den = NdotV + Mathf.Sqrt(m2 + (1 - m2) * NdotV * NdotV); // Full BRDF is thus... float GGX = NDF / (Smith_i_den * Smith_o_den); // integral += GGX * cosThetaI * sinThetaI; integral += GGX; } // integralNDF += Mathf.TWOPI * m2 * cosThetaI * sinThetaI / (Mathf.PI * Mathf.Pow( cosThetaI*cosThetaI * (m2 - 1) + 1, 2.0f )); } // Finalize // integral *= dTheta * dPhi; integral *= 0.5f * dMu * dPhi; // Cosine-weighted sampling has a 0.5 factor! // integralNDF *= dTheta; result[X, Y] = integral; dumpMathematica += "{ " + cosThetaO + ", " + m + ", " + integral + "}, "; } } dumpMathematica = dumpMathematica.Remove(dumpMathematica.Length - 2); // Remove last comma dumpMathematica += " };"; // Dump as binary using (FileStream S = MSBRDFFileName.Create()) using (BinaryWriter W = new BinaryWriter(S)) { for (uint Y = 0; Y < ROUGHNESS_SUBDIVS_COUNT; Y++) { for (uint X = 0; X < COS_THETA_SUBDIVS_COUNT; X++) { W.Write(result[X, Y]); } } } ////////////////////////////////////////////////////////////////////////// // Compute average irradiance based on roughness, re-using the computed results const uint THETA_SUBDIVS_COUNT2 = 512; float dTheta2 = Mathf.HALFPI / THETA_SUBDIVS_COUNT2; float[] resultAvg = new float[ROUGHNESS_SUBDIVS_COUNT]; for (uint X = 0; X < ROUGHNESS_SUBDIVS_COUNT; X++) { float integral = 0.0f; for (uint THETA = 0; THETA < THETA_SUBDIVS_COUNT2; THETA++) { float thetaO = Mathf.HALFPI * (0.5f + THETA) / THETA_SUBDIVS_COUNT2; float cosThetaO = Mathf.Cos(thetaO); float sinThetaO = Mathf.Sin(thetaO); // Sample previously computed table float i = cosThetaO * COS_THETA_SUBDIVS_COUNT; uint i0 = Math.Min(COS_THETA_SUBDIVS_COUNT - 1, (uint)Mathf.Floor(i)); uint i1 = Math.Min(COS_THETA_SUBDIVS_COUNT - 1, i0 + 1); float E = (1 - i) * result[i0, X] + i * result[i1, X]; integral += E * cosThetaO * sinThetaO; } // Finalize integral *= Mathf.TWOPI * dTheta2; resultAvg[X] = integral; } // Dump as binary using (FileStream S = MSBRDFFileName2.Create()) using (BinaryWriter W = new BinaryWriter(S)) { for (uint X = 0; X < ROUGHNESS_SUBDIVS_COUNT; X++) { W.Write(resultAvg[X]); } } #endif // Build irradiance complement texture using (PixelsBuffer content = new PixelsBuffer(COS_THETA_SUBDIVS_COUNT * ROUGHNESS_SUBDIVS_COUNT * 4)) { using (FileStream S = MSBRDFFileName.OpenRead()) using (BinaryReader R = new BinaryReader(S)) using (BinaryWriter W = content.OpenStreamWrite()) { for (uint Y = 0; Y < ROUGHNESS_SUBDIVS_COUNT; Y++) { for (uint X = 0; X < COS_THETA_SUBDIVS_COUNT; X++) { W.Write(R.ReadSingle()); } } } m_tex_IrradianceComplement = new Texture2D(m_Device, COS_THETA_SUBDIVS_COUNT, ROUGHNESS_SUBDIVS_COUNT, 1, 1, ImageUtility.PIXEL_FORMAT.R32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content }); } // Build average irradiance texture using (PixelsBuffer content = new PixelsBuffer(ROUGHNESS_SUBDIVS_COUNT * 4)) { using (FileStream S = MSBRDFFileName2.OpenRead()) using (BinaryReader R = new BinaryReader(S)) using (BinaryWriter W = content.OpenStreamWrite()) { for (uint X = 0; X < ROUGHNESS_SUBDIVS_COUNT; X++) { W.Write(R.ReadSingle()); } } ////////////////////////////////////////////////////////////////////////// // Check single-scattering and multiple-scattering BRDFs are actual complements // /* * for ( uint Y=0; Y < ROUGHNESS_SUBDIVS_COUNT; Y++ ) { * float m = (float) Y / (ROUGHNESS_SUBDIVS_COUNT-1); * float m2 = Math.Max( 0.01f, m*m ); * * for ( uint X=0; X < COS_THETA_SUBDIVS_COUNT; X++ ) { * float cosThetaO = (float) X / (COS_THETA_SUBDIVS_COUNT-1); * float sinThetaO = Mathf.Sqrt( 1 - cosThetaO*cosThetaO ); * * const uint THETA_SUBDIVS_COUNT = 512; * const uint PHI_SUBDIVS_COUNT = 2*512; * * float integral = 0.0f; * for ( uint THETA=0; THETA < THETA_SUBDIVS_COUNT; THETA++ ) { * * // Use cosine-weighted sampling * float sqCosThetaI = (0.5f+THETA) / THETA_SUBDIVS_COUNT; * float cosThetaI = Mathf.Sqrt( sqCosThetaI ); * float sinThetaI = Mathf.Sqrt( 1 - sqCosThetaI ); * * // float NdotL = cosThetaI; * * for ( uint PHI=0; PHI < PHI_SUBDIVS_COUNT; PHI++ ) { * float phi = Mathf.TWOPI * PHI / PHI_SUBDIVS_COUNT; * * // Compute cos(theta_h) = Omega_h.N where Omega_h = (Omega_i + Omega_o) / ||Omega_i + Omega_o|| is the half vector and N the surface normal * float cosThetaH = (cosThetaI + cosThetaO) / Mathf.Sqrt( 2 * (1 + cosThetaO * cosThetaI + sinThetaO * sinThetaI * Mathf.Sin( phi )) ); * // float3 omega_i = new float3( sinThetaI * Mathf.Cos( phi ), sinThetaI * Mathf.Sin( phi ), cosThetaI ); * // float3 omega_o = new float3( sinThetaO, 0, cosThetaO ); * // float3 omega_h = (omega_i + omega_o).Normalized; * // float cosThetaH = omega_h.z; * * // Compute GGX NDF * float den = 1 - cosThetaH*cosThetaH * (1 - m2); * float NDF = m2 / (Mathf.PI * den*den); * * // Compute Smith shadowing/masking * float Smith_i_den = NdotL + Mathf.Sqrt( m2 + (1-m2) * NdotL*NdotL ); * float Smith_o_den = NdotV + Mathf.Sqrt( m2 + (1-m2) * NdotV*NdotV ); * * // Full BRDF is thus... * float GGX = NDF / (Smith_i_den * Smith_o_den); * * // integral += GGX * cosThetaI * sinThetaI; * integral += GGX; * * } * } * } * } * //*/ ////////////////////////////////////////////////////////////////////////// // verify BRDF + BRDFms integration = 1 // cube map + integration m_tex_IrradianceAverage = new Texture2D(m_Device, ROUGHNESS_SUBDIVS_COUNT, 1, 1, 1, ImageUtility.PIXEL_FORMAT.R32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content }); } }
private void LoadHeightMap(System.IO.FileInfo _FileName) { try { tabControlGenerators.Enabled = false; // Dispose of existing resources if (m_imageSourceHeightMap != null) { m_imageSourceHeightMap.Dispose(); } m_imageSourceHeightMap = null; if (m_textureTarget_CPU != null) { m_textureTarget_CPU.Dispose(); } m_textureTarget_CPU = null; if (m_textureTarget0 != null) { m_textureTarget0.Dispose(); } m_textureTarget0 = null; if (m_textureTarget1 != null) { m_textureTarget1.Dispose(); } m_textureTarget1 = null; if (m_textureSourceHeightMap != null) { m_textureSourceHeightMap.Dispose(); } m_textureSourceHeightMap = null; // Load the source image m_SourceFileName = _FileName; m_imageSourceHeightMap = new ImageUtility.ImageFile(_FileName); outputPanelInputHeightMap.Image = m_imageSourceHeightMap; W = m_imageSourceHeightMap.Width; H = m_imageSourceHeightMap.Height; // Build the source texture assuming the image is in linear space float4[] scanline = new float4[W]; PixelsBuffer SourceHeightMap = new PixelsBuffer(W * H * 4); // using ( System.IO.BinaryWriter Wr = SourceHeightMap.OpenStreamWrite() ) // for ( uint Y=0; Y < H; Y++ ) { // m_imageSourceHeightMap.ReadScanline( Y, scanline ); // for ( int X=0; X < W; X++ ) // Wr.Write( scanline[X].x ); // } using (System.IO.BinaryWriter Wr = SourceHeightMap.OpenStreamWrite()) { m_imageSourceHeightMap.ReadPixels((uint X, uint Y, ref float4 _color) => { Wr.Write(_color.x); }); } m_textureSourceHeightMap = new Texture2D(m_device, W, H, 1, 1, ImageUtility.PIXEL_FORMAT.R32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { SourceHeightMap }); // Build the target UAV & staging texture for readback m_textureTarget0 = new Texture2D(m_device, W, H, 1, 1, ImageUtility.PIXEL_FORMAT.R32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, true, null); m_textureTarget1 = new Texture2D(m_device, W, H, 1, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, true, null); m_textureTarget_CPU = new Texture2D(m_device, W, H, 1, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, true, false, null); tabControlGenerators.Enabled = true; buttonGenerate.Focus(); } catch (Exception _e) { MessageBox("An error occurred while opening the image:\n\n", _e); } }
private void LoadHeightMap( System.IO.FileInfo _FileName ) { try { tabControlGenerators.Enabled = false; // Dispose of existing resources if ( m_imageSourceHeightMap != null ) m_imageSourceHeightMap.Dispose(); m_imageSourceHeightMap = null; if ( m_textureTarget_CPU != null ) m_textureTarget_CPU.Dispose(); m_textureTarget_CPU = null; if ( m_textureTarget0 != null ) m_textureTarget0.Dispose(); m_textureTarget0 = null; if ( m_textureTarget1 != null ) m_textureTarget1.Dispose(); m_textureTarget1 = null; if ( m_textureSourceHeightMap != null ) m_textureSourceHeightMap.Dispose(); m_textureSourceHeightMap = null; // Load the source image m_SourceFileName = _FileName; m_imageSourceHeightMap = new ImageUtility.ImageFile( _FileName ); outputPanelInputHeightMap.Image = m_imageSourceHeightMap; W = m_imageSourceHeightMap.Width; H = m_imageSourceHeightMap.Height; // Build the source texture assuming the image is in linear space float4[] scanline = new float4[W]; PixelsBuffer SourceHeightMap = new PixelsBuffer( W*H*4 ); using ( System.IO.BinaryWriter Wr = SourceHeightMap.OpenStreamWrite() ) for ( uint Y=0; Y < H; Y++ ) { m_imageSourceHeightMap.ReadScanline( Y, scanline ); for ( int X=0; X < W; X++ ) Wr.Write( scanline[X].x ); } m_textureSourceHeightMap = new Texture2D( m_device, W, H, 1, 1, PIXEL_FORMAT.R32_FLOAT, false, false, new PixelsBuffer[] { SourceHeightMap } ); // Build the target UAV & staging texture for readback m_textureTarget0 = new Texture2D( m_device, W, H, 1, 1, PIXEL_FORMAT.R32_FLOAT, false, true, null ); m_textureTarget1 = new Texture2D( m_device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, true, null ); m_textureTarget_CPU = new Texture2D( m_device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, true, false, null ); tabControlGenerators.Enabled = true; buttonGenerate.Focus(); } catch ( Exception _e ) { MessageBox( "An error occurred while opening the image:\n\n", _e ); } }
public Texture2D Image2Texture( uint _Width, uint _Height, byte[] _Content ) { using ( PixelsBuffer Buff = new PixelsBuffer( (uint) _Content.Length ) ) { using ( System.IO.BinaryWriter W = Buff.OpenStreamWrite() ) W.Write( _Content ); return Image2Texture( _Width, _Height, PIXEL_FORMAT.RGBA8_UNORM_sRGB, Buff ); } }
private void LoadThicknessMap( System.IO.FileInfo _FileName ) { try { groupBoxOptions.Enabled = false; // Dispose of existing resources if ( m_ImageSourceThickness != null ) m_ImageSourceThickness.Dispose(); m_ImageSourceThickness = null; if ( m_TextureSourceThickness != null ) m_TextureSourceThickness.Dispose(); m_TextureSourceThickness = null; if ( m_TextureSourceVisibility != null ) m_TextureSourceVisibility.Dispose(); m_TextureSourceVisibility = null; if ( m_TextureTarget_CPU != null ) { m_TextureTarget_CPU.Dispose(); } m_TextureTarget_CPU = null; if ( m_TextureFilteredThickness != null ) m_TextureFilteredThickness.Dispose(); m_TextureFilteredThickness = null; if ( m_TextureTargets[0][0] != null ) { m_TextureTargets[0][0].Dispose(); m_TextureTargets[0][1].Dispose(); m_TextureTargets[1][0].Dispose(); m_TextureTargets[1][1].Dispose(); m_TextureTargets[2][0].Dispose(); m_TextureTargets[2][1].Dispose(); } m_TextureTargets[0][0] = null; m_TextureTargets[0][1] = null; m_TextureTargets[1][0] = null; m_TextureTargets[1][1] = null; m_TextureTargets[2][0] = null; m_TextureTargets[2][1] = null; if ( m_TextureTargetCombined != null ) m_TextureTargetCombined.Dispose(); m_TextureTargetCombined = null; // Load the source image m_SourceFileName = _FileName; m_ImageSourceThickness = new ImageUtility.ImageFile( _FileName ); imagePanelThicknessMap.Image = m_ImageSourceThickness; W = m_ImageSourceThickness.Width; H = m_ImageSourceThickness.Height; // Build the source texture assuming the image is in linear space float4[] scanline = new float4[W]; PixelsBuffer sourceHeightMap = new PixelsBuffer( W*H*4 ); using ( System.IO.BinaryWriter Wr = sourceHeightMap.OpenStreamWrite() ) for ( uint Y=0; Y < H; Y++ ) { m_ImageSourceThickness.ReadScanline( Y, scanline ); for ( uint X=0; X < W; X++ ) { Wr.Write( scanline[X].x ); } } m_TextureSourceThickness = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.R32_FLOAT, false, false, new PixelsBuffer[] { sourceHeightMap } ); // Build the 3D visibility texture m_TextureSourceVisibility = new Texture3D( m_Device, W, H, VISIBILITY_SLICES, 1, PIXEL_FORMAT.R16_FLOAT, false, true, null ); // Build the target UAV & staging texture for readback m_TextureFilteredThickness = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.R32_FLOAT, false, true, null ); for ( int i=0; i < 3; i++ ) { m_TextureTargets[i][0] = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, true, null ); m_TextureTargets[i][1] = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, true, null ); } m_TextureTargetCombined = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, true, null ); m_TextureTarget_CPU = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, true, false, null ); groupBoxOptions.Enabled = true; buttonGenerate.Focus(); } catch ( Exception _e ) { MessageBox( "An error occurred while opening the thickness map \"" + _FileName.FullName + "\":\n\n", _e ); } }
private void LoadAlbedoMap( System.IO.FileInfo _FileName ) { try { // Dispose of existing resources if ( m_imageSourceAlbedo != null ) m_imageSourceAlbedo.Dispose(); m_imageSourceAlbedo = null; if ( m_TextureSourceAlbedo != null ) m_TextureSourceAlbedo.Dispose(); m_TextureSourceAlbedo = null; // Load the source image m_imageSourceAlbedo = new ImageUtility.ImageFile( _FileName ); imagePanelAlbedoMap.Image = m_imageSourceAlbedo; uint W = m_imageSourceAlbedo.Width; uint H = m_imageSourceAlbedo.Height; // Build the source texture assuming the image's color profile float4[] scanline = new float4[W]; float4 linearRGB = float4.Zero; ImageUtility.ColorProfile imageProfile = m_imageSourceAlbedo.ColorProfile; // ImageUtility.ColorProfile imageProfile = m_sRGBProfile; // float4[,] ContentRGB = new float4[W,H]; // m_LinearProfile.XYZ2RGB( m_imageSourceAlbedo.ContentXYZ, ContentRGB ); PixelsBuffer SourceMap = new PixelsBuffer( W*H*16 ); using ( System.IO.BinaryWriter Wr = SourceMap.OpenStreamWrite() ) for ( uint Y=0; Y < H; Y++ ) { m_imageSourceAlbedo.ReadScanline( Y, scanline ); for ( uint X=0; X < W; X++ ) { imageProfile.GammaRGB2LinearRGB( scanline[X], ref linearRGB ); Wr.Write( linearRGB.x ); Wr.Write( linearRGB.y ); Wr.Write( linearRGB.z ); Wr.Write( linearRGB.w ); } } m_TextureSourceAlbedo = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, false, new PixelsBuffer[] { SourceMap } ); } catch ( Exception _e ) { MessageBox( "An error occurred while opening the albedo map \"" + _FileName.FullName + "\":\n\n", _e ); } }
void BuildFont() { string charSet = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~éèêëôöàçÔÖÂÊÉœûüù"; m_fontRectangles = new Rectangle[charSet.Length]; for (int charIndex = 0; charIndex < charSet.Length; charIndex++) { char C = charSet[charIndex]; int index = (int)C; m_char2Index[index] = charIndex; } #if BUILD_FONTS using (Font F = new Font(this.Font.FontFamily, 36.0f)) { // Build small bitmap and write each character int width = 0; int maxheight = 0; using (Bitmap B = new Bitmap(70, 70, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { using (Graphics G = Graphics.FromImage(B)) { for (int i = 0; i < charSet.Length; i++) { string s = charSet.Substring(i, 1); // G.FillRectangle( Brushes.Black, 0, 0, B.Width, B.Height ); // G.DrawString( s, F, Brushes.White, new PointF( 0, 0 ) ); SizeF tempSize = G.MeasureString(s, F); m_fontRectangles[i] = new Rectangle(width, 0, (int)Mathf.Ceiling(tempSize.Width), (int)Mathf.Ceiling(tempSize.Height)); if (m_fontRectangles[i].Width > B.Width || m_fontRectangles[i].Height > B.Height) { throw new Exception("Fonts are too big, expand bitmap size or reduce font size!"); } width += m_fontRectangles[i].Width; maxheight = Math.Max(maxheight, m_fontRectangles[i].Height); } } } // Build the final bitmap using (Bitmap B = new Bitmap(width, maxheight, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { using (Graphics G = Graphics.FromImage(B)) { G.FillRectangle(Brushes.Black, 0, 0, B.Width, B.Height); for (int i = 0; i < charSet.Length; i++) { string s = charSet.Substring(i, 1); G.DrawString(s, F, Brushes.White, new PointF(m_fontRectangles[i].X, m_fontRectangles[i].Y)); } using (ImageUtility.ImageFile file = new ImageUtility.ImageFile(B, new ImageUtility.ColorProfile(ImageUtility.ColorProfile.STANDARD_PROFILE.sRGB))) { file.Save(new FileInfo("Atlas.png"), ImageUtility.ImageFile.FILE_FORMAT.PNG); } } } } // Write char sizes using (FileStream S = new FileInfo("Atlas.rect").Create()) using (BinaryWriter W = new BinaryWriter(S)) { for (int i = 0; i < m_fontRectangles.Length; i++) { W.Write(m_fontRectangles[i].X); W.Write(m_fontRectangles[i].Y); W.Write(m_fontRectangles[i].Width); W.Write(m_fontRectangles[i].Height); } } #endif // Load atlas & rectangles using (ImageUtility.ImageFile file = new ImageUtility.ImageFile(new FileInfo("Atlas.png"))) { ImageUtility.ImageFile file2 = new ImageUtility.ImageFile(file, ImageUtility.PIXEL_FORMAT.RGBA8); using (ImageUtility.ImagesMatrix M = new ImageUtility.ImagesMatrix(file2, ImageUtility.ImagesMatrix.IMAGE_TYPE.sRGB)) { m_tex_FontAtlas = new Texture2D(m_device, M, ImageUtility.COMPONENT_FORMAT.UNORM_sRGB); } } using (FileStream S = new FileInfo("Atlas.rect").OpenRead()) using (BinaryReader R = new BinaryReader(S)) { // Read both CPU and GPU versions float recW = 1.0f / m_tex_FontAtlas.Width; float recH = 1.0f / m_tex_FontAtlas.Height; using (PixelsBuffer content = new PixelsBuffer((uint)(16 * m_fontRectangles.Length))) { using (BinaryWriter W = content.OpenStreamWrite()) { for (int i = 0; i < m_fontRectangles.Length; i++) { m_fontRectangles[i].X = R.ReadInt32(); m_fontRectangles[i].Y = R.ReadInt32(); m_fontRectangles[i].Width = R.ReadInt32(); m_fontRectangles[i].Height = R.ReadInt32(); W.Write(recW * (float)m_fontRectangles[i].X); W.Write(recH * (float)m_fontRectangles[i].Y); W.Write(recW * (float)m_fontRectangles[i].Width); W.Write(recH * (float)m_fontRectangles[i].Height); } } m_tex_FontRectangle = new Texture2D(m_device, (uint)m_fontRectangles.Length, 1, 1, 1, ImageUtility.PIXEL_FORMAT.RGBA32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, false, new PixelsBuffer[] { content }); } } }
public Texture2D Image2Texture( int _Width, int _Height, byte[] _Content ) { using ( PixelsBuffer Buff = new PixelsBuffer( _Content.Length ) ) { using ( System.IO.BinaryWriter W = Buff.OpenStreamWrite() ) W.Write( _Content ); return Image2Texture( _Width, _Height, Buff ); } }