Jump to content

  • Log In with Google      Sign In   
  • Create Account

L. Spiro

Member Since 29 Oct 2003
Online Last Active Today, 05:00 AM

Topics I've Started

Conservation Factor for Ashikhmin-Shirley

24 November 2014 - 02:37 AM

This is basically a call for anyone more mathematically literate than myself to verify my results.
I want my shader system to be designed such that it is easy to mix-and-match various specular models and diffuse models while retaining proper conservation between specular and diffuse.
 
The way I have set it up is so that the specular function returns a factor by which to multiply the diffuse in order to enforce conservation.
So if you look at tri-Ace’s research papers on physically plausible Blinn-Phong, you see that they include a second Fresnel factor (using L·N) in the diffuse component.  Since that factor is designed to ensure energy conservation, I actually don’t want to make it part of the diffuse model, but rather the diffuse multiplier returned by the specular model, because that is basically saying how much is left over for diffuse after specular is determined.
 
In other words, I don’t want to do this:
void BlinnPhongDir( in DEF_LIGHT_ARGS _dlaArgs, inout vec4 _vDiffuse, inout vec4 _vSpecular ) {
	// Diffuse normalization (division by PI) done once outside of the BRDF's.
	vec4 vDiffuse;
	vec4 vSpecular;

	// *********************
	// SPECULAR
	// *********************
	float fS = 0.0397436 * _dlaArgs.fShininess + 0.0856832;
	
	float fSpec = SchlickFresnel( _dlaArgs.fSpecReflectance, _dlaArgs.fVdotH ) * pow( _dlaArgs.fNdotH, _dlaArgs.fShininess );
	fSpec /= max( _dlaArgs.fLdotN, _dlaArgs.fVdotN );
	vSpecular = max( fSpec * fS, 0.0 ) * _dlaArgs.vLightDiffuse * _dlaArgs.fLdotN;


	// *********************
	// DIFFUSE
	// *********************	
	float fD = saturate( (1.0 - SchlickFresnel( _dlaArgs.fSpecReflectance, _dlaArgs.fLdotN )) );
	vDiffuse = _dlaArgs.fLdotN * fD * _dlaArgs.vLightDiffuse;
	
	_vDiffuse += vDiffuse;
	_vSpecular += vSpecular;
}
I want to keep them separated this way so that they can be interchanged with other specular/diffuse models:
float BlinnPhongSpecular( in DEF_LIGHT_ARGS _dlaArgs, out vec4 _vSpecular ) {
	float fS = 0.0397436 * _dlaArgs.fShininess + 0.0856832;
	
	float fSpec = SchlickFresnel( _dlaArgs.fSpecReflectance, _dlaArgs.fVdotH ) * pow( _dlaArgs.fNdotH, _dlaArgs.fShininess );
	fSpec /= max( _dlaArgs.fLdotN, _dlaArgs.fVdotN );
	_vSpecular = max( fSpec * fS, 0.0 ) * _dlaArgs.vLightDiffuse * _dlaArgs.fLdotN;
	
	float fD = saturate( (1.0 - SchlickFresnel( _dlaArgs.fSpecReflectance, _dlaArgs.fLdotN )) );
	//float fD = 1.0 - _dlaArgs.fSpecReflectance;
	return fD;
}

void BlinnPhongDiffuse( in DEF_LIGHT_ARGS _dlaArgs, out vec4 _vDiffuse ) {
	LambertDiffuse( _dlaArgs, _vDiffuse );
	//BurleyDiffuse( _dlaArgs, _vDiffuse );
}

void BlinnPhongDir( in DEF_LIGHT_ARGS _dlaArgs, inout vec4 _vDiffuse, inout vec4 _vSpecular ) {
	// Diffuse normalization (division by PI) done once outside of the BRDF's.
	vec4 vDiffuse;
	vec4 vSpecular;
	float fDFactor = BlinnPhongSpecular( _dlaArgs, vSpecular );
	BlinnPhongDiffuse( _dlaArgs, vDiffuse );
	vDiffuse *= fDFactor; // DIFFUSE REDUCED BY AMOUNT LOST TO SPECULAR HERE.
	
	_vDiffuse += vDiffuse;
	_vSpecular += vSpecular;
}
This way I can do this:
// *********************
// Oren-Nayar/Blinn-Phong.
// *********************
void OrenNayarBlinnPhongDir( in DEF_LIGHT_ARGS _dlaArgs, inout vec4 _vDiffuse, inout vec4 _vSpecular ) {
	// Diffuse normalization (division by PI) done once outside of the BRDF's.
	vec4 vDiffuse;
	vec4 vSpecular;
	float fDFactor = BlinnPhongSpecular( _dlaArgs, vSpecular );
	OrenNayarDiffuse( _dlaArgs, vDiffuse );
	vDiffuse *= fDFactor; // DIFFUSE REDUCED BY AMOUNT LOST TO SPECULAR HERE.

	_vDiffuse += vDiffuse;
	_vSpecular += vSpecular;
}
I want to apply this also to Ashikhmin-Shirley.
Here is how it would be if you separated the specular and diffuse in the “typical” way:
void AshikhminShirleySpecular( inout DEF_LIGHT_ARGS _dlaArgs, out vec4 _vSpecular ) {
	const vec3 vEpsilon = vec3( 1.0, 0.0, 0.0 );
	vec3 vTangent = normalize( cross( _dlaArgs.vNormal, vEpsilon ) );
    vec3 vBiTangent = normalize( cross( _dlaArgs.vNormal, vTangent ) );
	float HdotX = dot( _dlaArgs.vLightHalfVector, vTangent );
    float HdotY = dot( _dlaArgs.vLightHalfVector, vBiTangent );
	
	// _dlaArgs.vAshikFactors.w = Rs.
	float fF = SchlickFresnel( _dlaArgs.vAshikFactors.w, _dlaArgs.fVdotH );
	// _dlaArgs.vAshikFactors.y = sqrt((Nu+1)*(Nv+1)).
	float fNormS = _dlaArgs.vAshikFactors.y * (1.0 / (8.0 * PI));
	float fN = (_dlaArgs.vAshikFactors.x * Sqr( HdotX ) + _dlaArgs.vAshikFactors.y * Sqr( HdotY )) / (1.0 - Sqr( _dlaArgs.fNdotH ));
	float fDenom = max( (_dlaArgs.fVdotH * max( _dlaArgs.fVdotN, _dlaArgs.fLdotN )), LSE_EPSILON );
	float fFinal = max( fNormS * fF * pow( _dlaArgs.fNdotH, fN ) / fDenom, 0.0 );
	
	_vSpecular = (fFinal * _dlaArgs.fLdotN) * _dlaArgs.vLightDiffuse;
}

void AshikhminShirleyDiffuse( in DEF_LIGHT_ARGS _dlaArgs, out vec4 _vDiffuse ) {
	float fFactorV = 1.0 - Pow5( 1.0 - _dlaArgs.fVdotN * 0.5 );
	float fFactorL = (1.0 - Pow5( 1.0 - _dlaArgs.fLdotN * 0.5 ));
	// (23.0 * PI) changed to just 23.0 because diffuse is divided by PI later.
	_vDiffuse = (1.0 - _dlaArgs.vAshikFactors.w) * (28.0 / 23.0) * (fFactorV * fFactorL) * _dlaArgs.fLdotN * _dlaArgs.vLightDiffuse;
}
This is how the specular and diffuse terms are isolated in the papers.

For my purposes I need to extract the part of the diffuse that is actually meant to conserve energy from the specular, and this is my result:
float AshikhminShirleySpecular( inout DEF_LIGHT_ARGS _dlaArgs, out vec4 _vSpecular ) {
	const vec3 vEpsilon = vec3( 1.0, 0.0, 0.0 );
	vec3 vTangent = normalize( cross( _dlaArgs.vNormal, vEpsilon ) );
    vec3 vBiTangent = normalize( cross( _dlaArgs.vNormal, vTangent ) );
	float HdotX = dot( _dlaArgs.vLightHalfVector, vTangent );
    float HdotY = dot( _dlaArgs.vLightHalfVector, vBiTangent );
	
	// _dlaArgs.vAshikFactors.w = Rs.
	float fF = SchlickFresnel( _dlaArgs.vAshikFactors.w, _dlaArgs.fVdotH );
	// _dlaArgs.vAshikFactors.y = sqrt((Nu+1)*(Nv+1)).
	float fNormS = _dlaArgs.vAshikFactors.y * (1.0 / (8.0 * PI));
	float fN = (_dlaArgs.vAshikFactors.x * Sqr( HdotX ) + _dlaArgs.vAshikFactors.y * Sqr( HdotY )) / (1.0 - Sqr( _dlaArgs.fNdotH ));
	float fDenom = max( (_dlaArgs.fVdotH * max( _dlaArgs.fVdotN, _dlaArgs.fLdotN )), LSE_EPSILON );
	float fFinal = max( fNormS * fF * pow( _dlaArgs.fNdotH, fN ) / fDenom, 0.0 );
	
	_vSpecular = (fFinal * _dlaArgs.fLdotN) * _dlaArgs.vLightDiffuse;
	
	// According to the paper, (28.0 / (23.0 * PI)) is a magic number designed to ensure energy conservation.
	return (1.0 - _dlaArgs.vAshikFactors.w) *		// Constant ratio of specular to diffuse.
		(28.0 / 23.0) *					// (23.0 * PI) changed to just 23.0 because diffuse is divided by PI later.
		(1.0 - Pow5( 1.0 - _dlaArgs.fLdotN * 0.5 ));	// Light lost from diffuse by increased specular at glancing angles.
}

void AshikhminShirleyDiffuse( in DEF_LIGHT_ARGS _dlaArgs, out vec4 _vDiffuse ) {
	float fFactorV = 1.0 - Pow5( 1.0 - _dlaArgs.fVdotN * 0.5 );
	_vDiffuse = (fFactorV * _dlaArgs.fLdotN) * _dlaArgs.vLightDiffuse;
}

void AshikhminShirleyDir( in DEF_LIGHT_ARGS _dlaArgs, inout vec4 _vDiffuse, inout vec4 _vSpecular ) {
	// Diffuse normalization (division by PI) done once outside of the BRDF's.
	vec4 vDiffuse;
	vec4 vSpecular;
	float fDFactor = AshikhminShirleySpecular( _dlaArgs, vSpecular );
	AshikhminShirleyDiffuse( _dlaArgs, vDiffuse );
	vDiffuse *= fDFactor; // DIFFUSE REDUCED BY AMOUNT LOST TO SPECULAR HERE.
	
	_vDiffuse += vDiffuse;
	_vSpecular += vSpecular;
}
Can anyone verify this is correct?
28.0 / 23.0 is a magic number I don’t know how was obtained, but the paper says it is for conservation so I put it in my conservation part.
1.0 - _dlaArgs.vAshikFactors.w (1 - Rs) I know is part of the exchange between specular and diffuse.
1.0 - Pow5( 1.0 - _dlaArgs.fLdotN * 0.5 ) I moved to the conservation area because it appears to be the part that compensates for increasing specular at glancing angles.
 
The remaining part I left in the diffuse term because having diffuse decrease at glancing angles to the viewer is a property that specifically Ashikhmin-Shirley diffuse wants.  It’s not related to conserving energy with specular.
 
The basic question I would like anyone better at math than myself to answer is, if I want to mix Ashikhmin-Shirley specular with Oren-Nayar diffuse while retaining energy conservation (as I did with Blinn-Phong/Oren-Nayar), is this correct?
 
 
L. Spiro

Conservation Factor for Epic’s Shading Model

23 November 2014 - 11:44 AM

What is the conservation factor between the specular and diffuse in Epic’s shading model?
Both they and Disney are ignoring it.
Since it uses typical Fresnel, I am assuming it is:
saturate( (1.0 - SchlickFresnel( _dlaArgs.fSpecReflectance, _dlaArgs.fLdotN )) )
 
My code is:
// _fCosThetaH = N*H.
// _fW = Roughness^2.
float TrowbridgeReitzD( float _fCosThetaH, float _fW ) {
	float fA2 = Sqr( _fW );
	return fA2 / (PI * Sqr( Sqr( _fCosThetaH ) * (fA2 - 1.0) + 1.0 ));
}

float SmithG1_GGX( float _fVdotN, float _fAlphaG ) {
	return _fVdotN / (_fVdotN * (1.0 - _fAlphaG) + _fAlphaG);
}

// _fAlphaG = Roughness.
float SmithG_GGX( float _fLdotN, float _fVdotN, float _fAlphaG ) {
	float fK = Sqr( _fAlphaG + 1.0 ) * (1.0 / 8.0);
	return SmithG1_GGX( _fLdotN, fK ) * SmithG1_GGX( _fVdotN, fK );
}

float SchlickFresnel_SG( float _F0, float _fU ) {
	return _F0 + (1.0 - _F0) * exp2( (_fU * -5.55473 - 6.98316) * _fU );
}

float EpicShadingSpecular( in DEF_LIGHT_ARGS _dlaArgs, out vec4 _vSpecular ) {
	float fD = TrowbridgeReitzD( _dlaArgs.fNdotH, _dlaArgs.fRoughness * _dlaArgs.fRoughness );
	float fG = SmithG_GGX( _dlaArgs.fLdotN, _dlaArgs.fVdotN, _dlaArgs.fRoughness );
	float fF = SchlickFresnel_SG( _dlaArgs.fSpecReflectance, _dlaArgs.fVdotH );

	float fS = fD * fG * fF;
	_vSpecular = _dlaArgs.fLdotN * fS * _dlaArgs.vLightDiffuse;

	// Returns the specular/diffuse conservation factor.
	return saturate( (1.0 - SchlickFresnel_SG( _dlaArgs.fSpecReflectance, _dlaArgs.fLdotN )) );
}

Is it correct to use just the Fresnel (from the light’s point of view, hence L•N, not V•N) or should it include the distribution/geometric terms as well? I tend to think these are typically ignored for performance, but for the moment I am more interested in accuracy.


L. Spiro

Science Lesson: Facts, Theories, Hypotheses, and Postulations

10 November 2014 - 02:22 AM

Due to the nature of another book I am writing, this time of a more scientific nature, I have been discussing science more and more often with people, and have been absolutely astounded as to how many people misunderstand the scientific method and the terminology associated with it.
 
So here is a pop-quiz for you to see if you yourself are completely free of any misunderstanding surrounding theories, facts, laws, hypotheses, etc.
 
 
Check all that apply.
Gravity is:

  • A fact.
  • A theory.
  • A law.
  • A hypothesis.

Many of you will be saying, “I see the catch.  I know the difference between a fact and a theory.  Easy question.”
But that isn’t the catch.
 
Let’s cover the basics.
 
 
The scientific method begins with empirical observation.  You observe something and then ask (postulate), “How does that work?”.
Then you make a best guess based on whatever information you can gather (a hypothesis) and test it.  You observe the results and compare/contrast them with the observed phenomena.  After many tests and perhaps many revisions to the hypothesis, a conclusion might be drawn and a scientific theory formed.
A scientific theory is never considered a fact within the scientific community—it simply best-explains the observed phenomena but could later be proven false.
 
 
Most likely all of you knew that, right?  No one here mistakes a theory for fact, right?  So the answer must be #2, right?
 
 
But I said that wasn’t the catch.  The astute reader may have noticed that we haven’t discussed laws yet.

A scientific law is a statement based on repeated experimental observations that describes some aspects of the universe. A scientific law always applies under the same conditions, and implies that there is a causal relationship involving its elements.

http://en.wikipedia.org/wiki/Scientific_law
In other words, a scientific law provides a prediction of “what will happen under these circumstances”.
Generally speak, the law of gravity suggests that if you let go of a standard ball from the roof of a building, it will fall towards the earth.  For the sake of brevity we are not going to explain that the building does not reach into space, nothing is attached to the ball to make it float, etc.  Just keep it simple.
 
 
So is the answer #3?  Or is it #2 and #3?
 
 
If you think it is either of these suggestions, you are not paying close-enough attention.  Consider the implications if the answer is “#2 and #3” or “#2”.  If the theory (#2) changes, does that change how we are attracted to the earth or how the moon orbits Earth?
 
At the very beginning of the explanation of the scientific method I mentioned very important key words: Empirical observation.
When you make an observation, the thing you are observing does exist, or the phenomena you are observing is actually happening (not delving into discussions related to trusting your senses etc.—that is for another day).
In other words, you might say that thing factually exists, or that phenomena factually occurs.
 
 
The correct answer is “#1, #2, and #3”.  All theories originate from empirically observed phenomena, which by definition themselves must actually exist—a non-factual phenomena can’t be factually observed; it exists within the realm of imagination and in that case can at-best be only a theorem (if anything).
The reason people get confused is because theories and laws have the same name as their observed phenomenon.  To make the distinctions clearer, I have color-coded facts, theories, and laws below.
 
 
Laws, theories, and facts are not mutually exclusive—that is the catch.  Gravity is a fact that we observe.  Because of its predictable behavior we also made the Law of Gravity, which doesn’t explain anything about how gravity works, but predicts that a ball dropped from a building will fall, and equations can even determine how fast it will fall.  The Theory of Gravity attempts to explain how gravity works.  The key point here is that theories provide explanatory purposes.
 
 
To deny that gravity is a fact is to deny that the moon orbits Earth and the earth orbits the sun.
Gravity is an observable fact, with an associated theory (gravitational theory) which tries to explain why bodies of mass attract (and indeed there have been many attempts to explain how gravity (the attraction of 2 bodies of mass, regardless of how that attraction takes place) works).

And while working on the theory, the nature of gravity is predictable enough that there is also the law of gravity, which explains what happens between 2 bodies of mass in regards to attraction.

 

 

Appendix:

Scientific Theoryhttp://en.wikipedia.org/wiki/Scientific_theory

“A scientific theory is a well-substantiated explanation of some aspect of the natural world that is acquired through the scientific method and repeatedly tested and confirmed through observation and experimentation.”

 

Scientific Methodhttp://en.wikipedia.org/wiki/Scientific_method

“The scientific method is a body of techniques for investigating phenomena, acquiring new knowledge, or correcting and integrating previous knowledge. To be termed scientific, a method of inquiry must be based on empirical and measurable evidence subject to specific principles of reasoning.”

- Evidence must factually exist or factually occur to be empirically observed or measured.

 

Scientific Lawhttp://en.wikipedia.org/wiki/Scientific_law

“A scientific law is a statement based on repeated experimental observations that describes some aspects of the universe. A scientific law always applies under the same conditions, and implies that there is a causal relationship involving its elements.”

 

 

 

I hope this has been useful.  Surprisingly many people are confused by the fact that events/phenomena, theories, and laws all have the same name, and it makes it hard to make the distinction between them.  If you say gravity is a fact, you will likely get a reply along the lines of, “No, it’s just a theory,” followed by an explanation of the differences between facts and scientific theories and how a theory is never considered a fact.

This is true, but the person replying has misunderstood the founding principles of the scientific method—all theories begin as factually observed phenomenon.  In other words, you could say, all theories are facts before they are theories—scientific theories can’t exist unless there is something already there to explain.

 

Now you can explain to anyone the real difference between facts and theories.

 

 

L. Spiro


MIT License in PlayStation Vita Game

09 July 2014 - 03:43 PM

The language of the MIT license isn’t the clearest in the world: http://opensource.org/licenses/mit-license.php
 

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.


At first I thought this meant that I just had to keep the copyright notice inside the source files, but apparently it means I have to include their notice somewhere as a separate file along with my game(s).

But our game is for PlayStation Vita, so that is obviously impossible.
It is also impossible to show their MIT copyright text inside the game anywhere.

Do I simply have to not use the MIT-licensed code or are there other options etc.?


L. Spiro

My Kingdom for a Link to a Past Post

24 June 2014 - 09:40 PM

Search-after-search I can’t find a past post I really need right now.

 

A long time ago someone did some tests on the best ways to update vertex buffers and he shared his results, but when I try the few key words I remember (which I won’t list here in order not to pass on a possibly mistaken key word to others) I just get results of people asking questions.  I even searched replies for a link to the post for which I am searching and nothing.

 

So the guy benchmarked at least 3 ways to update vertex buffers.

He did client arrays and VBO’s with DYNAMIC_DRAW and different updating strategies.

One of the strategies was orphaning.

It was about 2 years ago.

 

My kingdom for anyone who can find that post.  It may have been OpenGL ES 2.0.

 

 

L. Spiro


PARTNERS