Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Program that provides empirical evidence that the clamped cosine lobes 0.5cos^2 and (5/6)cos^4 form a partition of unity over the unit sphere. This is related to the ambient dice paper: http://www.ppsloan.org/publications/AmbientDice.pdf
#include <stdio.h>
#include <math.h>
float max(float x, float y) {
return x > y ? x : y;
}
class vec3 {
public:
float x;
float y;
float z;
vec3(const float x_, const float y_, const float z_):
x(x_),
y(y_),
z(z_){
}
vec3() {
x = 0.0f;
y = 0.0f;
z = 0.0f;
}
friend vec3 operator*(const float s, const vec3& a) {
return vec3(s * a.x, s * a.y, s * a.z);
}
static float dot(const vec3& a, const vec3& b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
};
const float PI = 3.14;
const float EPSILON = 1e-5f;
const float THETA_SPACING = 0.01f;
const float PHI_SPACING = 0.01f;
const float BIG_PHI = 0.618034f;
const float RCP_ICO_LEN = 1.0 / sqrt(1 + BIG_PHI * BIG_PHI);
// these are all the vertex groups from the ambient dice paper.
// they are all the vertices on the icosahedron defined in the paper.
// and the vectors are all normalized, by multiplying by RCP_ICO_LEN
const int N_ICO_VERTICES = 12;
vec3 ico_vertices[N_ICO_VERTICES] = {
// Group A.
RCP_ICO_LEN * vec3(+1.0f, +BIG_PHI, +0.0f),
RCP_ICO_LEN * vec3(+1.0f, -BIG_PHI, +0.0f),
RCP_ICO_LEN * vec3(-1.0f, +BIG_PHI, +0.0f),
RCP_ICO_LEN * vec3(-1.0f, -BIG_PHI, +0.0f),
// Group B
RCP_ICO_LEN * vec3(0.0f, +1.0, +BIG_PHI),
RCP_ICO_LEN * vec3(0.0f, +1.0, -BIG_PHI),
RCP_ICO_LEN * vec3(0.0f, -1.0, +BIG_PHI),
RCP_ICO_LEN * vec3(0.0f, -1.0, -BIG_PHI),
// Group C
RCP_ICO_LEN * vec3(+BIG_PHI, 0.0f, +1.0f),
RCP_ICO_LEN * vec3(+BIG_PHI, 0.0f, -1.0f),
RCP_ICO_LEN * vec3(-BIG_PHI, 0.0f, +1.0f),
RCP_ICO_LEN * vec3(-BIG_PHI, 0.0f, -1.0f),
};
int main() {
// we sample a whole bunch of units vectors on the unit sphere.
for(float theta = 0.0f; theta <= +2.0 * PI; theta += THETA_SPACING) {
for(float phi = 0.0f; phi <= +PI; phi += PHI_SPACING) {
const vec3 sample_v(sin(theta) * cos(phi), sin(theta) * sin(phi),cos(theta));
float sum = 0.0f;
/*
Every vertex on the icosahedron will define a clamped
squared cosine lobe: cos^2.
These lobes form a partition of unity over the unit sphere, the paper claims.
If we project some unit vector on all the lobes, then the sums of all those
projections should be 1, if the partition of unity property is true.
And if we compute this sum for many, many vertices on the unit sphere,
and this sum is always 1, then we know with great certainty that the lobes form
a partiton of unity.
*/
for(int iv = 0; iv < N_ICO_VERTICES; ++iv) {
const vec3 ico_v = ico_vertices[iv];
const float cos_theta = max(0.0f, vec3::dot(ico_v, sample_v));
const float cos_theta2 = cos_theta * cos_theta;
sum += 0.5f * cos_theta2;
}
if(fabs(sum - 1.0) > EPSILON) {
// negative result. it is not a partition of unity.
printf("0.5cos^2 IS NOT a partition of unity!\n");
printf("test failed for sample %f %f %f!\n", sample_v.x, sample_v.y, sample_v.z);
printf("sum was %f instead of 1.0!\n", sum);
return 1;
}
}
}
printf("0.5cos^2 IS a partition of unity!\n");
// now let's also check for (5/6)cos^4
for(float theta = 0.0f; theta <= +2.0 * PI; theta += THETA_SPACING) {
for(float phi = 0.0f; phi <= +PI; phi += PHI_SPACING) {
const vec3 sample_v(sin(theta) * cos(phi), sin(theta) * sin(phi),cos(theta));
float sum = 0.0f;
for(int iv = 0; iv < N_ICO_VERTICES; ++iv) {
const vec3 ico_v = ico_vertices[iv];
const float cos_theta = max(0.0f, vec3::dot(ico_v, sample_v));
const float cos_theta4 = cos_theta * cos_theta * cos_theta * cos_theta;
sum += (5.0f / 6.0f) * cos_theta4;
}
if(fabs(sum - 1.0) > EPSILON) {
// negative result. it is not partition of unity.
printf("(5.0/6.0)cos^4 IS NOT a partition of unity!\n");
printf("test failed for sample %f %f %f!\n", sample_v.x, sample_v.y, sample_v.z);
printf("sum was %f instead of 1.0!\n", sum);
return 1;
}
}
}
printf("(5.0/6.0)cos^4 IS a partition of unity!\n");
}
@dodoleon

This comment has been minimized.

Copy link

@dodoleon dodoleon commented Apr 22, 2018

hello, I am reading the ambient dice paper, but dont know how to use partition of unity, and don't know how to use ambient dice to integral diffuse effect. Could you give me some formula to help me understand these questions, Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment