I had to change CosineA2 to be Pi * 0.25f, which corresponds with the 1, 2/3, 1/4 bands
Whoops, sorry about that! I corrected the code, in case anybody else looks at this thread later on.
Either way, I'm glad that you got it to work!
Graphics/engine programmer for Ready At Dawn Studios
Posted by MJP on 07 September 2015 - 01:36 PM
I had to change CosineA2 to be Pi * 0.25f, which corresponds with the 1, 2/3, 1/4 bands
Posted by MJP on 06 September 2015 - 08:59 PM
static const float Pi = 3.141592654f; static const float CosineA0 = Pi; static const float CosineA1 = (2.0f * Pi) / 3.0f; static const float CosineA2 = Pi * 0.25f; struct SH9 { float c[9]; }; struct SH9Color { float3 c[9]; }; SH9 SHCosineLobe(in float3 dir) { SH9 sh; // Band 0 sh.c[0] = 0.282095f * CosineA0; // Band 1 sh.c[1] = 0.488603f * dir.y * CosineA1; sh.c[2] = 0.488603f * dir.z * CosineA1; sh.c[3] = 0.488603f * dir.x * CosineA1; // Band 2 sh.c[4] = 1.092548f * dir.x * dir.y * CosineA2; sh.c[5] = 1.092548f * dir.y * dir.z * CosineA2; sh.c[6] = 0.315392f * (3.0f * dir.z * dir.z - 1.0f) * CosineA2; sh.c[7] = 1.092548f * dir.x * dir.z * CosineA2; sh.c[8] = 0.546274f * (dir.x * dir.x - dir.y * dir.y) * CosineA2; return sh; } float3 ComputeSHIrradiance(in float3 normal, in SH9Color radiance) { // Compute the cosine lobe in SH, oriented about the normal direction SH9 shCosine = SHCosineLobe(normal); // Compute the SH dot product to get irradiance float3 irradiance = 0.0f; for(uint i = 0; i < 9; ++i) irradiance += radiance.c[i] * shCosine.c[i]; return irradiance; } float3 ComputeSHDiffuse(in float3 normal, in SH9Color radiance, in float3 diffuseAlbedo) { // Diffuse BRDF is albedo / Pi return ComputeSHIrradiance(normal, radiance) * diffuseAlbedo * (1.0f / Pi); }I assembled and simplified this code from different places, so I apologize if there's a typo in there. But it should give you the general idea. Those cosine A0/A1/A2 terms are from Ravi's paper, and they're the zonal harmonics coefficients of a cosine lobe oriented around the Z axis. Also, you should notice how to compute the final diffuse value, I had to divide the result by Pi. This is because the actual diffuse BRDF is albedo / Pi, and if you forget that factor the result will be too bright. If you'd like, you can combine the 1 / Pi into the AO/A1/A2 terms, which simplifies nicely.
Posted by MJP on 06 September 2015 - 04:58 PM
Posted by MJP on 06 September 2015 - 04:53 PM
Posted by MJP on 06 September 2015 - 04:41 PM
Posted by MJP on 05 September 2015 - 06:32 PM
I believe D3D9 debug runtimes only worked on Windows XP?
Can I find a sample of setting the dummy vertex shader anywhere?
float4x4 Projection; struct VSInput { float3 Position : POSITION; float4 Color : COLOR0; float2 TexCoord : TEXCOORD0; }; struct VSOutput { float3 Position : POSITION; float4 Color : COLOR0; float2 TexCoord : TEXCOORD0; }; VSOutput MainVS(in VSInput Input) { VSOutput Output; Output.Position = mul(float4(Input.Position, 1.0f), Projection); Output.TexCoord = Input.TexCoord; Output.Color = Input.Color; return Output; }All this shader does is transform the vertex position by a projection matrix, and then pass along the texture coordinates and color to the pixel shader.
Do I simply need to load a dummy vertex shader and call SetVertexShader? Any additional vertex configuration or rendering configuration that needs to be done?
Posted by MJP on 03 September 2015 - 11:55 PM
Posted by MJP on 02 September 2015 - 03:52 PM
Posted by MJP on 27 August 2015 - 03:27 PM
Posted by MJP on 25 August 2015 - 01:05 PM
const float SunSize = DegToRad(0.27f); // Angular radius of the sun from Earth float thetaS = std::acos(1.0f - sunDirection.y); float elevation = (Pi / 2.0f) - thetaS; Float3 sunRadiance; SampledSpectrum groundAlbedoSpectrum = SampledSpectrum::FromRGB(GroundAlbedo); SampledSpectrum solarRadiance; const uint64 NumDiscSamples = 8; for(uint64 x = 0; x < NumDiscSamples; ++x) { for(uint64 y = 0; y < NumDiscSamples; ++y) { float u = (x + 0.5f) / NumDiscSamples; float v = (y + 0.5f) / NumDiscSamples; Float2 discSamplePos = SquareToConcentricDiskMapping(u, v); float theta = elevation + discSamplePos.y * SunSize; float gamma = discSamplePos.x * SunSize; for(int32 i = 0; i < nSpectralSamples; ++i) { ArHosekSkyModelState* skyState = arhosekskymodelstate_alloc_init(elevation, turbidity, groundAlbedoSpectrum[i]); float wavelength = Lerp(float(SampledLambdaStart), float(SampledLambdaEnd), i / float(nSpectralSamples)); solarRadiance[i] = float(arhosekskymodel_solar_radiance(skyState, theta, gamma, wavelength)); arhosekskymodelstate_free(skyState); skyState = nullptr; } Float3 sampleRadiance = solarRadiance.ToRGB(); sunRadiance += sampleRadiance; } } // Account for coordinate system scaling, and sample averaging sunRadiance *= 100.0f * (1.0f / NumDiscSamples) * (1.0f / NumDiscSamples);This computes an average radiance across the entire solar disc. I'm doing it this way so that the code works with the rest of our framework, which currently works off the assumption that the solar disc has a uniform radiance. If you just want to compute the appropriate intensity to use for a directional light, then you can just directly compute irradiance instead. To this you need to evaluate the integral of cos(theta) * radiance, which you can do with monte carlo. Basically for each sample you compute you would multiply by N dot L (where 'N' is the direction towards the center of the sun, and 'L' is your current sample direction), and accumulate the sum. Then you would need to multiply the sum by InversePDF / NumSamples. Otherwise, if you assume the radiance is uniform then you can compute the irradiance integral analytically:
static float IlluminanceIntegral(float theta) { float cosTheta = std::cos(theta); return Pi * (1.0f - (cosTheta * cosTheta)); }where 'theta' is angular radiance of the sun. So the final irradiance would be IlluminanceIntegral(SunSize) * sunRadiance.
inline Float2 SquareToConcentricDiskMapping(float x, float y) { float phi = 0.0f; float r = 0.0f; // -- (a,b) is now on [-1,1]ˆ2 float a = 2.0f * x - 1.0f; float b = 2.0f * y - 1.0f; if(a > -b) // region 1 or 2 { if(a > b) // region 1, also |a| > |b| { r = a; phi = (Pi / 4.0f) * (b / a); } else // region 2, also |b| > |a| { r = b; phi = (Pi / 4.0f) * (2.0f - (a / b)); } } else // region 3 or 4 { if(a < b) // region 3, also |a| >= |b|, a != 0 { r = -a; phi = (Pi / 4.0f) * (4.0f + (b / a)); } else // region 4, |b| >= |a|, but a==0 and b==0 could occur. { r = -b; if(b != 0) phi = (Pi / 4.0f) * (6.0f - (a / b)); else phi = 0; } } Float2 result; result.x = r * std::cos(phi); result.y = r * std::sin(phi); return result; }Hope this helps!
Posted by MJP on 21 August 2015 - 03:43 PM
Posted by MJP on 18 August 2015 - 02:54 PM
Posted by MJP on 15 August 2015 - 04:28 PM
The interface kinda lets you believe that a DrawCall is executed when called.
Posted by MJP on 14 August 2015 - 03:24 PM
Posted by MJP on 14 August 2015 - 01:29 PM