const int SAMPLES_COUNT = 50; // Number of samples used to compute the average terms // compute the average direction of the BRDF public void ComputeAverageTerms(IBRDF _BRDF, ref float3 _tsView, float _alpha) { magnitude = 0.0; fresnel = 0.0; Z = float3.Zero; error = 0.0; double weight, pdf, eval; float3 tsLight = float3.Zero; float3 H = float3.Zero; for (int j = 0; j < SAMPLES_COUNT; ++j) { for (int i = 0; i < SAMPLES_COUNT; ++i) { float U1 = (i + 0.5f) / SAMPLES_COUNT; float U2 = (j + 0.5f) / SAMPLES_COUNT; // sample _BRDF.GetSamplingDirection(ref _tsView, _alpha, U1, U2, ref tsLight); // eval eval = _BRDF.Eval(ref _tsView, ref tsLight, _alpha, out pdf); if (pdf == 0.0f) { continue; } H = (_tsView + tsLight).Normalized; // accumulate weight = eval / pdf; if (double.IsNaN(weight)) { throw new Exception("NaN!"); } magnitude += weight; fresnel += weight * Math.Pow(1 - Math.Max(0.0f, _tsView.Dot(H)), 5.0); Z += (float)weight * tsLight; } } magnitude /= SAMPLES_COUNT * SAMPLES_COUNT; fresnel /= SAMPLES_COUNT * SAMPLES_COUNT; // Finish building the average TBN orthogonal basis Z.y = 0.0f; // clear y component, which should be zero with isotropic BRDFs float length = Z.Length; if (length > 0.0f) { Z /= length; } else { Z = float3.UnitZ; } X.Set(Z.z, 0, -Z.x); Y = float3.UnitY; }
public void Read(BinaryReader _R) { m_index = _R.ReadInt32(); m_isValid = _R.ReadBoolean(); m_isNatural = _R.ReadBoolean(); m_isClosing = _R.ReadBoolean(); m_wsPosition.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); m_wsNormal.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); m_wsCenter.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); m_lines.Clear(); m_removedLines.Clear(); int linesCount = _R.ReadInt32(); for (int lineIndex = 0; lineIndex < linesCount; lineIndex++) { line_t L = new line_t(this); m_lines.Add(L); L.Read(_R); } int removedLinesCount = _R.ReadInt32(); for (int removedLinesIndex = 0; removedLinesIndex < removedLinesCount; removedLinesIndex++) { line_t L = new line_t(this); m_removedLines.Add(L); L.Read(_R); } }
// Build orthonormal basis from a 3D Unit Vector Without normalization [Frisvad2012]) void BuildOrthonormalBasis(float3 _normal, ref float3 _tangent, ref float3 _bitangent) { float a = _normal.z > -0.9999999f ? 1.0f / (1.0f + _normal.z) : 0.0f; float b = -_normal.x * _normal.y * a; _tangent.Set(1.0f - _normal.x * _normal.x * a, b, -_normal.x); _bitangent.Set(b, 1.0f - _normal.y * _normal.y * a, -_normal.y); }
public void Load(System.IO.BinaryReader _R) { albedo.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); opacity = _R.ReadSingle(); normal.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); variance = _R.ReadSingle(); accumulationCounter = _R.ReadInt32(); }
public OctreeNode(System.IO.BinaryReader _R) { m_wsCornerMin.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); m_size = _R.ReadSingle(); m_halfSize = 0.5f * m_size; m_level = 0; Load(_R); }
// Sets the resolution of the grid cells by which the positions are descretized public void SetGridCellSize(float3 _cellSize) { if (_cellSize.x < 1e-6f || _cellSize.y < 1e-6f || _cellSize.z < 1e-6f) { throw new Exception("Cell size is too small!"); } m_cellSize = _cellSize; m_invCellSize.Set(1.0f / _cellSize.x, 1.0f / _cellSize.y, 1.0f / _cellSize.z); }
public void Read(BinaryReader _R) { m_wsPosition.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); m_planes.Clear(); int planesCount = _R.ReadInt32(); for (int planeIndex = 0; planeIndex < planesCount; planeIndex++) { plane_t P = new plane_t(this); m_planes.Add(P); P.Read(_R); } }
public void Read(BinaryReader _R) { m_wsPosition.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); m_wsDirection.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); m_wsOrthoDirection.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); m_vertices[0].Read(_R); m_vertices[1].Read(_R); m_planeIndices[0] = _R.ReadUInt32(); m_planeIndices[1] = _R.ReadUInt32(); m_clipperPlaneIndex = _R.ReadUInt32(); }
void LoadNormalMap(System.IO.FileInfo _normalMapFileName) { try { ImageFile tempImageNormal = new ImageFile(_normalMapFileName); // Make sure we accept the image double isPOT = Math.Log(tempImageNormal.Width) / Math.Log(2.0); if (tempImageNormal.Width != tempImageNormal.Height || (int)isPOT != isPOT) { throw new Exception("The converter only supports square power-of-two textures!\r\nThis image is " + tempImageNormal.Width + "x" + tempImageNormal.Height); } // Replace existing if (m_imageNormal != null) { m_imageNormal.Dispose(); m_imageNormal = null; } m_imageNormal = tempImageNormal; imagePanelNormal.Bitmap = m_imageNormal.AsBitmap; // Read normals m_size = m_imageNormal.Width; nx = new Complex[m_size, m_size]; ny = new Complex[m_size, m_size]; const float pipo = 1.0f; // Amplification test => no real change! float3 normal = float3.Zero; m_imageNormal.ReadPixels((uint X, uint Y, ref float4 _color) => { normal.Set(pipo * (2.0f * _color.x - 1.0f), pipo * (2.0f * _color.y - 1.0f), 2.0f * _color.z - 1.0f); normal.Normalize(); double fact = normal.z != 0.0 ? 1.0 / normal.z : 0.0; nx[X, Y].Set(fact * normal.x, 0); ny[X, Y].Set(fact * normal.y, 0); }); // Enable conversion buttonConvert.Enabled = true; buttonConvertOneSided.Enabled = true; } catch (Exception _e) { MessageBox("An error occurred while loading the normal map:\r\n\r\n" + _e.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); } }
public Line3DCollider(float3 v1, float3 v2, ColliderInfo info) : this() { _header.Init(info, ColliderType.Line3D); var vLine = math.normalize(v2 - v1); // Axis of rotation to make 3D cylinder a cylinder along the z-axis var transAxis = new float3(vLine.y, -vLine.x, 0.0f); var l = math.lengthsq(transAxis); // line already points in z axis? if (l <= 1e-6f) { // choose arbitrary rotation vector transAxis.Set(1, 0f, 0f); } else { transAxis /= math.sqrt(l); } // Angle to rotate the line into the z-axis var dot = vLine.z; _matrix = new float3x3(); _matrix.RotationAroundAxis(transAxis, -math.sqrt(1 - dot * dot), dot); var trans1 = math.mul(_matrix, v1); var trans2Z = math.mul(_matrix, v2).z; // set up HitLineZ parameters _xy.x = trans1.x; _xy.y = trans1.y; _zLow = math.min(trans1.z, trans2Z); _zHigh = math.max(trans1.z, trans2Z); Bounds = new ColliderBounds(_header.Entity, _header.Id, new Aabb( math.min(v1.x, v2.x), math.max(v1.x, v2.x), math.min(v1.y, v2.y), math.max(v1.y, v2.y), math.min(v1.z, v2.z), math.max(v1.z, v2.z) )); }
/// <summary> /// Should always return something close to 1 /// </summary> /// <returns></returns> public double TestNormalization() { double sum = 0; float dtheta = 0.005f; float dphi = 0.025f; float3 L = new float3(); for (float theta = 0.0f; theta <= Mathf.PI; theta += dtheta) { for (float phi = 0.0f; phi <= Mathf.PI; phi += dphi) { L.Set(Mathf.Sin(theta) * Mathf.Cos(phi), Mathf.Sin(theta) * Mathf.Sin(phi), Mathf.Cos(theta)); sum += Mathf.Sin(theta) * Eval(ref L); } } sum *= dtheta * 2 * dphi; return(sum); }
/// <summary> /// Initializes the array of data we need to fit with the lobe model /// Computes the Center of Mass of the lobe /// </summary> /// <param name="_texHistogram_CPU"></param> /// <param name="_scatteringOrder"></param> public void InitTargetData(double[,] _histogramData) { m_histogramData = _histogramData; W = m_histogramData.GetLength(0); H = m_histogramData.GetLength(1); // Compute center of mass from which we'll measure distances m_centerOfMass = float3.Zero; float3 wsOutgoingDirection = float3.Zero; for (int Y = 0; Y < H; Y++) { // Y = theta bin index = 2.0 * LOBES_COUNT_THETA * pow2( sin( 0.5 * theta ) ) // We need theta: double theta = 2.0 * Math.Asin(Math.Sqrt(0.5 * Y / H)); double cosTheta = Math.Cos(theta); double sinTheta = Math.Sin(theta); for (int X = 0; X < W; X++) { // X = phi bin index = LOBES_COUNT_PHI * X / (2PI) // We need phi: double phi = 2.0 * Math.PI * X / W; double cosPhi = Math.Cos(phi); double sinPhi = Math.Sin(phi); // Build simulated microfacet reflection direction in macro-surface space double outgoingIntensity = m_histogramData[X, Y]; wsOutgoingDirection.Set((float)(outgoingIntensity * cosPhi * sinTheta), (float)(outgoingIntensity * sinPhi * sinTheta), (float)(outgoingIntensity * cosTheta)); // Accumulate lobe position m_centerOfMass += wsOutgoingDirection; } } m_centerOfMass /= W * H; }
/// <summary> /// This code tests the determinant of the transform matrices that rectify a /// </summary> void CheckMatrix() { const int COUNT_RADIUS = 10; const int COUNT_X = 10; const int COUNT_Y = 10; const int COUNT_Z = 10; const float Xmax = 10.0f; const float Ymax = 10.0f; const float Zmax = 4.0f; const float Rb = 2.0f; float3 P0 = float3.Zero; float3 T = new float3(1, 0, 0); float3 B = new float3(0, 1, 0); float3 N = new float3(0, 0, 1); // float3 Nt, Nb, Tn, Bn, Dtn, Dbn; // float4 P = float4.UnitW, Pt; // float4x4 M = new float4x4(); float3 P, Pt; float3x3 M = new float3x3(); float3x3 M2 = new float3x3(); float3x3 invM = new float3x3(); float3x3 invM2 = new float3x3(); float det, illuminance; // float depth; List <float[, , ]> determinantss = new List <float[, , ]>(COUNT_RADIUS); // for ( int radiusIndex=0; radiusIndex < COUNT_RADIUS; radiusIndex++ ) int radiusIndex = 10; { float[,,] determinants = new float[COUNT_Z, 1 + 2 * COUNT_Y, 1 + 2 * COUNT_X]; determinantss.Add(determinants); float radiusFactor = Mathf.Max(0.01f, 2.0f * radiusIndex / 100); float Rt = radiusFactor * Rb; T.Set(Rt, 0, 0); B.Set(0, Rb, 0); for (int Z = COUNT_Z; Z > 0; Z--) { P0.z = Zmax * Z / COUNT_Z; for (int Y = -COUNT_Y; Y <= COUNT_Y; Y++) { P0.y = Ymax * Y / COUNT_Y; for (int X = -COUNT_X; X <= COUNT_X; X++) { P0.x = Xmax * X / COUNT_X; #if true // Matrix is a simple slanted parallelogram M.r0 = (T - (P0.Dot(T) / P0.Dot(N)) * N) / (Rt * Rt); M.r1 = (B - (P0.Dot(B) / P0.Dot(N)) * N) / (Rb * Rb); M.r2 = N / P0.Dot(N); invM = M.Inverse; det = M.Determinant; // Construct inverse directly invM2.r0.Set(T.x, B.x, P0.x); invM2.r1.Set(T.y, B.y, P0.y); invM2.r2.Set(T.z, B.z, P0.z); M2 = invM2.Inverse; // Test matrix is working P = P0; Pt = M * P; P = T; Pt = M * P; P = -T; Pt = M * P; P = B; Pt = M * P; P = -B; Pt = M * P; P = float3.Lerp(0.5f * T - 0.25f * B, 0.5f * T - 0.25f * B + P0, 0.666f); Pt = M * P; // invM *= M; // invM2 *= M2; // Test lighting computation // Build rectangular area light corners in local space float3 lsAreaLightPosition = P0; float3[] lsLightCorners = new float3[4]; lsLightCorners[0] = lsAreaLightPosition + T + B; lsLightCorners[1] = lsAreaLightPosition + T - B; lsLightCorners[2] = lsAreaLightPosition - T - B; lsLightCorners[3] = lsAreaLightPosition - T + B; float3x3 world2TangentSpace = float3x3.Identity; // Assume we're already in tangent space // Transform them into tangent-space float3[] tsLightCorners = new float3[4]; tsLightCorners[0] = lsLightCorners[0] * world2TangentSpace; tsLightCorners[1] = lsLightCorners[1] * world2TangentSpace; tsLightCorners[2] = lsLightCorners[2] * world2TangentSpace; tsLightCorners[3] = lsLightCorners[3] * world2TangentSpace; // Compute diffuse disk illuminance = DiskIrradiance(tsLightCorners); #else // Stupid version where I still thought we needed a perspective projection matrix! depth = P0.Dot(N); // Altitude from plane Nt = P0.Dot(T) * N; Nb = P0.Dot(B) * N; Tn = P0.Dot(N) * T; // = depth * T Bn = P0.Dot(N) * B; // = depth * B #if true M.r0.Set((Tn - Nt) / Rt, 0); M.r1.Set((Bn - Nb) / Rb, 0); M.r2.Set(0, 0, 1, 0); M.r3.Set(-N, depth); #else Dtn = (Nt - Tn) / Rt; Dbn = (Nb - Bn) / Rb; M.r0.Set(Dtn, -P0.Dot(Dtn)); M.r1.Set(Dbn, -P0.Dot(Dbn)); M.r2.Set(N / depth, 0.0f); // Will normalize Z to 1 if P is at same altitude as P0 M.r3.Set(N, -P0.Dot(N)); // Here, use "depth" #endif det = M.Determinant; determinants[Z - 1, COUNT_Y + Y, COUNT_X + X] = det; // Test matrix is working P.Set(P0, 1); Pt = M * P; // Pt /= Pt.w; // This will NaN because W=0 in this particular case P.Set(Rt * T, 1); Pt = M * P; Pt /= Pt.w; P.Set(-Rt * T, 1); Pt = M * P; Pt /= Pt.w; P.Set(Rb * B, 1); Pt = M * P; Pt /= Pt.w; P.Set(-Rb * B, 1); Pt = M * P; Pt /= Pt.w; P.Set(float3.Lerp(0.5f * Rt * T - 0.25f * Rb * B, P0, 0.666f), 1); Pt = M * P; Pt /= Pt.w; #endif } } } } }
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(); }
public Surface(Model _Owner, BinaryReader _R) { m_Owner = _Owner; m_Material = Material.Find(m_Owner.ReadString(_R)); int MaterialIndex = (int)m_Owner.ReadBig32(_R); // Don't use that // Prepare triangles uint VerticesCount = _R.ReadUInt32(); uint IndicesCount = _R.ReadUInt32(); m_Vertices = new Vertex[VerticesCount]; m_Indices = new ushort[IndicesCount]; // Read vertex declaration int VertexElementsCount = (int)_R.ReadByte(); m_VertexElements = new VertexElement[VertexElementsCount]; for (int elementIndex = 0; elementIndex < VertexElementsCount; elementIndex++) { m_VertexElements[elementIndex].Read(_R); } // Read vertex scale & bias float3 XYZScale = new float3(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); float3 XYZBias = new float3(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); float2 UVScale = new float2(_R.ReadSingle(), _R.ReadSingle()); float2 UVBias = new float2(_R.ReadSingle(), _R.ReadSingle()); // Read vertices for (int i = 0; i < m_Vertices.Length; i++) { Vertex V = new Vertex(); m_Vertices[i] = V; foreach (VertexElement E in m_VertexElements) { E.ReadElement(_R, V); } } // Read indices for (int i = 0; i < m_Indices.Length; i++) { m_Indices[i] = _R.ReadUInt16(); if (m_Indices[i] >= m_Vertices.Length) { throw new Exception("Vertex index out of range!"); } } // Read bounds & stuff m_BoundsMin.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); m_BoundsMax.Set(_R.ReadSingle(), _R.ReadSingle(), _R.ReadSingle()); int detailOffset = _R.ReadInt32(); // End uint TrailingMagic = m_Owner.ReadBig32(_R); if ((TrailingMagic & 0x00FFFFFFU) != 0x004C4D42) { throw new Exception("Bad trailing magic!"); } }
public double Eval(double[] _newParameters) { double lobeTheta = _newParameters[0]; double lobeRoughness = _newParameters[1]; double lobeGlobalScale = _newParameters[2]; double lobeFlatten = _newParameters[3]; double maskingImportance = _newParameters[4]; // Flattening is not linear when using the anisotropic lobe model! if (m_lobeType == LOBE_TYPE.MODIFIED_PHONG_ANISOTROPIC) { lobeFlatten = Math.Pow(2.0, 4.0 * (lobeFlatten - 1.0)); // in [2e-4, 2e4], log space } double invLobeFlatten = 1.0 / lobeFlatten; // Compute constant masking term due to incoming direction double maskingIncoming = Masking(m_direction.z, lobeRoughness); // Masking( incoming ) // Compute lobe's reflection vector and tangent space using new parameters double cosTheta = Math.Cos(lobeTheta); double sinTheta = Math.Sin(lobeTheta); float3 lobe_normal = new float3((float)(sinTheta * m_incomingDirection_CosPhi), (float)(sinTheta * m_incomingDirection_SinPhi), (float)cosTheta); float3 lobe_tangent = new float3((float)-m_incomingDirection_SinPhi, (float)m_incomingDirection_CosPhi, 0.0f); // Always lying in the X^Y plane float3 lobe_biTangent = lobe_normal.Cross(lobe_tangent); // Compute sum double phi, theta, cosPhi, sinPhi; double outgoingIntensity_Simulated, length; double outgoingIntensity_Analytical, lobeIntensity; double difference; float3 wsOutgoingDirection = float3.Zero; float3 wsOutgoingDirection2 = float3.Zero; float3 lsOutgoingDirection = float3.Zero; double maskingOutGoing = 0.0; double maskingShadowing; double sum = 0.0; double sum_Simulated = 0.0; double sum_Analytical = 0.0; double sqSum_Simulated = 0.0; double sqSum_Analytical = 0.0; for (int Y = 0; Y < H; Y++) { // Formerly used wrong stuff! // // Y = theta bin index = 2.0 * LOBES_COUNT_THETA * pow2( sin( 0.5 * theta ) ) // // We need theta: // theta = 2.0 * Math.Asin( Math.Sqrt( 0.5 * Y / H ) ); // Y = theta bin index = LOBES_COUNT_THETA * (1 - cos( theta ) ) // // We need theta: theta = Math.Acos(1.0 - (float)Y / H); cosTheta = Math.Cos(theta); sinTheta = Math.Sin(theta); for (int X = 0; X < W; X++) { // X = phi bin index = LOBES_COUNT_PHI * X / (2PI) // We need phi: phi = 2.0 * Math.PI * X / W; cosPhi = Math.Cos(phi); sinPhi = Math.Sin(phi); // Build simulated microfacet reflection direction in macro-surface space outgoingIntensity_Simulated = m_histogramData[X, Y]; wsOutgoingDirection.Set((float)(cosPhi * sinTheta), (float)(sinPhi * sinTheta), (float)cosTheta); // Compute maksing term due to outgoing direction maskingOutGoing = Masking(wsOutgoingDirection.z, lobeRoughness); // Masking( outgoing ) // Compute projection of world space direction onto reflected direction float Vx = wsOutgoingDirection.Dot(lobe_tangent); float Vy = wsOutgoingDirection.Dot(lobe_biTangent); float Vz = wsOutgoingDirection.Dot(lobe_normal); //Vz = Math.Min( 0.99f, Vz ); float cosTheta_M = Math.Max(1e-6f, Vz); // Compute the lobe intensity in local space lobeIntensity = NDF(cosTheta_M, lobeRoughness); maskingShadowing = 1.0 + maskingImportance * (maskingIncoming * maskingOutGoing - 1.0); // = 1 when importance = 0, = masking when importance = 1 lobeIntensity *= maskingShadowing; // * Masking terms lobeIntensity *= lobeGlobalScale; // Apply additional lobe scaling/flattening length = m_flatteningEval(Vx, Vy, Vz, lobeFlatten, invLobeFlatten); outgoingIntensity_Analytical = lobeIntensity * length; // Lobe intensity was estimated in lobe space, account for scaling when converting back in world space // Sum the difference between simulated intensity and lobe intensity outgoingIntensity_Analytical *= m_oversizeFactor; // Apply tolerance factor so we're always a bit smaller than the simulated lobe if (m_fitUsingCenterOfMass) { double difference0 = outgoingIntensity_Simulated - outgoingIntensity_Analytical; float3 wsLobePosition_Simulated = (float)outgoingIntensity_Simulated * wsOutgoingDirection; float3 wsLobePosition_Analytical = (float)outgoingIntensity_Analytical * wsOutgoingDirection; // Subtract center of mass wsLobePosition_Simulated -= m_centerOfMass; wsLobePosition_Analytical -= m_centerOfMass; // Compute new intensities, relative to center of mass outgoingIntensity_Simulated = wsLobePosition_Simulated.Length; outgoingIntensity_Analytical = wsLobePosition_Analytical.Length; double difference1 = outgoingIntensity_Simulated - outgoingIntensity_Analytical; difference = 0.5 * difference0 + 0.5 * difference1; // difference *= (wsLobePosition_Simulated - wsLobePosition_Analytical).Length; // difference += (wsLobePosition_Simulated - wsLobePosition_Analytical).Length; // We also add the distance between lobe positions so it goes to the best of the 2 minima! } else { difference = outgoingIntensity_Simulated - outgoingIntensity_Analytical; // difference = outgoingIntensity_Simulated / Math.Max( 1e-6, outgoingIntensity_Analytical ) - 1.0; // difference = outgoingIntensity_Analytical / Math.Max( 1e-6, outgoingIntensity_Simulated ) - 1.0; } sum += difference * difference; sum_Simulated += outgoingIntensity_Simulated; sum_Analytical += outgoingIntensity_Analytical; sqSum_Simulated += outgoingIntensity_Simulated * outgoingIntensity_Simulated; sqSum_Analytical += outgoingIntensity_Analytical * outgoingIntensity_Analytical; } } sum /= W * H; // Not very useful since BFGS won't care but I'm doing it anyway to have some sort of normalized sum, better for us humans return(sum); }
private void CubeMapSamplerSH(Probe.Pixel _Pixel, out byte _R, out byte _G, out byte _B) { float3 Dir = _Pixel.View; // Dot the SH together float3 Color = float3.Zero; if (m_IsolateSet) { float Factor = 1.0f; if (m_bShowSHDynamic) { for (int i = 0; i < 9; i++) { Color += (float)_Pixel.SHCoeffs[i] * m_Probe.m_Sets[m_IsolatedSetIndex].SH[i]; } Factor = m_bNormalizeSH ? 2.0f * m_Probe.m_Sets[m_IsolatedSetIndex].SH[0].Max() : 1.0f; } if (m_bShowSHEmissive) { int EmissiveSetIndex = Math.Min(m_IsolatedSetIndex, m_Probe.m_EmissiveSets.Length - 1); if (EmissiveSetIndex >= 0) { for (int i = 0; i < 9; i++) { Color += (float)_Pixel.SHCoeffs[i] * m_Probe.m_EmissiveSets[EmissiveSetIndex].SH[i]; } } Factor = m_bNormalizeSH ? 2.0f * m_Probe.m_EmissiveSets[EmissiveSetIndex].SH[0].Max() : 1.0f; } // Color *= 100.0f; Color *= 1.0f / Factor; } else { float Factor = 0.0f; if (m_bShowSHStatic) { for (int i = 0; i < 9; i++) { Color += (float)_Pixel.SHCoeffs[i] * m_SHStatic[i]; } Factor = Math.Max(Factor, m_SHStatic[0].Max()); } if (m_bShowSHDynamic) { for (int i = 0; i < 9; i++) { Color += (float)_Pixel.SHCoeffs[i] * m_SHDynamic[i]; } Factor = Math.Max(Factor, m_SHDynamic[0].Max()); } if (m_bShowSHEmissive) { for (int i = 0; i < 9; i++) { Color += (float)_Pixel.SHCoeffs[i] * m_SHEmissive[i]; } Factor = Math.Max(Factor, m_SHEmissive[0].Max()); } if (m_bShowSHOcclusion) { for (int i = 0; i < 9; i++) { Color += (float)_Pixel.SHCoeffs[i] * m_SHOcclusion[i] * float3.One; } Factor = Math.Max(Factor, m_SHOcclusion[0]); } // Color *= 50.0f; Color *= m_bNormalizeSH ? 1.0f / Factor : 1.0f; } if (Color.x < 0.0f || Color.y < 0.0f || Color.z < 0.0f) { Color.Set(1, 0, 1); } _R = (byte)Math.Min(255, 255 * Color.x); _G = (byte)Math.Min(255, 255 * Color.y); _B = (byte)Math.Min(255, 255 * Color.z); }
public void SampleCubeMap(float3 _View, CubeMapSampler _Sampler, out byte _R, out byte _G, out byte _B) { AbsView.Set(Math.Abs(_View.x), Math.Abs(_View.y), Math.Abs(_View.z)); float MaxComponent = Math.Max(Math.Max(AbsView.x, AbsView.y), AbsView.z); fXYZ.Set(_View.x / MaxComponent, _View.y / MaxComponent, _View.z / MaxComponent); int FaceIndex = 0; if (Math.Abs(fXYZ.x) > 1.0 - 1e-6) { // +X or -X if (_View.x > 0.0) { FaceIndex = 0; fXY.Set(-fXYZ.z, fXYZ.y); } else { FaceIndex = 1; fXY.Set(fXYZ.z, fXYZ.y); } } else if (Math.Abs(fXYZ.y) > 1.0 - 1e-6) { // +Y or -Y if (_View.y > 0.0) { FaceIndex = 2; fXY.Set(fXYZ.x, -fXYZ.z); } else { FaceIndex = 3; fXY.Set(fXYZ.x, fXYZ.z); } } else // if ( Math.Abs( fXYZ.z ) > 1.0-1e-6 ) { // +Z or -Z if (_View.z > 0.0) { FaceIndex = 4; fXY.Set(fXYZ.x, fXYZ.y); } else { FaceIndex = 5; fXY.Set(-fXYZ.x, fXYZ.y); } } fXY.y = -fXY.y; int X = (int)(Probe.CUBE_MAP_SIZE * 0.5 * (1.0 + fXY.x)); int Y = (int)(Probe.CUBE_MAP_SIZE * 0.5 * (1.0 + fXY.y)); // if ( X < 0 || X > Probe.CUBE_MAP_SIZE-1 ) // throw new Exception(); // if ( Y < 0 || Y > Probe.CUBE_MAP_SIZE-1 ) // throw new Exception(); X = Math.Min(Probe.CUBE_MAP_SIZE - 1, X); Y = Math.Min(Probe.CUBE_MAP_SIZE - 1, Y); Probe.Pixel[,] CubeMapFace = m_Probe.m_CubeMap[FaceIndex]; _Sampler(CubeMapFace[X, Y], out _R, out _G, out _B); }