use of org.sunflow.math.OrthoNormalBasis in project joons-renderer by joonhyublee.
the class InstantGI method getIrradiance.
@Override
public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
float b = (float) Math.PI * c / diffuseReflectance.getMax();
Color irr = Color.black();
Point3 p = state.getPoint();
Vector3 n = state.getNormal();
int set = (int) (state.getRandom(0, 1, 1) * numSets);
for (PointLight vpl : virtualLights[set]) {
Ray r = new Ray(p, vpl.p);
float dotNlD = -(r.dx * vpl.n.x + r.dy * vpl.n.y + r.dz * vpl.n.z);
float dotND = r.dx * n.x + r.dy * n.y + r.dz * n.z;
if (dotNlD > 0 && dotND > 0) {
float r2 = r.getMax() * r.getMax();
Color opacity = state.traceShadow(r);
Color power = Color.blend(vpl.power, Color.BLACK, opacity);
float g = (dotND * dotNlD) / r2;
irr.madd(0.25f * Math.min(g, b), power);
}
}
// bias compensation
int nb = (state.getDiffuseDepth() == 0 || numBias <= 0) ? numBias : 1;
if (nb <= 0) {
return irr;
}
OrthoNormalBasis onb = state.getBasis();
Vector3 w = new Vector3();
float scale = (float) Math.PI / nb;
for (int i = 0; i < nb; i++) {
float xi = (float) state.getRandom(i, 0, nb);
float xj = (float) state.getRandom(i, 1, nb);
float phi = (float) (xi * 2 * Math.PI);
float cosPhi = (float) Math.cos(phi);
float sinPhi = (float) Math.sin(phi);
float sinTheta = (float) Math.sqrt(xj);
float cosTheta = (float) Math.sqrt(1.0f - xj);
w.x = cosPhi * sinTheta;
w.y = sinPhi * sinTheta;
w.z = cosTheta;
onb.transform(w);
Ray r = new Ray(state.getPoint(), w);
r.setMax((float) Math.sqrt(cosTheta / b));
ShadingState temp = state.traceFinalGather(r, i);
if (temp != null) {
temp.getInstance().prepareShadingState(temp);
if (temp.getShader() != null) {
float dist = temp.getRay().getMax();
float r2 = dist * dist;
float cosThetaY = -Vector3.dot(w, temp.getNormal());
if (cosThetaY > 0) {
float g = (cosTheta * cosThetaY) / r2;
// was this path accounted for yet?
if (g > b) {
irr.madd(scale * (g - b) / g, temp.getShader().getRadiance(temp));
}
}
}
}
}
return irr;
}
use of org.sunflow.math.OrthoNormalBasis in project joons-renderer by joonhyublee.
the class PathTracingGIEngine method getIrradiance.
@Override
public Color getIrradiance(ShadingState state, Color diffuseReflectance) {
if (samples <= 0) {
return Color.BLACK;
}
// compute new sample
Color irr = Color.black();
OrthoNormalBasis onb = state.getBasis();
Vector3 w = new Vector3();
int n = state.getDiffuseDepth() == 0 ? samples : 1;
for (int i = 0; i < n; i++) {
float xi = (float) state.getRandom(i, 0, n);
float xj = (float) state.getRandom(i, 1, n);
float phi = (float) (xi * 2 * Math.PI);
float cosPhi = (float) Math.cos(phi);
float sinPhi = (float) Math.sin(phi);
float sinTheta = (float) Math.sqrt(xj);
float cosTheta = (float) Math.sqrt(1.0f - xj);
w.x = cosPhi * sinTheta;
w.y = sinPhi * sinTheta;
w.z = cosTheta;
onb.transform(w);
ShadingState temp = state.traceFinalGather(new Ray(state.getPoint(), w), i);
if (temp != null) {
temp.getInstance().prepareShadingState(temp);
if (temp.getShader() != null) {
irr.add(temp.getShader().getRadiance(temp));
}
}
}
irr.mul((float) Math.PI / n);
return irr;
}
use of org.sunflow.math.OrthoNormalBasis in project joons-renderer by joonhyublee.
the class SphereLight method getPhoton.
public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) {
float z = (float) (1 - 2 * randX2);
float r = (float) Math.sqrt(Math.max(0, 1 - z * z));
float phi = (float) (2 * Math.PI * randY2);
float x = r * (float) Math.cos(phi);
float y = r * (float) Math.sin(phi);
p.x = center.x + x * radius;
p.y = center.y + y * radius;
p.z = center.z + z * radius;
OrthoNormalBasis basis = OrthoNormalBasis.makeFromW(new Vector3(x, y, z));
phi = (float) (2 * Math.PI * randX1);
float cosPhi = (float) Math.cos(phi);
float sinPhi = (float) Math.sin(phi);
float sinTheta = (float) Math.sqrt(randY1);
float cosTheta = (float) Math.sqrt(1 - randY1);
dir.x = cosPhi * sinTheta;
dir.y = sinPhi * sinTheta;
dir.z = cosTheta;
basis.transform(dir);
power.set(radiance);
power.mul((float) (Math.PI * Math.PI * 4 * r2));
}
use of org.sunflow.math.OrthoNormalBasis in project joons-renderer by joonhyublee.
the class SphereLight method getSamples.
public void getSamples(ShadingState state) {
if (getNumSamples() <= 0) {
return;
}
Vector3 wc = Point3.sub(center, state.getPoint(), new Vector3());
float l2 = wc.lengthSquared();
if (l2 <= r2) {
// inside the sphere?
return;
}
// top of the sphere as viewed from the current shading point
float topX = wc.x + state.getNormal().x * radius;
float topY = wc.y + state.getNormal().y * radius;
float topZ = wc.z + state.getNormal().z * radius;
if (state.getNormal().dot(topX, topY, topZ) <= 0) {
// top of the sphere is below the horizon
return;
}
float cosThetaMax = (float) Math.sqrt(Math.max(0, 1 - r2 / Vector3.dot(wc, wc)));
OrthoNormalBasis basis = OrthoNormalBasis.makeFromW(wc);
int samples = state.getDiffuseDepth() > 0 ? 1 : getNumSamples();
float scale = (float) (2 * Math.PI * (1 - cosThetaMax));
Color c = Color.mul(scale / samples, radiance);
for (int i = 0; i < samples; i++) {
// random offset on unit square
double randX = state.getRandom(i, 0, samples);
double randY = state.getRandom(i, 1, samples);
// cone sampling
double cosTheta = (1 - randX) * cosThetaMax + randX;
double sinTheta = Math.sqrt(1 - cosTheta * cosTheta);
double phi = randY * 2 * Math.PI;
Vector3 dir = new Vector3((float) (Math.cos(phi) * sinTheta), (float) (Math.sin(phi) * sinTheta), (float) cosTheta);
basis.transform(dir);
// check that the direction of the sample is the same as the
// normal
float cosNx = Vector3.dot(dir, state.getNormal());
if (cosNx <= 0) {
continue;
}
float ocx = state.getPoint().x - center.x;
float ocy = state.getPoint().y - center.y;
float ocz = state.getPoint().z - center.z;
float qa = Vector3.dot(dir, dir);
float qb = 2 * ((dir.x * ocx) + (dir.y * ocy) + (dir.z * ocz));
float qc = ((ocx * ocx) + (ocy * ocy) + (ocz * ocz)) - r2;
double[] t = Solvers.solveQuadric(qa, qb, qc);
if (t == null) {
continue;
}
LightSample dest = new LightSample();
// compute shadow ray to the sampled point
dest.setShadowRay(new Ray(state.getPoint(), dir));
// FIXME: arbitrary bias, should handle as in other places
dest.getShadowRay().setMax((float) t[0] - 1e-3f);
// prepare sample
dest.setRadiance(c, c);
dest.traceShadow(state);
state.addSample(dest);
}
}
use of org.sunflow.math.OrthoNormalBasis in project joons-renderer by joonhyublee.
the class ShadingState method occlusion.
/**
* Ambient occlusion routine, returns a value between bright and dark
* depending on the amount of geometric occlusion in the scene.
*
* @param samples number of sample rays
* @param maxDist maximum length of the rays
* @param bright color when nothing is occluded
* @param dark color when fully occluded
* @return occlusion color
*/
public final Color occlusion(int samples, float maxDist, Color bright, Color dark) {
if (n == null) {
// in case we got called on a geometry without orientation
return bright;
}
// make sure we are on the right side of the material
faceforward();
OrthoNormalBasis onb = getBasis();
Vector3 w = new Vector3();
Color result = Color.black();
for (int i = 0; i < samples; i++) {
float xi = (float) getRandom(i, 0, samples);
float xj = (float) getRandom(i, 1, samples);
float phi = (float) (2 * Math.PI * xi);
float cosPhi = (float) Math.cos(phi);
float sinPhi = (float) Math.sin(phi);
float sinTheta = (float) Math.sqrt(xj);
float cosTheta = (float) Math.sqrt(1.0f - xj);
w.x = cosPhi * sinTheta;
w.y = sinPhi * sinTheta;
w.z = cosTheta;
onb.transform(w);
Ray r = new Ray(p, w);
r.setMax(maxDist);
result.add(Color.blend(bright, dark, traceShadow(r)));
}
return result.mul(1.0f / samples);
}
Aggregations