use of org.sunflow.math.Vector3 in project joons-renderer by joonhyublee.
the class ImageBasedLight method getDirection.
private Vector3 getDirection(float u, float v) {
Vector3 dest = new Vector3();
double phi = 0, theta = 0;
theta = u * 2 * Math.PI;
phi = v * Math.PI;
double sin_phi = Math.sin(phi);
dest.x = (float) (-sin_phi * Math.cos(theta));
dest.y = (float) Math.cos(phi);
dest.z = (float) (sin_phi * Math.sin(theta));
return dest;
}
use of org.sunflow.math.Vector3 in project joons-renderer by joonhyublee.
the class LightServer method calculatePhotons.
boolean calculatePhotons(final PhotonStore map, String type, final int seed, Options options) {
if (map == null) {
return true;
}
if (lights.length == 0) {
UI.printError(Module.LIGHT, "Unable to trace %s photons, no lights in scene", type);
return false;
}
final float[] histogram = new float[lights.length];
histogram[0] = lights[0].getPower();
for (int i = 1; i < lights.length; i++) {
histogram[i] = histogram[i - 1] + lights[i].getPower();
}
UI.printInfo(Module.LIGHT, "Tracing %s photons ...", type);
map.prepare(options, scene.getBounds());
int numEmittedPhotons = map.numEmit();
if (numEmittedPhotons <= 0 || histogram[histogram.length - 1] <= 0) {
UI.printError(Module.LIGHT, "Photon mapping enabled, but no %s photons to emit", type);
return false;
}
UI.taskStart("Tracing " + type + " photons", 0, numEmittedPhotons);
Thread[] photonThreads = new Thread[scene.getThreads()];
final float scale = 1.0f / numEmittedPhotons;
int delta = numEmittedPhotons / photonThreads.length;
photonCounter = 0;
Timer photonTimer = new Timer();
photonTimer.start();
for (int i = 0; i < photonThreads.length; i++) {
final int threadID = i;
final int start = threadID * delta;
final int end = (threadID == (photonThreads.length - 1)) ? numEmittedPhotons : (threadID + 1) * delta;
photonThreads[i] = new Thread(new Runnable() {
public void run() {
IntersectionState istate = new IntersectionState();
for (int i = start; i < end; i++) {
synchronized (LightServer.this) {
UI.taskUpdate(photonCounter);
photonCounter++;
if (UI.taskCanceled()) {
return;
}
}
int qmcI = i + seed;
double rand = QMC.halton(0, qmcI) * histogram[histogram.length - 1];
int j = 0;
while (rand >= histogram[j] && j < histogram.length) {
j++;
}
// make sure we didn't pick a zero-probability light
if (j == histogram.length) {
continue;
}
double randX1 = (j == 0) ? rand / histogram[0] : (rand - histogram[j]) / (histogram[j] - histogram[j - 1]);
double randY1 = QMC.halton(1, qmcI);
double randX2 = QMC.halton(2, qmcI);
double randY2 = QMC.halton(3, qmcI);
Point3 pt = new Point3();
Vector3 dir = new Vector3();
Color power = new Color();
lights[j].getPhoton(randX1, randY1, randX2, randY2, pt, dir, power);
power.mul(scale);
Ray r = new Ray(pt, dir);
scene.trace(r, istate);
if (istate.hit()) {
shadePhoton(ShadingState.createPhotonState(r, istate, qmcI, map, LightServer.this), power);
}
}
}
});
photonThreads[i].setPriority(scene.getThreadPriority());
photonThreads[i].start();
}
for (int i = 0; i < photonThreads.length; i++) {
try {
photonThreads[i].join();
} catch (InterruptedException e) {
UI.printError(Module.LIGHT, "Photon thread %d of %d was interrupted", i + 1, photonThreads.length);
return false;
}
}
if (UI.taskCanceled()) {
// shut down task cleanly
UI.taskStop();
return false;
}
photonTimer.end();
UI.taskStop();
UI.printInfo(Module.LIGHT, "Tracing time for %s photons: %s", type, photonTimer.toString());
map.init();
return true;
}
use of org.sunflow.math.Vector3 in project joons-renderer by joonhyublee.
the class Texture method getBump.
public Vector3 getBump(float x, float y, OrthoNormalBasis basis, float scale) {
Bitmap bitmapv = getBitmap();
float dx = 1.0f / bitmapv.getWidth();
float dy = 1.0f / bitmapv.getHeight();
float b0 = getPixel(x, y).getLuminance();
float bx = getPixel(x + dx, y).getLuminance();
float by = getPixel(x, y + dy).getLuminance();
return basis.transform(new Vector3(scale * (b0 - bx), scale * (b0 - by), 1)).normalize();
}
use of org.sunflow.math.Vector3 in project joons-renderer by joonhyublee.
the class AnisotropicWardShader method brdf.
private float brdf(Vector3 i, Vector3 o, OrthoNormalBasis basis) {
float fr = 4 * (float) Math.PI * alphaX * alphaY;
float p = basis.untransformZ(i) * basis.untransformZ(o);
if (p > 0) {
fr *= (float) Math.sqrt(p);
} else {
fr = 0;
}
Vector3 h = Vector3.add(i, o, new Vector3());
basis.untransform(h);
float hx = h.x / alphaX;
hx *= hx;
float hy = h.y / alphaY;
hy *= hy;
float hn = h.z * h.z;
if (fr > 0) {
fr = (float) Math.exp(-(hx + hy) / hn) / fr;
}
return fr;
}
use of org.sunflow.math.Vector3 in project joons-renderer by joonhyublee.
the class AnisotropicWardShader method getRadiance.
public Color getRadiance(ShadingState state) {
// make sure we are on the right side of the material
state.faceforward();
OrthoNormalBasis onb = state.getBasis();
// direct lighting and caustics
state.initLightSamples();
state.initCausticSamples();
Color lr = Color.black();
// compute specular contribution
if (state.includeSpecular()) {
Vector3 in = state.getRay().getDirection().negate(new Vector3());
for (LightSample sample : state) {
float cosNL = sample.dot(state.getNormal());
float fr = brdf(in, sample.getShadowRay().getDirection(), onb);
lr.madd(cosNL * fr, sample.getSpecularRadiance());
}
// indirect lighting - specular
if (numRays > 0) {
int n = state.getDepth() == 0 ? numRays : 1;
for (int i = 0; i < n; i++) {
// specular indirect lighting
double r1 = state.getRandom(i, 0, n);
double r2 = state.getRandom(i, 1, n);
float alphaRatio = alphaY / alphaX;
float phi = 0;
if (r1 < 0.25) {
double val = 4 * r1;
phi = (float) Math.atan(alphaRatio * Math.tan(Math.PI / 2 * val));
} else if (r1 < 0.5) {
double val = 1 - 4 * (0.5 - r1);
phi = (float) Math.atan(alphaRatio * Math.tan(Math.PI / 2 * val));
phi = (float) Math.PI - phi;
} else if (r1 < 0.75) {
double val = 4 * (r1 - 0.5);
phi = (float) Math.atan(alphaRatio * Math.tan(Math.PI / 2 * val));
phi += Math.PI;
} else {
double val = 1 - 4 * (1 - r1);
phi = (float) Math.atan(alphaRatio * Math.tan(Math.PI / 2 * val));
phi = 2 * (float) Math.PI - phi;
}
float cosPhi = (float) Math.cos(phi);
float sinPhi = (float) Math.sin(phi);
float denom = (cosPhi * cosPhi) / (alphaX * alphaX) + (sinPhi * sinPhi) / (alphaY * alphaY);
float theta = (float) Math.atan(Math.sqrt(-Math.log(1 - r2) / denom));
float sinTheta = (float) Math.sin(theta);
float cosTheta = (float) Math.cos(theta);
Vector3 h = new Vector3();
h.x = sinTheta * cosPhi;
h.y = sinTheta * sinPhi;
h.z = cosTheta;
onb.transform(h);
Vector3 o = new Vector3();
float ih = Vector3.dot(h, in);
o.x = 2 * ih * h.x - in.x;
o.y = 2 * ih * h.y - in.y;
o.z = 2 * ih * h.z - in.z;
float no = onb.untransformZ(o);
float ni = onb.untransformZ(in);
float w = ih * cosTheta * cosTheta * cosTheta * (float) Math.sqrt(Math.abs(no / ni));
Ray r = new Ray(state.getPoint(), o);
lr.madd(w / n, state.traceGlossy(r, i));
}
}
lr.mul(rhoS);
}
// add diffuse contribution
lr.add(state.diffuse(getDiffuse(state)));
return lr;
}
Aggregations