-
Notifications
You must be signed in to change notification settings - Fork 67
Bxdf fixes cook torrance #930
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| if (isInfinity) | ||
| return hlsl::promote<spectral_type>(0.0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it needs to be commented and documented why you don't hoist above line 176 (my previous review comment)
| isInfinity = true; | ||
| return bit_cast<scalar_type>(numeric_limits<scalar_type>::infinity); | ||
| } | ||
| isInfinity = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not that easy!
your exp2 will spit out inf waay before a2<Threshold it also depends on NdotH2
so you need to replace isInfinity = false with isInfinity = isinf(retval) after the multiplication by pi and /denom (or you compute nom/denom and check that value is <Max/Pi)
| isInfinity = true; | ||
| return bit_cast<scalar_type>(numeric_limits<scalar_type>::infinity); | ||
| } | ||
| isInfinity = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const scalar_type VdotH = cache.getVdotH(); | ||
| const scalar_type VdotH_etaLdotH = hlsl::mix(VdotH + orientedEta * cache.getLdotH(), | ||
| VdotH / orientedEta + cache.getLdotH(), | ||
| interaction.getPathOrigin() == PathOrigin::PO_SENSOR); | ||
| quant_query.neg_rcp2_refractionDenom = scalar_type(-1.0) / (VdotH_etaLdotH * VdotH_etaLdotH); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why have we got code for this and not using somethign from microfacet_to_light_transform.hlsl ?
| { | ||
| scalar_type D = query.getNdf(); | ||
| scalar_type dg1 = query.getNdf() / (scalar_type(1.0) + query.getLambdaV()); | ||
| isInfinity = D == bit_cast<scalar_type>(numeric_limits<scalar_type>::infinity); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the isInfinity is supposed to be an "early out" , it should even be called isNDFInfinity to make things clear.
You want to know if the NDF is infinite, sicne G2 and G2 can only be in [0,1]
| isInfinity = true; | ||
| return bit_cast<scalar_type>(numeric_limits<scalar_type>::infinity); | ||
| } | ||
| isInfinity = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as beckmann
| isInfinity = true; | ||
| return bit_cast<scalar_type>(numeric_limits<scalar_type>::infinity); | ||
| } | ||
| isInfinity = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as beckmann comment
| const scalar_type VdotH_etaLdotH = cache.getVdotH() + orientedEta * cache.getLdotH(); | ||
| quant_query.neg_rcp2_VdotH_etaLdotH = scalar_type(-1.0) / (VdotH_etaLdotH * VdotH_etaLdotH); | ||
| const scalar_type VdotH = cache.getVdotH(); | ||
| const scalar_type VdotH_etaLdotH = hlsl::mix(VdotH + orientedEta * cache.getLdotH(), | ||
| VdotH / orientedEta + cache.getLdotH(), | ||
| interaction.getPathOrigin() == PathOrigin::PO_SENSOR); | ||
| quant_query.neg_rcp2_refractionDenom = scalar_type(-1.0) / (VdotH_etaLdotH * VdotH_etaLdotH); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, why duplicate code with Beckmann ?
| { | ||
| scalar_type D = query.getNdfwoNumerator(); | ||
| scalar_type dg1_over_2NdotV = query.getNdfwoNumerator() * query.getG1over2NdotV(); | ||
| isInfinity = D == bit_cast<scalar_type>(numeric_limits<scalar_type>::infinity); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you got the right thing this time, but I'd hoist to be right after D and use isinf or <Max for setting the bool
| void addCosine(T cosA, T biasA) | ||
| { | ||
| const bool AltminusB = tmp0 < (-tmp1); | ||
| const float cosSumAB = tmp0 * tmp1 - tmp3 * tmp4; | ||
| const bool ABltminusC = cosSumAB < (-tmp2); | ||
| const bool ABltC = cosSumAB < tmp2; | ||
| // apply triple angle formula | ||
| const float absArccosSumABC = acos<float>(clamp<float>(cosSumAB * tmp2 - (tmp0 * tmp4 + tmp3 * tmp1) * tmp5, -1.f, 1.f)); | ||
| return ((AltminusB ? ABltC : ABltminusC) ? (-absArccosSumABC) : absArccosSumABC) + ((AltminusB || ABltminusC) ? numbers::pi<float> : (-numbers::pi<float>)); | ||
| const T bias = biasA + runningSum.imag(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's biasA ? how does it work ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me recap some assumptions:
- you initialize to an angle thats between 0 and 2pi (you need to handle the case where the initialization is with
sin<0so you get>piwhen querying for the arccos) - each time you add an angle you add a positive angle (so again, handle case where new angle sine is negative)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually you can assume the initial and each added angle is between 0 and pi because a larger angle would mean a concave (not convex) spherical polygon
| } | ||
|
|
||
| float getArccosSumofABC_minus_PI() | ||
| void addCosine(T cosA, T biasA) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where's a addAngle(const complex_t<T>) if I don't want to reconstruct the sine of the angle I'm adding from the cosine?
| static T getArccosSumofABC_minus_PI(T cosA, T cosB, T cosC, T sinA, T sinB, T sinC) | ||
| { | ||
| const bool AltminusB = cosA < (-cosB); | ||
| const T cosSumAB = cosA * cosB - sinA * sinB; | ||
| const bool ABltminusC = cosSumAB < (-cosC); | ||
| const bool ABltC = cosSumAB < cosC; | ||
| // apply triple angle formula | ||
| const T absArccosSumABC = acos<T>(clamp<T>(cosSumAB * cosC - (cosA * sinB + sinA * cosB) * sinC, T(-1.0), T(1.0))); | ||
| return ((AltminusB ? ABltC : ABltminusC) ? (-absArccosSumABC) : absArccosSumABC) + ((AltminusB || ABltminusC) ? numbers::pi<T> : (-numbers::pi<T>)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should disappear and everything that uses it, should just do
accumulator = sincos_accumulator::create(cosA,sinA)
accumulator.addAngle(cosB,sinB);
accumulator.addAngle(cosC,sinC);
accumulator.getSumofArccos();| const T a = cosA; | ||
| const T b = runningSum.real(); | ||
| const bool reverse = abs<T>(min<T>(a, b)) > max<T>(a, b); | ||
| const T c = a * b - sqrt<T>((T(1.0) - a * a) * (T(1.0) - b * b)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I shouldn't need to reconstruct the sine of the angle I've accumulated
| retval.tmp3 = sinA; | ||
| retval.tmp4 = sinB; | ||
| retval.tmp5 = sinC; | ||
| retval.runningSum = complex_t<T>::create(cosA, T(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you're using complex for storage, then you should initialize to cosA,sinA
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what I meant by #899 (comment)
store the wraparound in integer part of sine
Is that a sine is [-1,1] and therefore you can store the wraparound in int(abs(complex.y)) or a similar encoding which retains the info about the fractional part of the sine or a separate uint16_t (if you see its faster despite using more regs- test with spherical triangle and rectangle sampling)
| const vector3_type H = hlsl::mul(interaction.getFromTangentSpace(), localH); | ||
| assert(hlsl::abs(hlsl::length(H) - scalar_type(1.0)) < scalar_type(1e-4)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw assertion for orthonormality of matrix is just checking the dot products between all pairs of rows are 1.0
You could have a general utility function bool dotIsUnity(A,B); then this becomes
// tangent frame orthonormality
assert(dotIsUnity(fromTangent[0],fromTangent[1]));
assert(dotIsUnity(fromTangent[1],fromTangent[2]));
assert(dotIsUnity(fromTangent[2],fromTangent[0]));
// NDF sampling produced a unit length direction
assert(dotIsUnity(localH,localH));you don't want to assert stuff on the output H
Description
Continues #899 , #916 and #919
Testing
TODO list: