Jump to content

View more

Image of the Day

Boxes as reward for our ranking mode. ヾ(☆▽☆)
#indiedev #gamedev #gameart #screenshotsaturday https://t.co/ALF1InmM7K
IOTD | Top Screenshots

The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.


Sign up now

Specular convolution problem.

4: Adsense
  • You cannot reply to this topic
3 replies to this topic

#1 xxxkxxx   Members   

115
Like
0Likes
Like

Posted 21 April 2017 - 07:17 AM

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):

bug.png

In final rendered image looks like that:

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.

bug2.PNG

Appreciate any help, thanks!


Edited by xxxkxxx, 21 April 2017 - 01:19 PM.


#2 Tom Sloper   Moderators   

15848
Like
0Likes
Like

Posted 21 April 2017 - 02:24 PM

locking thread at request of OP (solved)
-- Tom Sloper
Sloperama Productions
Making games fun and getting them done.
www.sloperama.com

Please do not PM me. My email address is easy to find, but note that I do not give private advice.

#3 frob   Moderators   

44018
Like
0Likes
Like

Posted 21 April 2017 - 02:28 PM

(Unlocking so he can post his solution to the problem)


Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I occasionally write about assorted stuff.


#4 xxxkxxx   Members   

115
Like
1Likes
Like

Posted 21 April 2017 - 11:18 PM

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);