public void Mutate() { for (int i = 0; i < _jobsLength; i++) { if (SimpleRNG.GetUniform() < _mutationRate) { int r = SimpleRNG.Next(0, _jobsLength); int temp = JobGenes[i]; JobGenes[i] = JobGenes[r]; JobGenes[r] = temp; // Mutate the delay time r = SimpleRNG.Next(0, _modesLength); double mutatedDelay = 0; //mutatedDelay = SimpleRNG.GetExponential(_delayMean); mutatedDelay = SimpleRNG.GetNormal(TimeGenes[r], 1.0); //mutatedDelay = _rand.NextDouble() * _delayMean; if (mutatedDelay < 0.0) { mutatedDelay = 0.0; } TimeGenes[r] = mutatedDelay; } } //Mutate the Mode vector: for (int i = 0; i < _modesLength; i++) { if (SimpleRNG.GetUniform() < _mutationRate) { ModeGenes[i] = SimpleRNG.Next(0, _numberOfModes); } } }
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 }); }
public void RandomInit() { List <int> randarray = new List <int>(); for (int i = 0; i < _jobsLength; i++) { randarray.Add(i); } for (int i = 0; i < _jobsLength; i++) { int r = SimpleRNG.Next(0, _jobsLength - i); JobGenes[i] = randarray[r]; randarray.RemoveAt(r); } for (int i = 0; i < _timesLength; i++) { if (SimpleRNG.GetUniform() < _delayRate) { TimeGenes[i] = SimpleRNG.GetExponential(_delayMean); } else { TimeGenes[i] = 0.0; } ModeGenes[i] = SimpleRNG.Next(0, _numberOfModes); } fitness = -1; }
private double GetTheta() { double x = SimpleRNG.GetUniform(); int index = Math.Min(m_UniformRandom2Angle.Length - 1, (int)Math.Floor(x * m_UniformRandom2Angle.Length)); double value = m_UniformRandom2Angle[index]; return(value); }
/// <summary> /// Generates blue noise distribution by randomly swapping pixels in the texture to reach lowest possible score and minimize a specific energy function /// </summary> /// <param name="_randomSeed"></param> /// <param name="_minEnergyThreshold"></param> /// <param name="_maxIterations"></param> /// <param name="_standardDeviationImage">Standard deviation for image space. If not sure, use 2.1</param> /// <param name="_standardDeviationValue">Standard deviation for value space. If not sure, use 1.0</param> /// <param name="_progress"></param> public void Generate(uint _randomSeed, float _minEnergyThreshold, int _maxIterations, float _standardDeviationImage, float _standardDeviationValue, ProgressDelegate _progress) { m_kernelFactorImage = -1.0 / (_standardDeviationImage * _standardDeviationImage); m_kernelFactorValue = -1.0 / (_standardDeviationValue * _standardDeviationValue); // Generate initial white noise SimpleRNG.SetSeed(_randomSeed); for (int Y = 0; Y < m_textureSize; Y++) { for (int X = 0; X < m_textureSize; X++) { m_textures[0][X, Y] = (float)SimpleRNG.GetUniform(); } } // Perform iterations float bestScore = ComputeScore(m_textures[0]); int iterationIndex = 0; while (iterationIndex < _maxIterations && bestScore > _minEnergyThreshold) { // Copy source to target array Array.Copy(m_textures[0], m_textures[1], m_textureTotalSize); // Swap up to N pixels randomly for (int swapCount = 0; swapCount < MAX_SWAPPED_ELEMENTS_PER_ITERATION; swapCount++) { uint sourceIndex = GetUniformInt(m_textureTotalSize); uint targetIndex = sourceIndex; while (targetIndex == sourceIndex) { targetIndex = GetUniformInt(m_textureTotalSize); // Make sure target index differs! } float temp = Get(m_textures[1], sourceIndex); Set(m_textures[1], sourceIndex, Get(m_textures[1], targetIndex)); Set(m_textures[1], targetIndex, temp); } // Compute new score float score = ComputeScore(m_textures[1]); if (score < bestScore) { // New best score! Swap textures... bestScore = score; float[,] temp = m_textures[0]; m_textures[0] = m_textures[1]; m_textures[1] = temp; } iterationIndex++; if (_progress != null) { _progress(iterationIndex, bestScore, m_textures[0]); // Notify! } } }
private void BuildRandomBuffer() { Reg(m_SB_Random = new StructuredBuffer <float4>(m_Device, RANDOM_TABLE_SIZE, true)); for (int i = 0; i < RANDOM_TABLE_SIZE; i++) { // m_SB_Random.m[i] = new float4( (float) SimpleRNG.GetUniform(), (float) SimpleRNG.GetUniform(), (float) SimpleRNG.GetUniform(), (float) SimpleRNG.GetUniform() ); m_SB_Random.m[i] = new float4((float)SimpleRNG.GetUniform(), (float)SimpleRNG.GetUniform(), (float)SimpleRNG.GetUniform(), -(float)Math.Log(1e-3 + (1.0 - 1e-3) * SimpleRNG.GetUniform())); } m_SB_Random.Write(); }
private void GenerateRays(int _raysCount, StructuredBuffer <float3> _target) { _raysCount = Math.Min(MAX_THREADS, _raysCount); // Half-Life 2 basis float3[] HL2Basis = new float3[] { new float3((float)Math.Sqrt(2.0 / 3.0), 0.0f, (float)Math.Sqrt(1.0 / 3.0)), new float3(-(float)Math.Sqrt(1.0 / 6.0), (float)Math.Sqrt(1.0 / 2.0), (float)Math.Sqrt(1.0 / 3.0)), new float3(-(float)Math.Sqrt(1.0 / 6.0), -(float)Math.Sqrt(1.0 / 2.0), (float)Math.Sqrt(1.0 / 3.0)) }; float centerTheta = (float)Math.Acos(HL2Basis[0].z); float[] centerPhi = new float[] { (float)Math.Atan2(HL2Basis[0].y, HL2Basis[0].x), (float)Math.Atan2(HL2Basis[1].y, HL2Basis[1].x), (float)Math.Atan2(HL2Basis[2].y, HL2Basis[2].x), }; for (int rayIndex = 0; rayIndex < _raysCount; rayIndex++) { double phi = (Math.PI / 3.0) * (2.0 * SimpleRNG.GetUniform() - 1.0); // Stratified version double theta = (Math.Acos(Math.Sqrt((rayIndex + SimpleRNG.GetUniform()) / _raysCount))); // // Don't give a shit version (a.k.a. melonhead version) // // double Theta = Math.Acos( Math.Sqrt(WMath.SimpleRNG.GetUniform() ) ); // double Theta = 0.5 * Math.PI * WMath.SimpleRNG.GetUniform(); theta = Math.Min(0.499f * Math.PI, theta); double cosTheta = Math.Cos(theta); double sinTheta = Math.Sin(theta); double lengthFactor = 1.0 / sinTheta; // The ray is scaled so we ensure we always walk at least a texel in the texture cosTheta *= lengthFactor; sinTheta *= lengthFactor; // Yeah, yields 1... :) _target.m[0 * MAX_THREADS + rayIndex].Set((float)(Math.Cos(centerPhi[0] + phi) * sinTheta), (float)(Math.Sin(centerPhi[0] + phi) * sinTheta), (float)cosTheta); _target.m[1 * MAX_THREADS + rayIndex].Set((float)(Math.Cos(centerPhi[1] + phi) * sinTheta), (float)(Math.Sin(centerPhi[1] + phi) * sinTheta), (float)cosTheta); _target.m[2 * MAX_THREADS + rayIndex].Set((float)(Math.Cos(centerPhi[2] + phi) * sinTheta), (float)(Math.Sin(centerPhi[2] + phi) * sinTheta), (float)cosTheta); } _target.Write(); }
private void ShowFlag(string guid, double value) { var direction = SimpleRNG.GetUniform() > 0.5 ? FlagDirection.Up : FlagDirection.Down; var flag = new Flag { Id = guid, Value = value, FlagDirection = direction.ToString() }; foreach (var h in _handlers) { h.Value(flag); } }
/// <summary> /// Set the random turn component of the AI. /// </summary> private float randTurn() { float offset = 2.0f; float radius = 1.0f; float maxRotation = MathHelper.Pi / 7.0f; currentRotation += (float)(SimpleRNG.GetUniform() * 2 - 1) * maxRotation; float width = (float)Math.Sin(currentRotation) * radius; float extra = (float)Math.Cos(currentRotation) * radius; return((float)Math.Tanh(width / (offset + extra))); }
public Action StartSparkline(IEnumerable <AddTimeValue> addTimeValues) { Func <int> tickTime = () => { // Convert.ToInt32(Math.Floor(SimpleRNG.GetUniform()*2000)); return(1000 / 2); }; Func <AddTimeValue, Action> tickGenerator = addTimeValue => { var x = 100.0; return(() => { while (true) { var newx = x + SimpleRNG.GetNormal() * 2; if (newx < 0.0) { newx = 0.0; } _dispatcher.BeginInvoke((Action)(() => { var guid = addTimeValue(newx); if (SimpleRNG.GetUniform() > 0.75) { ShowFlag(guid, newx); } })); x = newx; Thread.Sleep(tickTime()); } }); }; Func <Action, WaitCallback> toWaitCallback = gen => wc => gen(); Action start = () => { var tickGenerators = addTimeValues.Select(tickGenerator).ToArray(); foreach (var generateTicks in tickGenerators) { ThreadPool.QueueUserWorkItem(toWaitCallback(generateTicks)); } }; return(start); }
private int SelectParent() { int p = 0; switch (parentSelection) { case ParentSelectionOp.FitnessProportional: double totalFitness = 0; for (int i = 0; i < _popsize; i++) { totalFitness += population[i].fitness; } //double r = _rand.NextDouble() * totalFitness; double r = SimpleRNG.GetUniform() * totalFitness; double runningTotal = population[p].fitness; while (runningTotal > r) { p++; runningTotal += population[p].fitness; } break; case ParentSelectionOp.Tournament: int k = _popsize / 10; //p = _rand.Next(_popsize); p = (int)(SimpleRNG.GetUniform() * _popsize); double bestfitness = population[p].fitness; for (int i = 0; i < k; i++) { int px = SimpleRNG.Next(0, _popsize); if (population[px].fitness > bestfitness) { bestfitness = population[px].fitness; p = px; } } break; } return(p); }
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); } }
private void Generate_CPU(int _RaysCount) { try { tabControlGenerators.Enabled = false; // Half-life basis (Z points outside of the surface, as in normal maps) float3[] basis = new float3[] { new float3((float)Math.Sqrt(2.0 / 3.0), 0.0f, (float)Math.Sqrt(1.0 / 3.0)), new float3((float)-Math.Sqrt(1.0 / 6.0), (float)Math.Sqrt(1.0 / 2.0), (float)Math.Sqrt(1.0 / 3.0)), new float3((float)-Math.Sqrt(1.0 / 6.0), (float)-Math.Sqrt(1.0 / 2.0), (float)Math.Sqrt(1.0 / 3.0)), }; // // 1] Compute normal map // float3 dX = new float3(); // float3 dY = new float3(); // float3 N; // float ddX = floatTrackbarControlPixelSize.Value; // float ddH = floatTrackbarControlHeight.Value; // for ( int Y=0; Y < H; Y++ ) // { // int Y0 = Math.Max( 0, Y-1 ); // int Y1 = Math.Min( H-1, Y+1 ); // for ( int X=0; X < W; X++ ) // { // int X0 = Math.Max( 0, X-1 ); // int X1 = Math.Min( W-1, X+1 ); // // float Hx0 = m_BitmapSource.ContentXYZ[X0,Y].y; // float Hx1 = m_BitmapSource.ContentXYZ[X1,Y].y; // float Hy0 = m_BitmapSource.ContentXYZ[X,Y0].y; // float Hy1 = m_BitmapSource.ContentXYZ[X,Y1].y; // // dX.Set( 2.0f * ddX, 0.0f, ddH * (Hx1 - Hx0) ); // dY.Set( 0.0f, 2.0f * ddX, ddH * (Hy1 - Hy0) ); // // N = dX.Cross( dY ).Normalized; // // m_Normal[X,Y] = new float3( // N.Dot( Basis[0] ), // N.Dot( Basis[1] ), // N.Dot( Basis[2] ) ); // } // // // Update and show progress // UpdateProgress( m_Normal, Y, true ); // } // UpdateProgress( m_Normal, H, true ); float LobeExponent = 4.0f; //floatTrackbarControlLobeExponent.Value; float PixelSize_mm = 1000.0f / floatTrackbarControlPixelDensity.Value; float scale = 0.1f * PixelSize_mm / floatTrackbarControlHeight.Value; // Scale factor to apply to pixel distances so they're renormalized in [0,1], our "heights space"... // Scale *= floatTrackbarControlZFactor.Value; // Cheat Z velocity so AO is amplified! // 2] Build local rays only once int raysCount = integerTrackbarControlRaysCount.Value; float3[,] rays = new float3[3, raysCount]; // Create orthonormal bases to orient the lobe float3 Xr = basis[0].Cross(float3.UnitZ).Normalized; // We can safely use (0,0,1) as the "up" direction since the HL2 basis doesn't have any vertical direction float3 Yr = Xr.Cross(basis[0]); float3 Xg = basis[1].Cross(float3.UnitZ).Normalized; // We can safely use (0,0,1) as the "up" direction since the HL2 basis doesn't have any vertical direction float3 Yg = Xg.Cross(basis[1]); float3 Xb = basis[2].Cross(float3.UnitZ).Normalized; // We can safely use (0,0,1) as the "up" direction since the HL2 basis doesn't have any vertical direction float3 Yb = Xb.Cross(basis[2]); double Exponent = 1.0 / (1.0 + LobeExponent); for (int RayIndex = 0; RayIndex < raysCount; RayIndex++) { // if ( false ) { // double Phi = 2.0 * Math.PI * WMath.SimpleRNG.GetUniform(); // // double Theta = Math.Acos( Math.Pow( WMath.SimpleRNG.GetUniform(), Exponent ) ); // double Theta = Math.PI / 3.0 * WMath.SimpleRNG.GetUniform(); // // float3 RayLocal = new float3( // (float) (Math.Cos( Phi ) * Math.Sin( Theta )), // (float) (Math.Sin( Phi ) * Math.Sin( Theta )), // (float) Math.Cos( Theta ) ); // // Rays[0,RayIndex] = RayLocal.x * Xr + RayLocal.y * Yr + RayLocal.z * Basis[0]; // Rays[1,RayIndex] = RayLocal.x * Xg + RayLocal.y * Yg + RayLocal.z * Basis[1]; // Rays[2,RayIndex] = RayLocal.x * Xb + RayLocal.y * Yb + RayLocal.z * Basis[2]; // } else { double Phi = Math.PI / 3.0 * (2.0 * SimpleRNG.GetUniform() - 1.0); double Theta = 0.49 * Math.PI * SimpleRNG.GetUniform(); rays[0, RayIndex] = new float3( (float)(Math.Cos(Phi) * Math.Sin(Theta)), (float)(Math.Sin(Phi) * Math.Sin(Theta)), (float)Math.Cos(Theta)); Phi = Math.PI / 3.0 * (2.0 * SimpleRNG.GetUniform() - 1.0 + 2.0); Theta = 0.49 * Math.PI * SimpleRNG.GetUniform(); rays[1, RayIndex] = new float3( (float)(Math.Cos(Phi) * Math.Sin(Theta)), (float)(Math.Sin(Phi) * Math.Sin(Theta)), (float)Math.Cos(Theta)); Phi = Math.PI / 3.0 * (2.0 * SimpleRNG.GetUniform() - 1.0 + 4.0); Theta = 0.49 * Math.PI * SimpleRNG.GetUniform(); rays[2, RayIndex] = new float3( (float)(Math.Cos(Phi) * Math.Sin(Theta)), (float)(Math.Sin(Phi) * Math.Sin(Theta)), (float)Math.Cos(Theta)); } rays[0, RayIndex].z *= scale; rays[1, RayIndex].z *= scale; rays[2, RayIndex].z *= scale; } // 3] Compute directional occlusion float4[] scanline = new float4[W]; float4 gammaRGB = float4.Zero; for (uint Y = 0; Y < H; Y++) { for (uint X = 0; X < W; X++) { gammaRGB.x = ComputeAO(0, X, Y, scale, rays); gammaRGB.y = ComputeAO(1, X, Y, scale, rays); gammaRGB.z = ComputeAO(2, X, Y, scale, rays); gammaRGB.w = (gammaRGB.x + gammaRGB.y + gammaRGB.z) / 3.0f; m_sRGBProfile.GammaRGB2LinearRGB(gammaRGB, ref scanline[X]); } m_imageResult.WriteScanline(Y, scanline); // Update and show progress UpdateProgress(m_imageResult, Y, true); } UpdateProgress(m_imageResult, H, true); // m_BitmapResult.Save( "eye_generic_01_disp_hl2.png", ImageFormat.Png ); } catch (Exception _e) { MessageBox("An error occurred during generation:\r\n" + _e.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { tabControlGenerators.Enabled = true; } }
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); } }
/// <summary> /// Computes up to 20 orders of A coefficients for various AO and angle values /// </summary> void NumericalIntegration_20Orders() { // Generate a bunch of rays with equal probability on the hemisphere const int THETA_SAMPLES = 100; const int SAMPLES_COUNT = 4 * THETA_SAMPLES * THETA_SAMPLES; const double dPhi = 2.0 * Math.PI / (4 * THETA_SAMPLES); float3[] directions = new float3[SAMPLES_COUNT]; for (int Y = 0; Y < THETA_SAMPLES; Y++) { for (int X = 0; X < 4 * THETA_SAMPLES; X++) { double phi = dPhi * (X + SimpleRNG.GetUniform()); double theta = 2.0 * Math.Acos(Math.Sqrt(1.0 - 0.5 * (Y + SimpleRNG.GetUniform()) / THETA_SAMPLES)); // Uniform sampling on theta directions[4 * THETA_SAMPLES * Y + X].Set((float)(Math.Sin(theta) * Math.Cos(phi)), (float)(Math.Sin(theta) * Math.Sin(phi)), (float)Math.Cos(theta)); } } // Compute numerical integration for various sets of angles const int TABLE_SIZE = 64; const int ORDERS = 20; float3 coneDirection = float3.Zero; float[,,] integratedSHCoeffs = new float[TABLE_SIZE, TABLE_SIZE, ORDERS]; double[] A = new double[ORDERS]; for (int thetaIndex = 0; thetaIndex < TABLE_SIZE; thetaIndex++) { float V = (float)thetaIndex / TABLE_SIZE; // float cosTheta = (float) Math.Cos( 0.5 * Math.PI * V ); float cosTheta = V; coneDirection.x = (float)Math.Sqrt(1.0f - cosTheta * cosTheta); coneDirection.z = cosTheta; for (int AOIndex = 0; AOIndex < TABLE_SIZE; AOIndex++) { float U = (float)AOIndex / TABLE_SIZE; // float cosConeHalfAngle = U; float cosConeHalfAngle = (float)Math.Cos(0.5 * Math.PI * U); Array.Clear(A, 0, ORDERS); for (int sampleIndex = 0; sampleIndex < SAMPLES_COUNT; sampleIndex++) { float3 direction = directions[sampleIndex]; if (direction.Dot(coneDirection) < cosConeHalfAngle) { continue; // Sample is outside cone } float u = direction.z; // cos(theta_sample) for (int order = 0; order < ORDERS; order++) { A[order] += u * SHFunctions.P0(order, u); } } // Finalize integration for (int order = 0; order < ORDERS; order++) { A[order] *= 2.0 * Math.PI / SAMPLES_COUNT; } for (int order = 0; order < ORDERS; order++) { integratedSHCoeffs[thetaIndex, AOIndex, order] = (float)A[order]; } } } // Save table using (System.IO.FileStream S = new System.IO.FileInfo(@"ConeTable_cosTheta_order20.float").Create()) using (System.IO.BinaryWriter W = new System.IO.BinaryWriter(S)) { for (int thetaIndex = 0; thetaIndex < TABLE_SIZE; thetaIndex++) { for (int AOIndex = 0; AOIndex < TABLE_SIZE; AOIndex++) { for (int order = 0; order < ORDERS; order++) { W.Write(integratedSHCoeffs[thetaIndex, AOIndex, order]); } } } } }
private void buttonShoot_Click(object sender, EventArgs e) { // Clear accumulation for (int Y = 0; Y < TEXTURE_SIZE; Y++) { for (int X = 0; X < TEXTURE_SIZE; X++) { m_PhotonsAccumulation[X, Y] = 0.0f; } } float LightTheta = (float)Math.PI * floatTrackbarControlTheta.Value / 180.0f; Vector Light = new Vector((float)-Math.Sin(LightTheta), 0.0f, (float)Math.Cos(LightTheta)); // float Flux = TEXTURE_SIZE*TEXTURE_SIZE / integerTrackbarControlPhotonsCount.Value; float Flux = 20000.0f / integerTrackbarControlPhotonsCount.Value; float PlaneD = (float)Math.Cos(IRIS_START_ANGLE); float IrisRadius = (float)Math.Sin(IRIS_START_ANGLE); // Compute bounds for photon generation float BoundX0 = -IrisRadius; float BoundX1 = +IrisRadius; Vector Ortho = new Vector(Light.z, 0.0f, -Light.x); // Vector tangent to the plane where we can measure projected bounds float ProjectedBound0 = BoundX0 * Ortho.x + PlaneD * Ortho.z; float ProjectedBound1 = BoundX1 * Ortho.x + PlaneD * Ortho.z; ProjectedBound1 = Math.Max(ProjectedBound1, Ortho.z); // Max with the projected sphere's tangent ProjectedBound1 *= 1.1f; // We now have a tight rectangle in projected space [-IrisRadius,ProjectedBound0] [IrisRadius,ProjectedBound1] // where we can place random photons that will shoot toward the eye's iris. // We still can miss the sphere though... // Start shooting double MaxThetaRandom = Math.Pow(Math.Sin(IRIS_START_ANGLE), 2.0); Vector P = new Vector(); Vector N = new Vector(); Vector Ray = new Vector(); Vector Intersection = new Vector(); float Eta = 1.00029f / 1.34f; // n1 / n2 float fX, fY; int Px, Py; for (int PhotonIndex = 0; PhotonIndex < integerTrackbarControlPhotonsCount.Value; PhotonIndex++) { // Wrong as photons are not distributed on the spherical cap // double Phi = 2.0 * Math.PI * SimpleRNG.GetUniform(); // double Theta = Math.Asin( Math.Sqrt( MaxThetaRandom * SimpleRNG.GetUniform() ) ); // // N.x = (float) (Math.Sin( Theta ) * Math.Cos( Phi )); // N.y = (float) (Math.Sin( Theta ) * Math.Sin( Phi )); // N.z = (float) Math.Cos( Theta ); // if ( N.Dot( Light ) < 0.0f ) // continue; // Opposite side of the spherical cap // Draw a random position on the light plane and shoot toward the iris float x = (float)(ProjectedBound0 + SimpleRNG.GetUniform() * (ProjectedBound1 - ProjectedBound0)); float y = (float)(IrisRadius * (2.0 * SimpleRNG.GetUniform() - 1.0)); float SqRadius = x * x + y * y; if (SqRadius > 1.0f) { continue; // Photon will hit outside the sphere (should never happen unless iris is as large as the eye itself) } float z = (float)Math.Sqrt(1.0 - SqRadius); // Recompute normal at intersection N.x = x * Ortho.x + z * Light.x; N.y = y; N.z = x * Ortho.z + z * Light.z; if (N.z < PlaneD) { continue; // We drew a position beneath the iris plane (outside of zone of interest) } // Refract ray through the surface float c1 = -N.Dot(Light); float cs2 = 1.0f - Eta * Eta * (1.0f - c1 * c1); if (cs2 < 0.0f) { continue; // Total internal reflection } cs2 = Eta * c1 - (float)Math.Sqrt(cs2); Ray.x = Eta * Light.x + cs2 * N.x; Ray.y = Eta * Light.y + cs2 * N.y; Ray.z = Eta * Light.z + cs2 * N.z; // Compute intersection with plane float d = (PlaneD - N.z) / Ray.z; if (d < 0.0f) { continue; // ? } Intersection.x = N.x + d * Ray.x; Intersection.y = N.y + d * Ray.y; Intersection.z = N.z + d * Ray.z; fX = 0.5f * (1.0f + Intersection.x / IrisRadius); fY = 0.5f * (1.0f + Intersection.y / IrisRadius); Px = (int)Math.Floor(fX * TEXTURE_SIZE); if (Px < 0 || Px >= TEXTURE_SIZE) { continue; // Out of range?? } Py = (int)Math.Floor(fY * TEXTURE_SIZE); if (Py < 0 || Py >= TEXTURE_SIZE) { continue; // Out of range?? } m_PhotonsAccumulation[Px, Py] += Flux; } outputPanel1.PhotonsAccumulation = m_PhotonsAccumulation; }
void TestTransform1D(double _time) { // Build the input signal Array.Clear(m_signalSource, 0, m_signalSource.Length); switch (m_signalType1D) { case SIGNAL_TYPE.SQUARE: for (int i = 0; i < SIGNAL_SIZE; i++) { m_signalSource[i].r = 0.5 * Math.Sin(_time) + ((i + 50.0 * _time) % (SIGNAL_SIZE / 2.0) < (SIGNAL_SIZE / 4.0) ? 0.5 : -0.5); } break; case SIGNAL_TYPE.SINE: for (int i = 0; i < SIGNAL_SIZE; i++) { // m_signalSource[i].r = Math.Cos( 2.0 * Math.PI * i / SIGNAL_SIZE + _time ); m_signalSource[i].r = Math.Cos((4.0 * (1.0 + Math.Sin(_time))) * 2.0 * Math.PI * i / SIGNAL_SIZE); } break; case SIGNAL_TYPE.SAW: for (int i = 0; i < SIGNAL_SIZE; i++) { m_signalSource[i].r = 0.5 * Math.Sin(_time) + ((((i + 50.0 * _time) / 128.0) % 1.0) - 0.5); } break; case SIGNAL_TYPE.SINC: for (int i = 0; i < SIGNAL_SIZE; i++) { // double a = 4.0 * (1.0 + Math.Sin( _time )) * 2.0 * Math.PI * (1+i) / SIGNAL_SIZE; // Asymmetrical double a = 4.0 * (1.0 + Math.Sin(_time)) * 2.0 * Math.PI * (i - SIGNAL_SIZE / 2.0) * 2.0 / SIGNAL_SIZE; // Symmetrical m_signalSource[i].r = Math.Abs(a) > 0.0 ? Math.Sin(a) / a : 1.0; } break; case SIGNAL_TYPE.RANDOM: for (int i = 0; i < SIGNAL_SIZE; i++) { m_signalSource[i].r = SimpleRNG.GetUniform(); } // m_signalSource[i].r = SimpleRNG.GetExponential(); // m_signalSource[i].r = SimpleRNG.GetBeta( 0.5, 1 ); // m_signalSource[i].r = SimpleRNG.GetGamma( 1.0, 0.1 ); // m_signalSource[i].r = SimpleRNG.GetCauchy( 0.0, 1.0 ); // m_signalSource[i].r = SimpleRNG.GetChiSquare( 1.0 ); // m_signalSource[i].r = SimpleRNG.GetNormal( 0.0, 0.1 ); // m_signalSource[i].r = SimpleRNG.GetLaplace( 0.0, 0.1 ); // m_signalSource[i].r = SimpleRNG.GetStudentT( 2.0 ); break; } // Transform if (m_FFTW_1D != null && checkBoxUseFFTW.Checked) { m_FFTW_1D.FillInputSpatial((int x, int y, out float r, out float i) => { r = (float)m_signalSource[x].r; i = (float)m_signalSource[x].i; }); m_FFTW_1D.Execute(fftwlib.FFT2D.Normalization.DIMENSIONS_PRODUCT); m_FFTW_1D.GetOutput((int x, int y, float r, float i) => { m_spectrum[x].Set(r, i); }); } else { // DFT1D.DFT_Forward( m_signalSource, m_spectrum ); FFT1D.FFT_Forward(m_signalSource, m_spectrum); } // Try the GPU version m_FFT1D_GPU.FFT_Forward(m_signalSource, m_spectrumGPU); // m_FFT1D_GPU.FFT_Forward( m_signalSource, m_spectrum ); double sumSqDiffR = 0.0; double sumSqDiffI = 0.0; for (int i = 0; i < m_spectrum.Length; i++) { Complex diff = m_spectrum[i] - m_spectrumGPU[i]; sumSqDiffR += diff.r * diff.r; sumSqDiffI += diff.i * diff.i; } labelDiff.Text = "SqDiff = " + sumSqDiffR.ToString("G3") + " , " + sumSqDiffI.ToString("G3"); if (m_FFTW_1D == null && checkBoxUseFFTW.Checked) { labelDiff.Text += "\r\nERROR: Can't use FFTW because of an initialization error!"; } if (checkBoxInvertFilter.Checked) { for (int i = 0; i < m_spectrum.Length; i++) { m_spectrum[i] = m_spectrumGPU[i]; } } // else // for ( int i=0; i < m_spectrum.Length; i++ ) // m_spectrum[i] *= 2.0; // Filter FilterDelegate filter = null; switch (m_filter1D) { case FILTER_TYPE.CUT_LARGE: filter = (int i, int frequency) => { return(Math.Abs(frequency) > 256 ? 0 : 1.0); }; // Cut break; case FILTER_TYPE.CUT_MEDIUM: filter = (int i, int frequency) => { return(Math.Abs(frequency) > 128 ? 0 : 1.0); }; // Cut break; case FILTER_TYPE.CUT_SHORT: filter = (int i, int frequency) => { return(Math.Abs(frequency) > 64 ? 0 : 1.0); }; // Cut break; case FILTER_TYPE.EXP: filter = (int i, int frequency) => { return(Math.Exp(-0.01f * Math.Abs(frequency))); }; // Exponential break; case FILTER_TYPE.GAUSSIAN: filter = (int i, int frequency) => { return(Math.Exp(-0.005f * frequency * frequency)); }; // Gaussian break; case FILTER_TYPE.INVERSE: filter = (int i, int frequency) => { return(Math.Min(1.0, 4.0 / (1 + Math.Abs(frequency)))); }; // Inverse break; // case FILTER_TYPE.SINUS: // filter = ( int i, int frequency ) => { return Math.Sin( -2.0f * Math.PI * frequency / 32 ); }; // Gni ? // break; } if (filter != null) { int size = m_spectrum.Length; int halfSize = size >> 1; if (!checkBoxInvertFilter.Checked) { for (int i = 0; i < size; i++) { int frequency = ((i + halfSize) % size) - halfSize; double filterValue = filter(i, frequency); m_spectrum[i] *= filterValue; } } else { for (int i = 0; i < size; i++) { int frequency = ((size - i) % size) - halfSize; double filterValue = filter(i, frequency); m_spectrum[i] *= filterValue; } } } // Inverse Transform if (m_FFTW_1D != null && checkBoxUseFFTW.Checked) { m_FFTW_1D.FillInputFrequency((int x, int y, out float r, out float i) => { r = (float)m_spectrum[x].r; i = (float)m_spectrum[x].i; }); m_FFTW_1D.Execute(fftwlib.FFT2D.Normalization.NONE); m_FFTW_1D.GetOutput((int x, int y, float r, float i) => { m_signalReconstructed[x].Set(r, i); }); } else { // DFT1D.DFT_Inverse( m_spectrum, m_signalReconstructed ); FFT1D.FFT_Inverse(m_spectrum, m_signalReconstructed); } }
public static double GetUniform(double max) { return(max * SimpleRNG.GetUniform()); }
void GenWalls() { if (useRandomSeed) { SimpleRNG.SetSeedFromSystemTime(); } else { SimpleRNG.SetSeed((uint)manualSeed); } foreach (Cell c in cells) { unassignedRooms.Add(c); } Cell startRoom = null; int curRoom = 1; while (unassignedRooms.Count > 0) { // add room of random size int nextRoomSize = (int)(SimpleRNG.GetUniform() * (maxRoomSize - minRoomSize)) + minRoomSize; Cell centreCell = unassignedRooms[(int)(SimpleRNG.GetUniform() * (unassignedRooms.Count - 1))]; if (startRoom == null) { startRoom = centreCell; } // work out ideal bounds of new room int startX = centreCell.x - Mathf.CeilToInt(nextRoomSize / 2f) + 1; int endX = Mathf.Min(startX + nextRoomSize, cellsPerSide); startX = Mathf.Max(0, startX); int startY = centreCell.y - Mathf.CeilToInt(nextRoomSize / 2f) + 1; int endY = Mathf.Min(startY + nextRoomSize, cellsPerSide); startY = Mathf.Max(0, startY); var roomCells = new List <Cell>(); var lastInRoom = new List <int>(); // which rows in the last column had a room on it? If no rows match, column won't be inited and room will stop. Avoids split rooms for (int x = startX; x < endX; x++) { var cellsThisColumn = new List <int>(); if (lastInRoom.Count == 0) { // no cells in room yet, add first block bool started = false; for (int y = startY; y < endY; y++) { if (cells[x, y].room == 0) { cellsThisColumn.Add(y); started = true; } else if (started) { break; } } } else { // add last column's rooms to this column if valid, then spread up and down until hits another room foreach (int roomRow in lastInRoom) { if (!cellsThisColumn.Contains(roomRow) && cells[x, roomRow].room == 0) { cellsThisColumn.Add(roomRow); for (int south = roomRow - 1; south >= startY; south--) { if (cells[x, south].room == 0) { cellsThisColumn.Add(south); } else { break; } } for (int north = roomRow + 1; north < endY; north++) { if (cells[x, north].room == 0) { cellsThisColumn.Add(north); } else { break; } } } } // if no valid connection after room has started, stop making room if (cellsThisColumn.Count == 0) { break; } } // actually make rooms foreach (int row in cellsThisColumn) { // for each cell within room edges, add walls between neighbouring rooms (if not in another room already) // add each valid room to list, and if can't path to first room after all rooms done, make holes Cell roomCell = cells[x, row]; if (AddCellToRoom(roomCell, curRoom)) { roomCells.Add(roomCell); } } lastInRoom = cellsThisColumn; } Debug.Log("Room made"); PrintLayout(); // try to path to start room if (roomCells.Count > 0 && CellPath.PathTo(startRoom.centrePosition, roomCells[0].centrePosition) == null) { // no path, make corridor to first cell Cell pathEnd = null; int distToTarg = int.MaxValue; foreach (Cell edgeCell in roomCells) { int newDist = Mathf.Abs(edgeCell.x - startRoom.x) + Mathf.Abs(edgeCell.y - startRoom.y); if (newDist < distToTarg) { distToTarg = newDist; pathEnd = edgeCell; } } while (pathEnd.room == curRoom) { Debug.Log("Opening path from " + pathEnd); int xDist = startRoom.x - pathEnd.x; int yDist = startRoom.y - pathEnd.y; if (xDist >= Mathf.Abs(yDist)) { pathEnd = OpenCellInDirection(pathEnd, Direction.East); } else if (xDist <= -Mathf.Abs(yDist)) { pathEnd = OpenCellInDirection(pathEnd, Direction.West); } else if (yDist > Mathf.Abs(xDist)) { pathEnd = OpenCellInDirection(pathEnd, Direction.North); } else if (yDist < -Mathf.Abs(xDist)) { pathEnd = OpenCellInDirection(pathEnd, Direction.South); } } // check if can path. JUST IN CASE if (CellPath.PathTo(startRoom.centrePosition, roomCells[0].centrePosition) == null) { Debug.LogWarning("Still no path from room " + curRoom); PrintLayout(); } } curRoom++; } Debug.Log("Layout complete..."); PrintLayout(); // Instantiate walls? var verticalWalls = new Cell[cellsPerSide, cellsPerSide]; for (int x = 0; x < cellsPerSide - 1; x++) { int wallType = Random.Range(0, wallPrefabs.Length); for (int y = 0; y < cellsPerSide; y++) { if (!cells[x, y].canGoEast) { CreateWall(cells[x, y], Direction.East, wallType); verticalWalls[x, y] = cells[x, y]; if (y > 0 && verticalWalls[x, y - 1] == null) { CreateWallCap(cells[x, y], true); } } else { wallType = Random.Range(0, wallPrefabs.Length); if (y > 0 && verticalWalls[x, y - 1] != null) { CreateWallCap(cells[x, y], true); } } } } var horizontalWalls = new Cell[cellsPerSide, cellsPerSide]; for (int y = 0; y < cellsPerSide - 1; y++) { int wallType = Random.Range(0, wallPrefabs.Length); for (int x = 0; x < cellsPerSide; x++) { if (!cells[x, y].canGoNorth) { CreateWall(cells[x, y], Direction.North, wallType); horizontalWalls[x, y] = cells[x, y]; if (x > 0 && horizontalWalls[x - 1, y] == null) { CreateWallCap(cells[x, y], false); } } else { wallType = Random.Range(0, wallPrefabs.Length); if (x > 0 && horizontalWalls[x - 1, y] != null) { CreateWallCap(cells[x, y], false); } } } } }
/// <summary> /// Adds the cell to given room. /// </summary> /// <returns> /// Whether the cell was added /// </returns> /// <param name='newCell'> /// Cell to add /// </param> /// <param name='inRoom'> /// Room number to add to /// </param> bool AddCellToRoom(Cell newCell, int inRoom) { // Add walls between this and cells that have been set to other rooms if (newCell.room == 0) { newCell.room = inRoom; if (newCell.x > 0 && newCell.CellInDirection(Direction.West).room != 0 && newCell.CellInDirection(Direction.West).room != inRoom && SimpleRNG.GetUniform() < wallDensity) { newCell.canGoWest = newCell.CellInDirection(Direction.West).canGoEast = false; } if (newCell.x < cellsPerSide - 1 && newCell.CellInDirection(Direction.East).room != 0 && newCell.CellInDirection(Direction.East).room != inRoom && SimpleRNG.GetUniform() < wallDensity) { newCell.canGoEast = newCell.CellInDirection(Direction.East).canGoWest = false; } if (newCell.y > 0 && newCell.CellInDirection(Direction.South).room != 0 && newCell.CellInDirection(Direction.South).room != inRoom && SimpleRNG.GetUniform() < wallDensity) { newCell.canGoSouth = newCell.CellInDirection(Direction.South).canGoNorth = false; } if (newCell.y < cellsPerSide - 1 && newCell.CellInDirection(Direction.North).room != 0 && newCell.CellInDirection(Direction.North).room != inRoom && SimpleRNG.GetUniform() < wallDensity) { newCell.canGoNorth = newCell.CellInDirection(Direction.North).canGoSouth = false; } unassignedRooms.Remove(newCell); return(true); } return(false); }
/// <summary> /// Generates blue noise distribution by randomly swapping pixels in the texture to reach lowest possible score and minimize a specific energy function /// </summary> /// <param name="_randomSeed"></param> /// <param name="_maxIterations">The maximum amount of iterations before exiting with the last best solution</param> /// <param name="_standardDeviationImage">Standard deviation for image space. If not sure, use 2.1</param> /// <param name="_standardDeviationValue">Standard deviation for value space. If not sure, use 1.0</param> /// <param name="_neighborsOnlyMutations">True to only authorize mutations of neighbor pixels, false to randomly mutate any pixel</param> /// <param name="_notifyProgressEveryNIterations">Will read back the GPU texture to the CPU and notify of progress every N iterations</param> /// <param name="_progress"></param> public void Generate(uint _randomSeed, uint _maxIterations, float _standardDeviationImage, float _standardDeviationValue, bool _neighborsOnlyMutations, uint _notifyProgressEveryNIterations, ProgressDelegate _progress) { m_CB_Main.m._texturePOT = (uint)m_texturePOT; m_CB_Main.m._textureSize = m_textureSize; m_CB_Main.m._textureMask = m_textureSizeMask; m_CB_Main.m._kernelFactorSpatial = -1.0f / (_standardDeviationImage * _standardDeviationImage); m_CB_Main.m._kernelFactorValue = -1.0f / (_standardDeviationValue * _standardDeviationValue); m_CB_Main.UpdateData(); ////////////////////////////////////////////////////////////////////////// // Generate initial white noise { SimpleRNG.SetSeed(_randomSeed, 362436069U); switch (m_vectorDimension) { case 1: { // Build ordered initial values float[,] initialValues = new float[m_textureSize, m_textureSize]; for (uint Y = 0; Y < m_textureSize; Y++) { for (uint X = 0; X < m_textureSize; X++) { initialValues[X, Y] = (float)(m_textureSize * Y + X) / m_textureTotalSize; } } // Displace them randomly for (uint i = 0; i < m_textureTotalSize; i++) { uint startX = GetUniformInt(m_textureSize); uint startY = GetUniformInt(m_textureSize); uint endX = GetUniformInt(m_textureSize); uint endY = GetUniformInt(m_textureSize); float temp = initialValues[startX, startY]; initialValues[startX, startY] = initialValues[endX, endY]; initialValues[endX, endY] = temp; } m_texNoiseCPU.WritePixels(0, 0, (uint _X, uint _Y, System.IO.BinaryWriter _W) => { _W.Write(initialValues[_X, _Y]); }); break; } case 2: { // Build ordered initial values float2[,] initialValues = new float2[m_textureSize, m_textureSize]; for (uint Y = 0; Y < m_textureSize; Y++) { for (uint X = 0; X < m_textureSize; X++) { initialValues[X, Y].Set((float)(m_textureSize * Y + X) / m_textureTotalSize, (float)(m_textureSize * Y + X) / m_textureTotalSize); } } // Displace them randomly for (uint i = 0; i < m_textureTotalSize; i++) { uint startX = GetUniformInt(m_textureSize); uint startY = GetUniformInt(m_textureSize); uint endX = GetUniformInt(m_textureSize); uint endY = GetUniformInt(m_textureSize); float temp = initialValues[startX, startY].x; initialValues[startX, startY].x = initialValues[endX, endY].x; initialValues[endX, endY].x = temp; startX = GetUniformInt(m_textureSize); startY = GetUniformInt(m_textureSize); endX = GetUniformInt(m_textureSize); endY = GetUniformInt(m_textureSize); temp = initialValues[startX, startY].y; initialValues[startX, startY].y = initialValues[endX, endY].y; initialValues[endX, endY].y = temp; } m_texNoiseCPU.WritePixels(0, 0, (uint _X, uint _Y, System.IO.BinaryWriter _W) => { _W.Write(initialValues[_X, _Y].x); _W.Write(initialValues[_X, _Y].y); }); break; } } m_texNoise0.CopyFrom(m_texNoiseCPU); } ////////////////////////////////////////////////////////////////////////// // Perform iterations float bestScore = ComputeScore(m_texNoise0); float score = bestScore; uint iterationIndex = 0; uint mutationsRate = MAX_MUTATIONS_RATE; int iterationsCountWithoutImprovement = 0; #if !CAILLOU float maxIterationsCountWithoutImprovementBeforeDecreasingMutationsCount = 0.1f * m_textureTotalSize; // Arbitrary: 10% of the texture size #else float maxIterationsCountWithoutImprovementBeforeDecreasingMutationsCount = 0.01f * m_textureTotalSize; // Arbitrary: 1% of the texture size #endif // float maxIterationsCountWithoutImprovementBeforeDecreasingMutationsCount = 0.002f * m_textureTotalSize; // Arbitrary: 0.2% of the texture size float averageIterationsCountWithoutImprovement = 0.0f; float alpha = 0.001f; uint[] neighborOffsetX = new uint[8] { 0, 1, 2, 2, 2, 1, 0, 0 }; uint[] neighborOffsetY = new uint[8] { 0, 0, 0, 1, 2, 2, 2, 1 }; List <float> statistics = new List <float>(); //ReadBackScoreTexture( m_texNoiseScore2, textureCPU ); while (iterationIndex < _maxIterations) { ////////////////////////////////////////////////////////////////////////// // Copy if (m_CS_Copy.Use()) { m_texNoise0.SetCS(0); m_texNoise1.SetCSUAV(0); uint groupsCount = m_textureSize >> 4; m_CS_Copy.Dispatch(groupsCount, groupsCount, 1); } ////////////////////////////////////////////////////////////////////////// // Mutate current solution by swapping up to N pixels randomly if (m_CS_Mutate.Use()) { // Fill up mutations buffer if (_neighborsOnlyMutations) { // Swap neighbor pixels only for (int mutationIndex = 0; mutationIndex < mutationsRate; mutationIndex++) { uint sourceIndex = GetUniformInt(m_textureTotalSize); uint X, Y; ComputeXYFromSingleIndex(sourceIndex, out X, out Y); // Randomly pick one of the 8 neighbors uint neighborIndex = SimpleRNG.GetUint() & 0x7; uint Xn = (X + m_textureSizeMask + neighborOffsetX[neighborIndex]) & m_textureSizeMask; uint Yn = (Y + m_textureSizeMask + neighborOffsetY[neighborIndex]) & m_textureSizeMask; m_SB_Mutations.m[mutationIndex]._pixelSourceX = X; m_SB_Mutations.m[mutationIndex]._pixelSourceY = Y; m_SB_Mutations.m[mutationIndex]._pixelTargetX = Xn; m_SB_Mutations.m[mutationIndex]._pixelTargetY = Yn; if (m_vectorDimension > 1) { m_SB_Mutations.m[mutationIndex]._pixelTargetY |= SimpleRNG.GetUniform() > 0.5 ? 0x80000000U : 0x40000000U; } } } else { // Swap pixels randomly for (int mutationIndex = 0; mutationIndex < mutationsRate; mutationIndex++) { uint sourceIndex = GetUniformInt(m_textureTotalSize); uint targetIndex = GetUniformInt(m_textureTotalSize); ComputeXYFromSingleIndex(sourceIndex, out m_SB_Mutations.m[mutationIndex]._pixelSourceX, out m_SB_Mutations.m[mutationIndex]._pixelSourceY); ComputeXYFromSingleIndex(targetIndex, out m_SB_Mutations.m[mutationIndex]._pixelTargetX, out m_SB_Mutations.m[mutationIndex]._pixelTargetY); if (m_vectorDimension > 1) { m_SB_Mutations.m[mutationIndex]._pixelTargetY |= SimpleRNG.GetUniform() > 0.5 ? 0x80000000U : 0x40000000U; } } } m_SB_Mutations.Write(mutationsRate); m_SB_Mutations.SetInput(1); m_CS_Mutate.Dispatch(mutationsRate, 1, 1); m_texNoise0.RemoveFromLastAssignedSlots(); m_texNoise1.RemoveFromLastAssignedSlotUAV(); } ////////////////////////////////////////////////////////////////////////// // Compute new score float previousScore = score; score = ComputeScore(m_texNoise1); if (score < bestScore) { // New best score! Swap textures so we accept the new state... bestScore = score; Texture2D temp = m_texNoise0; m_texNoise0 = m_texNoise1; m_texNoise1 = temp; iterationsCountWithoutImprovement = 0; } else { iterationsCountWithoutImprovement++; } averageIterationsCountWithoutImprovement *= 1.0f - alpha; averageIterationsCountWithoutImprovement += alpha * iterationsCountWithoutImprovement; if (averageIterationsCountWithoutImprovement > maxIterationsCountWithoutImprovementBeforeDecreasingMutationsCount) { averageIterationsCountWithoutImprovement = 0.0f; // Start over... mutationsRate >>= 1; // Halve mutations count if (mutationsRate == 0) { break; // Clearly we've reached a steady state here... } } //statistics.Add( averageIterationsCountWithoutImprovement ); ////////////////////////////////////////////////////////////////////////// // Notify iterationIndex++; if (_progress == null || (iterationIndex % _notifyProgressEveryNIterations) != 1) { continue; } // _progress( iterationIndex, mutationsCount, bestScore, ReadBackScoreTexture( m_texNoiseScore ), statistics ); // Notify! switch (m_vectorDimension) { case 1: _progress(iterationIndex, mutationsRate, bestScore, ReadBackTexture1D(m_texNoise0), statistics); break; // Notify! case 2: _progress(iterationIndex, mutationsRate, bestScore, ReadBackTexture2D(m_texNoise0), statistics); break; // Notify! } } // One final call with our best final result switch (m_vectorDimension) { case 1: ReadBackTexture1D(m_texNoise0); break; case 2: ReadBackTexture2D(m_texNoise0); break; } if (_progress != null) { // _progress( iterationIndex, mutationsCount, bestScore, ReadBackScoreTexture( m_texNoiseScore ), statistics ); // Notify! switch (m_vectorDimension) { case 1: _progress(iterationIndex, mutationsRate, bestScore, ReadBackTexture1D(m_texNoise0), statistics); break; // Notify! case 2: _progress(iterationIndex, mutationsRate, bestScore, ReadBackTexture2D(m_texNoise0), statistics); break; // Notify! } } }
// public float3x3 MakeRot( float3 _from, float3 _to ) { // float3 v = _from.Cross( _to ); // float c = _from.Dot( _to ); // float k = 1.0f / (1.0f + c); // // float3x3 R = new float3x3(); // R.m[0, 0] = v.x*v.x*k + c; R.m[0, 1] = v.y*v.x*k - v.z; R.m[0, 2] = v.z*v.x*k + v.y; // R.m[1, 0] = v.x*v.y*k + v.z; R.m[1, 1] = v.y*v.y*k + c; R.m[1, 2] = v.z*v.y*k - v.x; // R.m[2, 0] = v.x*v.z*k - v.y; R.m[2, 1] = v.y*v.z*k + v.x; R.m[2, 2] = v.z*v.z*k + c; // // return R; // } public FittingForm() { // Random RNG = new Random(); // float3 From = new float3( 2.0f * (float) RNG.NextDouble() - 1.0f, 2.0f * (float) RNG.NextDouble() - 1.0f, 2.0f * (float) RNG.NextDouble() - 1.0f ).Normalized; // float3 To = new float3( 2.0f * (float) RNG.NextDouble() - 1.0f, 2.0f * (float) RNG.NextDouble() - 1.0f, 2.0f * (float) RNG.NextDouble() - 1.0f ).Normalized; // float3x3 Pipo = MakeRot( From, To ); // float3 Test = Pipo * From; //TestChromaRanges(); //TestSHRGBEEncoding(); //TestSquareFilling(); InitializeComponent(); // Create the random points List <float3> RandomDirections = new List <float3>(); List <float> RandomThetas = new List <float>(); for (int LobeIndex = 0; LobeIndex < m_RandomLobes.Length; LobeIndex++) { float MainPhi = (float)(m_RandomLobes[LobeIndex].Phi * Math.PI / 180.0f); float MainTheta = (float)(m_RandomLobes[LobeIndex].Theta * Math.PI / 180.0f); float Concentration = m_RandomLobes[LobeIndex].Concentration; int PointsCount = m_RandomLobes[LobeIndex].RandomPointsCount; // Build the main direction for the target lobe float3 MainDirection = new float3( (float)(Math.Sin(MainTheta) * Math.Sin(MainPhi)), (float)(Math.Cos(MainTheta)), (float)(Math.Sin(MainTheta) * Math.Cos(MainPhi)) ); // Build the transform to bring Y-aligned points to the main direction float3x3 Rot = new float3x3(); Rot.BuildRot(float3.UnitY, MainDirection); BuildDistributionMapping(Concentration, 0.0); // Draw random points in the Y-aligned hemisphere and transform them into the main direction for (int PointIndex = 0; PointIndex < PointsCount; PointIndex++) { double Theta = GetTheta(); float CosTheta = (float)Math.Cos(Theta); // float SinTheta = (float) Math.Sqrt( 1.0f - CosTheta*CosTheta ); float SinTheta = (float)Math.Sin(Theta); float Phi = (float)(SimpleRNG.GetUniform() * Math.PI); float3 RandomDirection = new float3( (float)(SinTheta * Math.Sin(Phi)), CosTheta, (float)(SinTheta * Math.Cos(Phi)) ); float3 FinalDirection = RandomDirection * Rot; RandomDirections.Add(FinalDirection); RandomThetas.Add(CosTheta); } } m_RandomDirections = RandomDirections.ToArray(); m_RandomThetas = RandomThetas.ToArray(); panelOutput.UpdateBitmap(); panelOutputNormalDistribution.UpdateBitmap(); // Do it! FitLobe[] Result = new FitLobe[FITTING_LOBES_COUNT]; for (int h = 0; h < Result.Length; h++) { Result[h] = new FitLobe(); } PerformExpectationMaximization(m_RandomDirections, Result); }
private void buttonShootPhotons_Click(object sender, EventArgs e) { ////////////////////////////////////////////////////////////////////////// // 1] Build initial photon positions and directions float3 SunDirection = new float3(0, 1, 0).Normalized; uint InitialDirection = PackPhotonDirection(-SunDirection); uint InitialColor = EncodeRGBE(new float3(1.0f, 1.0f, 1.0f)); int PhotonsPerSize = (int)Math.Floor(Math.Sqrt(PHOTONS_COUNT)); float PhotonCoverageSize = CLOUDSCAPE_SIZE / PhotonsPerSize; for (int PhotonIndex = 0; PhotonIndex < PHOTONS_COUNT; PhotonIndex++) { int Z = PhotonIndex / PhotonsPerSize; int X = PhotonIndex - Z * PhotonsPerSize; float x = ((X + (float)SimpleRNG.GetUniform()) / PhotonsPerSize - 0.5f) * CLOUDSCAPE_SIZE; float z = ((Z + (float)SimpleRNG.GetUniform()) / PhotonsPerSize - 0.5f) * CLOUDSCAPE_SIZE; m_SB_Photons.m[PhotonIndex].Position.Set(x, z); m_SB_Photons.m[PhotonIndex].Direction = InitialDirection; m_SB_Photons.m[PhotonIndex].RGBE = InitialColor; #if DEBUG_INFOS m_SB_Photons.m[PhotonIndex].Infos.Set(0, 0, 0, 0); // Will store scattering events counter, marched length, steps count, etc. #endif } m_SB_Photons.Write(); ////////////////////////////////////////////////////////////////////////// // 2] Initialize layers & textures // 2.1) Fill source bucket with all photons for (int PhotonIndex = 0; PhotonIndex < PHOTONS_COUNT; PhotonIndex++) { m_SB_PhotonLayerIndices.m[PhotonIndex] = 0U; // Starting from top layer, direction is down } m_SB_PhotonLayerIndices.Write(); // 2.2) Clear photon splatting texture m_Device.Clear(m_Tex_PhotonLayers_Flux, new float4(0, 0, 0, 0)); m_Device.Clear(m_Tex_PhotonLayers_Direction, new float4(0, 0, 0, 0)); ////////////////////////////////////////////////////////////////////////// // 3] Prepare buffers & states m_CloudScapeSize.Set(CLOUDSCAPE_SIZE, floatTrackbarControlCloudscapeThickness.Value, CLOUDSCAPE_SIZE); // 3.1) Prepare density field m_Tex_DensityField.SetCS(2); // 3.2) Constant buffer for photon shooting m_CB_PhotonShooterInput.m.LayersCount = LAYERS_COUNT; m_CB_PhotonShooterInput.m.MaxScattering = 30; m_CB_PhotonShooterInput.m.LayerThickness = m_CloudScapeSize.y / LAYERS_COUNT; m_CB_PhotonShooterInput.m.SigmaScattering = floatTrackbarControlSigmaScattering.Value; // 0.04523893421169302263386206471922f; // re=6µm Gamma=2 N0=4e8 Sigma_t = N0 * PI * re² m_CB_PhotonShooterInput.m.CloudScapeSize = m_CloudScapeSize; // 3.3) Prepare photon splatting buffer & states m_CB_SplatPhoton.m.CloudScapeSize = m_CloudScapeSize; m_CB_SplatPhoton.m.SplatSize = 1.0f * (2.0f / m_Tex_PhotonLayers_Flux.Width); m_CB_SplatPhoton.m.SplatIntensity = 1.0f; // 1000.0f / PHOTONS_COUNT; m_Device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.ADDITIVE); // Splatting is additive m_Tex_PhotonLayers_Flux.RemoveFromLastAssignedSlots(); m_Tex_PhotonLayers_Direction.RemoveFromLastAssignedSlots(); ////////////////////////////////////////////////////////////////////////// // 4] Splat initial photons to the top layer m_PS_PhotonSplatter.Use(); m_SB_Photons.SetInput(0); // RO version for splatting m_SB_PhotonLayerIndices.SetInput(1); // RO version for splatting m_CB_SplatPhoton.m.LayerIndex = 0U; m_CB_SplatPhoton.UpdateData(); m_Device.SetRenderTargets(m_Tex_PhotonLayers_Flux.Width, m_Tex_PhotonLayers_Flux.Height, new View3D[] { m_Tex_PhotonLayers_Flux.GetView(0, 0, 0, 1), m_Tex_PhotonLayers_Direction.GetView(0, 0, 0, 1) }, null); m_Prim_Point.RenderInstanced(m_PS_PhotonSplatter, PHOTONS_COUNT); ////////////////////////////////////////////////////////////////////////// // 5] Render loop int BatchesCount = PHOTONS_COUNT / PHOTON_BATCH_SIZE; m_SB_ProcessedPhotonsCounter.SetOutput(2); for (int BounceIndex = 0; BounceIndex < BOUNCES_COUNT; BounceIndex++) { // 5.1] Process every layers from top to bottom m_SB_ProcessedPhotonsCounter.m[0] = 0; m_SB_ProcessedPhotonsCounter.Write(); // Reset processed photons counter for (int LayerIndex = 0; LayerIndex < LAYERS_COUNT; LayerIndex++) { // 5.1.1) Shoot a bunch of photons from layer "LayerIndex" to layer "LayerIndex+1" m_CS_PhotonShooter.Use(); m_CB_PhotonShooterInput.m.LayerIndex = (uint)LayerIndex; m_SB_Photons.RemoveFromLastAssignedSlots(); m_SB_PhotonLayerIndices.RemoveFromLastAssignedSlots(); m_SB_Photons.SetOutput(0); m_SB_PhotonLayerIndices.SetOutput(1); m_SB_Random.SetInput(0); m_SB_PhaseQuantile.SetInput(1); for (int BatchIndex = 0; BatchIndex < BatchesCount; BatchIndex++) { m_CB_PhotonShooterInput.m.BatchIndex = (uint)BatchIndex; m_CB_PhotonShooterInput.UpdateData(); m_CS_PhotonShooter.Dispatch(1, 1, 1); m_Device.Present(true); // Notify of progress progressBar1.Value = progressBar1.Maximum * (1 + BatchIndex + BatchesCount * (LayerIndex + LAYERS_COUNT * BounceIndex)) / (BOUNCES_COUNT * LAYERS_COUNT * BatchesCount); Application.DoEvents(); } #if DEBUG_INFOS //DEBUG Read back photons buffer m_SB_Photons.Read(); // m_SB_PhotonLayerIndices.Read(); // Verify photons have the same energy and were indeed transported to the next layer unaffected (this test is only valid if the density field is filled with 0s) // for ( int PhotonIndex=0; PhotonIndex < PHOTONS_COUNT; PhotonIndex++ ) // { // if ( m_SB_Photons.m[PhotonIndex].RGBE != 0x80FFFFFF ) // throw new Exception( "Intensity changed!" ); // if ( m_SB_PhotonLayerIndices.m[PhotonIndex] != LayerIndex+1 ) // throw new Exception( "Unexpected layer index!" ); // } //DEBUG #endif // 5.1.2) Splat the photons that got through to the 2D texture array m_PS_PhotonSplatter.Use(); m_SB_Photons.SetInput(0); // RO version for splatting m_SB_PhotonLayerIndices.SetInput(1); // RO version for splatting m_CB_SplatPhoton.m.LayerIndex = (uint)(LayerIndex + 1); m_CB_SplatPhoton.UpdateData(); m_Device.SetRenderTargets(m_Tex_PhotonLayers_Flux.Width, m_Tex_PhotonLayers_Flux.Height, new View3D[] { m_Tex_PhotonLayers_Flux.GetView(0, 0, LayerIndex + 1, 1), m_Tex_PhotonLayers_Direction.GetView(0, 0, LayerIndex + 1, 1) }, null); m_Prim_Point.RenderInstanced(m_PS_PhotonSplatter, PHOTONS_COUNT); } m_SB_ProcessedPhotonsCounter.Read(); if (m_SB_ProcessedPhotonsCounter.m[0] < LOW_PHOTONS_COUNT_RATIO * PHOTONS_COUNT) { break; // We didn't shoot a significant number of photons to go on... } // ================================================================================ // 5.2] Process every layers from bottom to top BounceIndex++; if (BounceIndex >= BOUNCES_COUNT) { break; } m_SB_ProcessedPhotonsCounter.m[0] = 0; m_SB_ProcessedPhotonsCounter.Write(); // Reset processed photons counter for (int LayerIndex = LAYERS_COUNT; LayerIndex > 0; LayerIndex--) { // 5.2.1) Shoot a bunch of photons from layer "LayerIndex" to layer "LayerIndex-1" m_CS_PhotonShooter.Use(); m_CB_PhotonShooterInput.m.LayerIndex = (uint)LayerIndex | 0x80000000U; // <= MSB indicates photons are going up m_SB_Photons.RemoveFromLastAssignedSlots(); m_SB_PhotonLayerIndices.RemoveFromLastAssignedSlots(); m_SB_Photons.SetOutput(0); m_SB_PhotonLayerIndices.SetOutput(1); m_SB_Random.SetInput(0); m_SB_PhaseQuantile.SetInput(1); for (int BatchIndex = 0; BatchIndex < BatchesCount; BatchIndex++) { m_CB_PhotonShooterInput.m.BatchIndex = (uint)BatchIndex; m_CB_PhotonShooterInput.UpdateData(); m_CS_PhotonShooter.Dispatch(1, 1, 1); m_Device.Present(true); // Notify of progress progressBar1.Value = progressBar1.Maximum * (1 + BatchIndex + BatchesCount * (LayerIndex + LAYERS_COUNT * BounceIndex)) / (BOUNCES_COUNT * LAYERS_COUNT * BatchesCount); Application.DoEvents(); } // 5.2.2) Splat the photons that got through to the 2D texture array m_PS_PhotonSplatter.Use(); m_SB_Photons.SetInput(0); // RO version for splatting m_SB_PhotonLayerIndices.SetInput(1); // RO version for splatting m_CB_SplatPhoton.m.LayerIndex = (uint)(LayerIndex - 1) | 0x80000000U; // <= MSB indicates photons are going up m_CB_SplatPhoton.UpdateData(); m_Device.SetRenderTargets(m_Tex_PhotonLayers_Flux.Width, m_Tex_PhotonLayers_Flux.Height, new View3D[] { m_Tex_PhotonLayers_Flux.GetView(0, 0, LayerIndex - 1, 0), m_Tex_PhotonLayers_Direction.GetView(0, 0, LayerIndex - 1, 0) }, null); m_Prim_Point.RenderInstanced(m_PS_PhotonSplatter, PHOTONS_COUNT); } m_SB_ProcessedPhotonsCounter.Read(); if (m_SB_ProcessedPhotonsCounter.m[0] < LOW_PHOTONS_COUNT_RATIO * PHOTONS_COUNT) { break; // We didn't shoot a significant number of photons to go on... } } m_Tex_PhotonLayers_Flux.RemoveFromLastAssignedSlots(); m_Tex_PhotonLayers_Direction.RemoveFromLastAssignedSlots(); Render(); }
void CreateNoiseSpectrum(Complex[,] _spectrum) { uint size = m_handMadeBlueNoise.Width; uint halfSize = size >> 1; double noiseScale = floatTrackbarControlScale.Value; double noiseBias = floatTrackbarControlOffset.Value; double radialOffset = floatTrackbarControlRadialOffset.Value; double radialScale = floatTrackbarControlRadialScale.Value; double distributionPower = floatTrackbarControlDistributionPower.Value; double sigma = floatTrackbarControlSigma.Value; Complex Cnoise = new Complex(); for (uint Y = 0; Y < m_handMadeBlueNoise.Height; Y++) { uint Yoff = (Y + halfSize) & (size - 1); int Yrel = (int)Y - (int)halfSize; for (uint X = 0; X < m_handMadeBlueNoise.Width; X++) { uint Xoff = (X + halfSize) & (size - 1); int Xrel = (int)X - (int)halfSize; // Fetch "center noise" from blue noise // Cnoise = output[(halfSize>>1) + (X & (halfSize-1)), (halfSize>>1) + (Y & (halfSize-1))]; // Cnoise /= maxAverage; // Center noise is already factored by the maximum average so we "renormalize it" // Apply simple uniform noise Cnoise.r = noiseScale * (Math.Pow(SimpleRNG.GetUniform(), distributionPower) - noiseBias); Cnoise.i = noiseScale * (Math.Pow(SimpleRNG.GetUniform(), distributionPower) - noiseBias); // Cnoise.r = noiseScale * (SimpleRNG.GetNormal() - noiseBias); // Cnoise.i = noiseScale * (SimpleRNG.GetNormal() - noiseBias); // Cnoise.r = noiseScale * (SimpleRNG.GetLaplace( 0, sigma ) - noiseBias); // Cnoise.i = noiseScale * (SimpleRNG.GetLaplace( 0, sigma ) - noiseBias); // Cnoise.r = 2.0 * SimpleRNG.GetNormal( 0, 1 ) - 1.0; // Cnoise.i = 2.0 * SimpleRNG.GetNormal( 0, 1 ) - 1.0; // Cnoise.r = 1.0; // Cnoise.i = 0.0; // Apply weighting by radial profile int sqRadius = Xrel * Xrel + Yrel * Yrel; // Use averaged radial profile extracted from the noise texture // int radius = (int) Math.Max( 1, Math.Min( halfSize-1, Math.Sqrt( sqRadius ) ) ); // double profileFactor = m_radialSliceAverage_Smoothed[radius].r; //profileFactor *= 2.0; // Use the Mathematica hand-fitted curve double profileFactor = RadialProfile(radialOffset + radialScale * Math.Sqrt(sqRadius) / halfSize); //profileFactor *= 0.75 / 1; //profileFactor *= 3.0; //profileFactor *= Math.Sqrt( 2.0 ); //profileFactor *= 1.1; Cnoise *= profileFactor; //Cnoise = output[Xoff,Yoff]; //Cnoise *= Math.Exp( 0.01 * Math.Max( 0.0, radius - 128 ) ); _spectrum[Xoff, Yoff] = Cnoise; } } _spectrum[0, 0].Set(floatTrackbarControlDC.Value, 0.0); // Central value for constant term #if COMPUTE_RADIAL_SLICE const int BUCKETS_COUNT = 1000; uint[] noiseDistributionHistogram = new uint[BUCKETS_COUNT]; for (uint i = 0; i < m_handMadeBlueNoise.Width * m_handMadeBlueNoise.Height; i++) { double noiseValue = noiseScale * (Math.Pow(SimpleRNG.GetUniform(), distributionPower) - noiseBias); double noiseValue2 = noiseScale * (Math.Pow(SimpleRNG.GetUniform(), distributionPower) - noiseBias); noiseValue = Math.Abs(noiseValue + noiseValue2); noiseValue = Math.Pow(SimpleRNG.GetUniform(), 0.5); noiseValue = SimpleRNG.GetUniform() < 0.5 ? 0.5 * Math.Sqrt(1.0 - noiseValue) : 1.0 - 0.5 * Math.Sqrt(1.0 - noiseValue); int bucketIndex = Math.Min(BUCKETS_COUNT - 1, (int)Math.Floor(noiseValue * BUCKETS_COUNT)); noiseDistributionHistogram[bucketIndex]++; } // for ( uint Y=0; Y < m_handMadeBlueNoise.Height; Y++ ) { // uint Yoff = (Y + halfSize) & (size-1); // int Yrel = (int) Y - (int) halfSize; // for ( uint X=0; X < m_handMadeBlueNoise.Width; X++ ) { // uint Xoff = (X + halfSize) & (size-1); // int Xrel = (int) X - (int) halfSize; // int sqRadius = Xrel*Xrel + Yrel*Yrel; // double radius = Math.Sqrt( sqRadius ) / halfSize; // if ( radius < 0.01f ) // continue; // Avoid central values because of too much imprecision // // double random = Math.Abs( _spectrum[Xoff,Yoff].r ); // double profileAmplitude = RadialProfile( radius ); // double normalizedRandom = random / profileAmplitude; // // int bucketIndex = Math.Min( BUCKETS_COUNT-1, (int) Math.Floor( normalizedRandom * BUCKETS_COUNT ) ); // noiseDistributionHistogram[bucketIndex]++; // } // } m_spectrumNoiseDistribution_Custom.Clear(float4.One); float2 rangeX = new float2(0, 1); float2 rangeY = new float2(0, 4.0f / BUCKETS_COUNT); m_spectrumNoiseDistribution_Custom.PlotGraph(float4.UnitW, rangeX, rangeY, ( float _x ) => { int bucketIndex = Math.Min(BUCKETS_COUNT - 1, (int)Math.Floor(_x * BUCKETS_COUNT)); return((float)noiseDistributionHistogram[bucketIndex] / (m_blueNoise.Width * m_blueNoise.Height)); }); #endif }
void NumericalIntegration() { // Generate a bunch of rays with equal probability on the hemisphere const int THETA_SAMPLES = 100; const int SAMPLES_COUNT = 4 * THETA_SAMPLES * THETA_SAMPLES; const double dPhi = 2.0 * Math.PI / (4 * THETA_SAMPLES); float3[] directions = new float3[SAMPLES_COUNT]; for (int Y = 0; Y < THETA_SAMPLES; Y++) { for (int X = 0; X < 4 * THETA_SAMPLES; X++) { double phi = dPhi * (X + SimpleRNG.GetUniform()); double theta = 2.0 * Math.Acos(Math.Sqrt(1.0 - 0.5 * (Y + SimpleRNG.GetUniform()) / THETA_SAMPLES)); // Uniform sampling on theta directions[4 * THETA_SAMPLES * Y + X].Set((float)(Math.Sin(theta) * Math.Cos(phi)), (float)(Math.Sin(theta) * Math.Sin(phi)), (float)Math.Cos(theta)); } } // Compute numerical integration for various sets of angles const int TABLE_SIZE = 100; float3 coneDirection = float3.Zero; float3[,] integratedSHCoeffs = new float3[TABLE_SIZE, TABLE_SIZE]; double avgDiffA0 = 0.0; double avgDiffA1 = 0.0; double avgDiffA2 = 0.0; for (int thetaIndex = 0; thetaIndex < TABLE_SIZE; thetaIndex++) { // float cosTheta = 1.0f - (float) thetaIndex / TABLE_SIZE; float cosTheta = (float)Math.Cos(0.5 * Math.PI * thetaIndex / TABLE_SIZE); coneDirection.x = (float)Math.Sqrt(1.0f - cosTheta * cosTheta); coneDirection.z = cosTheta; for (int AOIndex = 0; AOIndex < TABLE_SIZE; AOIndex++) { // float AO = 1.0f - (float) AOIndex / TABLE_SIZE; // float coneHalfAngle = 0.5f * (float) Math.PI * AO; // Cone half angle varies in [0,PI/2] // float cosConeHalfAngle = (float) Math.Cos( coneHalfAngle ); float cosConeHalfAngle = (float)AOIndex / TABLE_SIZE; double A0 = 0.0; double A1 = 0.0; double A2 = 0.0; for (int sampleIndex = 0; sampleIndex < SAMPLES_COUNT; sampleIndex++) { float3 direction = directions[sampleIndex]; if (direction.Dot(coneDirection) < cosConeHalfAngle) { continue; // Sample is outside cone } float u = direction.z; // cos(theta_sample) float u2 = u * u; float u3 = u * u2; A0 += u; //A0 += 1.0; A1 += u2; A2 += 0.5 * (3 * u3 - u); } A0 *= 2.0 * Math.PI / SAMPLES_COUNT; A1 *= 2.0 * Math.PI / SAMPLES_COUNT; A2 *= 2.0 * Math.PI / SAMPLES_COUNT; A0 *= Math.Sqrt(1.0 / (4.0 * Math.PI)); A1 *= Math.Sqrt(3.0 / (4.0 * Math.PI)); A2 *= Math.Sqrt(5.0 / (4.0 * Math.PI)); // float3 verify = EstimateLambertReflectanceFactors( cosConeHalfAngle, 0.5f * (float) Math.PI * thetaIndex / TABLE_SIZE ); // avgDiffA0 += Math.Abs( A0 - verify.x ); // avgDiffA1 += Math.Abs( A1 - verify.y ); // avgDiffA2 += Math.Abs( A2 - verify.z ); integratedSHCoeffs[thetaIndex, AOIndex].Set((float)A0, (float)A1, (float)A2); } } avgDiffA0 /= TABLE_SIZE * TABLE_SIZE; avgDiffA1 /= TABLE_SIZE * TABLE_SIZE; avgDiffA2 /= TABLE_SIZE * TABLE_SIZE; using (System.IO.FileStream S = new System.IO.FileInfo(@"ConeTable_cosAO.float3").Create()) using (System.IO.BinaryWriter W = new System.IO.BinaryWriter(S)) { for (int thetaIndex = 0; thetaIndex < TABLE_SIZE; thetaIndex++) { for (int AOIndex = 0; AOIndex < TABLE_SIZE; AOIndex++) { W.Write(integratedSHCoeffs[thetaIndex, AOIndex].x); W.Write(integratedSHCoeffs[thetaIndex, AOIndex].y); W.Write(integratedSHCoeffs[thetaIndex, AOIndex].z); } } } }
private void buttonReset_Click(object sender, EventArgs e) { m_CB_Main.m._cameraSize = 10.0f * float2.One; m_CB_Main.m._cameraCenter = float2.Zero; m_CB_Main.UpdateData(); #if true for (int neuronIndex = 0; neuronIndex < m_nodesCount; neuronIndex++) { m_SB_NodeSims[0].m[neuronIndex].m_position.Set(0.5f * m_CB_Main.m._cameraSize.x * (2.0f * (float)SimpleRNG.GetUniform() - 1.0f), 0.5f * m_CB_Main.m._cameraSize.y * (2.0f * (float)SimpleRNG.GetUniform() - 1.0f)); // In a size 2 square //m_SB_NodeSims[0].m[neuronIndex].m_position.Set( 2.0f * neuronIndex - 1.0f, 0.0f ); m_SB_NodeSims[0].m[neuronIndex].m_velocity.Set(0, 0); } m_SB_NodeSims[0].Write(); #else for (int neuronIndex = 0; neuronIndex < m_nodesCount; neuronIndex++) { float a = Mathf.TWOPI * neuronIndex / m_nodesCount; m_SB_NodeSims[0].m[neuronIndex].m_position.Set(Mathf.Cos(a), Mathf.Sin(a)); // Set on a unit circle m_SB_NodeSims[0].m[neuronIndex].m_velocity.Set(0, 0); } m_SB_NodeSims[0].Write(); #endif }
private static double RdmGenerator(double max) { return(max * SimpleRNG.GetUniform()); }