Jump to content
  • Advertisement
Sign in to follow this  
xxxkxxx

Specular convolution problem.

This topic is 543 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello guys! Another IBL / convolution topic here.

I was doing specular-ibl-ggx-convolution and had encountered following artefact. It happens on +Z and -Z faces.

This is -Z cubemap face viewed in Renderdoc (resolutions are 256x256, 128x128, 64x64, cubemap is little bit washed out because it is in float16 hdr format, so I had changed range to better visualize artefact):

[attachment=35679:bug.png]

In final rendered image looks like that:

[attachment=35680:bug1.PNG]

Looks like it "swirls" at poles along Z axis. Diameter of the "dot" in the middle depends on 0.999 number from:

float3 tangentY = ((abs(N.z) < 0.999) ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0));

Code for convolution is pretty standard:
 

uint ReverseBits(in uint bits)
{
	bits = (bits << 16u) | (bits >> 16u);
	bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
	bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
	bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
	bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);

	return bits;
}

float2 Hammersley(in uint i, in uint N)
{
	return float2(float(i) / float(N), float(ReverseBits(i)) * 2.3283064365386963e-10);
}

float3 ImportanceSampleGGX(in float roughness, in float2 eta)
{
	float phi = 2.0 * PI * eta.x;
	float cosTheta = sqrt((1.0 - eta.y) / ((roughness * roughness - 1.0) * eta.y + 1.0));
	float sinTheta = sqrt(1.0 - cosTheta * cosTheta);

	float3 H = float3(sinTheta * cos(phi),  sinTheta * sin(phi), cosTheta);

	return H;
}

float TrowbridgeReitzGGX(in float roughness, in float NdotH)
{
	float a2 = roughness * roughness;
	float denominator = (a2 * NdotH - NdotH) * NdotH + 1.0;

	return a2 / (PI * denominator * denominator);
}

float3 ConvolveEnvironmentMap(in float linearRoughness,
			      in float3 V,
			      in SamplerState trilinearSampler,
			      in TextureCube<float4> environmentMap,
			      in float currentResolution,
			      in float activeMipsCountZeroBased,
		              in uint currentMip)
{
	float3 N = V;

	float3 tangentY = ((abs(N.z) < 0.999) ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0));
	float3 tangentX = normalize(cross(tangentY, N));
	tangentY = cross(N, tangentX);

	float3x3 W = float3x3(tangentX, tangentY, N);

	float roughness = linearRoughness * linearRoughness;

	float3 Integral = float3(0.0, 0.0, 0.0);
	float Weight = 0.0;

	const uint samplesCount = 32;
	for (uint i = 0; i < samplesCount; i++)
	{
		float2 eta = Hammersley(i, samplesCount);
		float3 H = mul(ImportanceSampleGGX(roughness, eta), W);
		float3 L = 2.0 * dot(V, H) * H - V;
		float NdotL = saturate(dot(N, L));
		float NdotH = saturate(dot(N, H));
		float LdotH = saturate(dot(L, H));
		float pdf = DTrowbridgeReitzGGX(roughness, NdotH) * 0.25;
		float sampleSolidAngle = 1.0 / (float(samplesCount0) * pdf);
		float texelSolidAngle = (4.0 * PI) / (6.0 * currentResolution * currentResolution);
		float environmentMapMipLevel = clamp(0.5 * log2(sampleSolidAngle / texelSolidAngle), 0.0, activeMipsCountZeroBased);

		float3 Li = environmentMap.SampleLevel(trilinearSampler, L, environmentMapMipLevel).rgb;

		Integral += Li * NdotL;
		Weight += NdotL;
	}

	return Integral / Weight;
}

Here's calling compute shader:

cbuffer ConvolutionData : register(b0)
{
	...
}

SamplerState LinearClampSampler : register(s0);

TextureCube Input : register(t0);

RWTexture2DArray<float4> CurrentMipSlice : register(u0);

[numthreads(16, 16, 1)]
void cs_main(
	uint3 groupID : SV_GroupID,
	uint3 dispatchThreadID : SV_DispatchThreadID,
	uint3 groupThreadID : SV_GroupThreadID,
	uint groupIndex : SV_GroupIndex)
{
	const float2 uv = ((float2(dispatchThreadID.xy) + 0.5) * InvCubemapResolution) * 2.0 - 1.0;

	const float3 V0 = normalize(float3(1.0, -uv.y, -uv.x));
	const float3 V1 = normalize(float3(-1.0, -uv.y, uv.x));
	const float3 V2 = normalize(float3(uv.x, 1.0, uv.y));
	const float3 V3 = normalize(float3(uv.x, -1.0, -uv.y));
	const float3 V4 = normalize(float3(uv.x, -uv.y, 1.0));
	const float3 V5 = normalize(float3(-uv.x, -uv.y, -1.0));

        CurrentMipSlice[uint3(dispatchThreadID.xy, 0)] = float4(ConvolveEnvironmentMap(V0, ...), 1.0);
        CurrentMipSlice[uint3(dispatchThreadID.xy, 1)] = float4(ConvolveEnvironmentMap(V1, ...), 1.0);
        CurrentMipSlice[uint3(dispatchThreadID.xy, 2)] = float4(ConvolveEnvironmentMap(V2, ...), 1.0);
	CurrentMipSlice[uint3(dispatchThreadID.xy, 3)] = float4(ConvolveEnvironmentMap(V3, ...), 1.0);
        CurrentMipSlice[uint3(dispatchThreadID.xy, 4)] = float4(ConvolveEnvironmentMap(V4, ...), 1.0);
	CurrentMipSlice[uint3(dispatchThreadID.xy, 5)] = float4(ConvolveEnvironmentMap(V5, ...), 1.0);
}

Sample count is pretty low (32), but changing it to 64 doesn't really help. Also because I'm using FIS approach, it should look better than that, I think.

[attachment=35681:bug2.PNG]

Appreciate any help, thanks!

Edited by xxxkxxx

Share this post


Link to post
Share on other sites
Advertisement

Problem was solved by changing

float texelSolidAngle = (4.0 * PI) / (6.0 * currentResolution * currentResolution);
float environmentMapMipLevel = clamp(0.5 * log2(sampleSolidAngle / texelSolidAngle), 0.0, activeMipsCountZeroBased);

to

float texelSolidAngle = (4.0 * PI) / (6.0 * Mip0Resolution * Mip0Resolution);
float environmentMapMipLevel = max(0.5 * log2(sampleSolidAngle / texelSolidAngle) + 1.0, 0.0);

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!