1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
/*! \brief utility library containing sampling functions */
// convention is to return the sample (Vec3f) generated from given Vec2f 's'ample as last parameter
// sampling functions often come in pairs: sample and pdf (needed later for MIS)
// good reference is "Total Compendium" by Philip Dutre http://people.cs.kuleuven.be/~philip.dutre/GI/
#include "../math/vec.isph"
#include "../math/linearspace.isph"
struct Sample3f
{
Vec3f v;
float pdf;
};
inline uniform Sample3f make_Sample3f(const uniform Vec3f& v, const uniform float pdf) {
uniform Sample3f s; s.v = v; s.pdf = pdf; return s;
}
#if defined(ISPC)
inline Sample3f make_Sample3f(const Vec3f& v, const float pdf) {
Sample3f s; s.v = v; s.pdf = pdf; return s;
}
#endif
inline Vec3f cartesian(const float phi, const float sinTheta, const float cosTheta)
{
const float sinPhi = sinf(phi);
const float cosPhi = cosf(phi);
//sincos(phi, &sinPhi, &cosPhi);
return make_Vec3f(cosPhi * sinTheta,
sinPhi * sinTheta,
cosTheta);
}
inline Vec3f cartesian(const float phi, const float cosTheta)
{
return cartesian(phi, cos2sin(cosTheta), cosTheta);
}
/// cosine-weighted sampling of hemisphere oriented along the +z-axis
////////////////////////////////////////////////////////////////////////////////
inline Vec3f cosineSampleHemisphere(const Vec2f s)
{
const float phi = 2.0f * M_PI * s.x;
const float cosTheta = sqrt(s.y);
const float sinTheta = sqrt(1.0f - s.y);
return cartesian(phi, sinTheta, cosTheta);
}
inline float cosineSampleHemispherePDF(const Vec3f &dir)
{
return dir.z / M_PI;
}
inline float cosineSampleHemispherePDF(float cosTheta)
{
return cosTheta / M_PI;
}
/*! Cosine weighted hemisphere sampling. Up direction is provided as argument. */
inline Sample3f cosineSampleHemisphere(const float u, const float v, const Vec3f& N)
{
Vec3f localDir = cosineSampleHemisphere(make_Vec2f(u,v));
Sample3f s;
s.v = frame(N) * localDir;
s.pdf = cosineSampleHemispherePDF(localDir);
return s;
}
/// power cosine-weighted sampling of hemisphere oriented along the +z-axis
////////////////////////////////////////////////////////////////////////////////
inline Vec3f powerCosineSampleHemisphere(const float n, const Vec2f &s)
{
const float phi = two_pi * s.x;
const float cosTheta = pow(s.y, 1.0f / (n + 1.0f));
return cartesian(phi, cosTheta);
}
inline float powerCosineSampleHemispherePDF(const float cosTheta, const float n) // TODO: order of arguments
{
return (n + 1.0f) * (0.5f / M_PI) * pow(cosTheta, n);
}
inline float powerCosineSampleHemispherePDF(const Vec3f& dir, const float n) // TODO: order of arguments
{
return (n + 1.0f) * (0.5f / M_PI) * pow(dir.z, n);
}
/// uniform sampling of cone of directions oriented along the +z-axis
////////////////////////////////////////////////////////////////////////////////
inline Vec3f uniformSampleCone(const float cosAngle, const Vec2f &s)
{
const float phi = two_pi * s.x;
const float cosTheta = 1.0f - s.y * (1.0f - cosAngle);
return cartesian(phi, cosTheta);
}
inline float uniformSampleConePDF(const float cosAngle)
{
return rcp(two_pi*(1.0f - cosAngle));
}
inline uniform float uniformSampleConePDF(const uniform float cosAngle)
{
return rcp(two_pi*(1.0f - cosAngle));
}
/// uniform sampling of disk
////////////////////////////////////////////////////////////////////////////////
inline Vec3f uniformSampleDisk(const float radius, const Vec2f &s)
{
const float r = sqrtf(s.x) * radius;
const float phi = two_pi * s.y;
const float sinPhi = sinf(phi);
const float cosPhi = cosf(phi);
//sincos(phi, &sinPhi, &cosPhi);
return make_Vec3f(r * cosPhi, r * sinPhi, 0.f);
}
inline float uniformSampleDiskPDF(const float radius)
{
return rcp(M_PI * sqr(radius));
}
inline uniform float uniformSampleDiskPDF(const uniform float radius)
{
return rcp(M_PI * sqr(radius));
}
/// uniform sampling of triangle abc
////////////////////////////////////////////////////////////////////////////////
inline Vec3f uniformSampleTriangle(const Vec3f &a, const Vec3f &b, const Vec3f &c, const Vec2f &s)
{
const float su = sqrtf(s.x);
return c + (1.0f - su) * (a-c) + (s.y*su) * (b-c);
}
inline float uniformSampleTrianglePDF(const Vec3f &a, const Vec3f &b, const Vec3f &c)
{
return 2.0f * rcp(abs(length(cross(a-c, b-c))));
}
|