Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Husbjörn

Member Since 27 Jan 2014
Offline Last Active Jun 28 2015 03:59 AM

Posts I've Made

In Topic: Inconsistent falloff for light sources

10 May 2015 - 02:26 AM

I think you're guilty of an incorrect characterization of those results as an "issue".

Well yes, although I did expect them to be different, not just for one surface to have close to a zero brightness value while the other is close to one.

However this: 

for a light direction nearly parallel with one of the two surfaces

I must admit to not giving any thought.

Also as you say, the surfaces are at right angles so I guess it does make sense that the difference in light influence should be big now that I think about it.

 

In any case, I think I'm starting to come to grips with this now so I wouldn't say this discussion has been completely in vain (for my sake), albeit based on ignorance. So thanks again for all received input! smile.png


In Topic: Inconsistent falloff for light sources

08 May 2015 - 06:30 PM

@L. Spiro: Oh, I was not aware.
I'm pretty sure I have read somewhere once upon a time that any "unused w component in a 4-component vector should be set to 1" so I just went with that. Well, the more you know so thanks for the explanation :)

Upon inspection it turns out it was indeed set to zero thanks to using the XMLoadFloat3 function. As described above I merely assumed it would set the last element to 1 instead.

 

Don't forget that computer graphics is mostly ... cheating wink.png 

 

Unless you have PBR, HDR, automatic exposure, tonemap and all that jazz (and even then) it comes down to tweaking numbers. 

Haha, good point.

I do believe you're right; I created a similar scene in Unity to compare how their spot lights would look and it turned out that that actually experiences the falloff issue with a significantly brighter surface that is at a straight angle with the light source as well, albeit there's a bit less extreme of a difference than in my case. Therefore I assume this is pretty much to be expected and to be mitigated into an "OK" state through different settings and general light composure.

 

How wide is that room ? 10 units ? 1000 ? 0.0001?

It's 100x100x100 units. My intent was to provide a basic general purpose solution that would work relatively well as-is for a map / scene creation editor such that light settings could be changed but wouldn't have to be manually tuned for each scene. But maybe that will have to be necessary after all, oh well. I'll play around a bit with various coefficients and see if I can find something that looks decent; at least I know there isn't anything fundamentally wrong with the system now!


In Topic: Inconsistent falloff for light sources

07 May 2015 - 04:57 AM

Sorry about the double post above, apparently my editing somehow failed.

 


No. I think what unbird observed is that it the pix appear to be just N dot L diffuse contributions. That would explain the first image, for instance, where the green spotlight falls off faster along the surface near the light, and falls off just slightly on the far wall where N dot L is nearly constant.

Hm I see... while that isn't the case (see line 102 of the second code snippet in my previous post), is that to say that my distance based attenuation value is supposed to be > 1 in places? If so I may have gotten the whole concept wrong.

 

It's not clear to me that the lighting is incorrect.

Perhaps it isn't; it's just that the stark difference between the quads struck me as unrealistic. But maybe this is rather supposed to be worked around using ambient lighting or some such?

 


For the second image, what happens if you place your light source equidistant from the three surfaces?

It looks pretty much "correct" if placed at the same distance from them all. If I just place it equidistant from three such as in a corner and closer to the floor than the ceiling plane, the latter appears brighter than the wall planes do towards their top again.

 


Also, are you using proper gamma correction in your lighting pipeline? If not, it might cause the darker areas to be unrealistically dark.

I was not; I tried to add it in quickly (it makes everything look rather washed out colour-wise so I guess I'll have to figure out more appropriate exponents though); the problem still occurs but it is a bit less noticible as you said.

 


Are CameraPos and IN.wPos float3?

No, they are float4.

CameraPos is a constant updated from the CPU for each frame so its W component is always one.

I did add and use this in place of IN.wPos however:

float3 worldPos = IN.wPos.xyz / IN.wPos.w;

While it does not have any effect on the current output I admit to having overlooked that so thanks for the catch :)


In Topic: Inconsistent falloff for light sources

06 May 2015 - 05:39 PM

Hm, wouldn't having no distance based attenuation just cause the same brightness everywhere (not counting normal reflection influence and edge-of-cone fall off)?

 

Anyway, here's my simple pixel shader:

float4 PS_Minimalistic(vs_out IN) : SV_TARGET {
	// Create tangent space matrix
	float3 n = normalize(IN.normal);
	float3 t = normalize(IN.tangent);
	float3 b = normalize(IN.binormal);
	float3x3 TBN = float3x3 (
		t.x, b.x, n.x, 
		t.y, b.y, n.y, 
		t.z, b.z, n.z
	);

	// Sample normal from normal map...
	float3 normal = NormalMap.Sample(DiffuseSampler, IN.texcoord).xyz * 2 - 1;
	// ... And bring it into world space	
	normal = t * normal.x + b * normal.y + n * normal.z;

	// Sample diffuse and specular maps
	float4 diffuse	= DiffuseMap.Sample(DiffuseSampler, IN.texcoord);
	float  specular = SpecularMap.Sample(DiffuseSampler, IN.texcoord).x;
	float  alpha	= diffuse.w;

	// Determine view direction
	float3 viewDir = normalize(CameraPos - IN.wPos).xyz;

	// Compute light contribution
	sLightContrib lc = ComputeLightContribution(IN.wPos, normal, viewDir);
	diffuse = (lc.diffuse * diffuse) + (lc.specular * specular);

	return float4(diffuse.xyz, alpha);
}

The ComputeLightContribution function is pretty much directly based on the ComputeLighting function from the link in the opening post, however here are the exact functions I'm using:

/**
 * This struct is used as output for the lighting calculation functions which will compute diffuse and
 * specular contributions of single lights.
 * These can then be additively mixed together to yield the final light contribution to a pixel.
 **/
struct sLightContrib {
	float4 diffuse;
	float4 specular;
};

/**
 * Calculates the attenuation at the given distance from a light source using the given
 * attenuation coefficients.
 **/
float CalculateAttenuation(float dist, float constantAtt, float linearAtt, float quadraticAtt) {
	return 1.0 / (constantAtt + linearAtt * dist + quadraticAtt * dist * dist);
}

/**
 * Calculates the diffuse contribution of a light source at the given pixel.
 * @param L		- Light-to-fragment direction vector (given in world space)
 * @param N		- Normal direction of the pixel being rendered in world space
 * @param C		- Light colour
 **/
float4 CalculateDiffuseContrib(float3 L, float3 N, float4 C) {
	float NL = max(0, dot(N, L));
	return C * NL;
}

/**
 * Calculates the specular contribution of a light source at the given pixel.
 * @param V		- Camera-to-fragment direction vector (given in world space)
 * @param L		- Light-to-fragment direction vector (given in world space)
 * @param N		- Normal direction of the pixel being rendered in world space
 * @param C		- Specular light colour
 * @param S		- Specular power
 **/
 float4 CalculateSpecularContrib(float3 V, float3 L, float3 N, float4 C, float S) {
	float3 R	= normalize(reflect(-L, N));
	float  RV	= max(0, dot(R, V));

	return C * pow(RV, S);
 }

/**
 * Computes light contribution for the given point light.
 * @param light 	- The point light instance
 * @param V 		- Camera-to-fragment direction vector (given in world space)
 * @param P 		- The world space position of the fragment being rendered
 * @param N 		- Normal direction of the fragment being rendered in world space
 **/
sLightContrib ComputePointLightContrib(sPointLight light, float3 V, float3 P, float3 N) {
	sLightContrib res;

	// Compute distance and a direction vector between the currently rendered pixel's world position (P) and the light's position
	float3 L    = light.wPos - P;
	float  dist = length(L);
	L /= dist;

	// Compute attenuation
	float att = saturate(CalculateAttenuation(dist, light.attCoef.x, light.attCoef.y, light.attCoef.z)) * light.intensity;

	// Compute diffuse and specular contributions of this light source
	res.diffuse	= CalculateDiffuseContrib(L, N, light.colour) * att;
	res.specular	= CalculateSpecularContrib(V, L, N, light.colour, 20.0) * att;		// TODO: Allow changing the specular component later on, probably through another argument to this function
	return res;
}

/**
 * Calculates the light intensity contribution for a spot light with the given light direction vector, direction and cone angle.
 * @param L		- The light-to-fragment direction vector in world space
 * @param dir		- The direction of the light source in world space
 * @param angle		- The half-cone angle of the spot light
 **/
float CalculateSpotConeIntensity(float3 L, float3 dir, float angle) {
	float minCos = cos(angle);
	float maxCos = (minCos + 1.0) / 2.0;
	float cosAng = dot(dir, -L);

	return smoothstep(minCos, maxCos, cosAng);
}

/**
 * Computes light contribution for the given spot light.
 * @param light 	- The spot light instance
 * @param V 		- Camera-to-fragment direction vector (given in world space)
 * @param P 		- The world space position of the fragment being rendered
 * @param N 		- Normal direction of the fragment being rendered in world space
 **/
sLightContrib ComputeSpotLightContrib(sSpotLight light, float3 V, float3 P, float3 N) {
	sLightContrib res;

	// Compute distance and a direction vector between the currently rendered fragment's world position (P) and the light's position
	float3 L    = light.wPos - P;
	float  dist = length(L);
	L = L / dist;

	// Compute attenuation
	float attenuation	= CalculateAttenuation(dist, light.attCoef.x, light.attCoef.y, light.attCoef.z);
	float intensity		= CalculateSpotConeIntensity(L, light.direction, light.coneAngle);

	res.diffuse		= CalculateDiffuseContrib(L, N, light.colour) * intensity * attenuation;
	res.specular	        = CalculateSpecularContrib(V, L, N, light.colour, 20.0) * intensity * attenuation;

	return res;
}

/**
 * Computes the combined lighting contribution for all light sources at the given fragment.
 * @param P			- The position in world space of the fragment being rendered
 * @param N			- The normal in world space of the fragment surface
 * @param V			- The camera view direction
 **/
sLightContrib ComputeLightContribution(float4 P, float3 N, float3 V) {
	sLightContrib total = { {0, 0, 0, 0}, {0, 0, 0, 0} };
	uint n;

	/* Process spot lights */
	for(n = 0; n < NumSpotLights; n++) {
		sLightContrib contrib = ComputeSpotLightContrib(SpotLight[n], V, P.xyz, N);
		total.diffuse  += contrib.diffuse;
		total.specular += contrib.specular;
	}

	/* Process point lights */
	for(n = 0; n < NumPointLights; n++) {
		sLightContrib contrib = { {0, 0, 0, 0}, {0, 0, 0, 0} };
		// TODO: Can check if the light source is marked as being hidden / excluded and issue a «continue» statement if so here later
		contrib = ComputePointLightContrib(PointLight[n], V, P.xyz, N);

		total.diffuse  += contrib.diffuse;
		total.specular += contrib.specular;
	}

	total.diffuse  = float4(AmbientLight.xyz, 1) + total.diffuse;
	total.specular = total.specular;
	return total;
}

Edit: fixed incorrect spacings in the code snippets.


In Topic: Inconsistent falloff for light sources

06 May 2015 - 05:35 PM

Removed due to accidental double posting.

PARTNERS