use of org.sunflow.image.Color 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);
}
use of org.sunflow.image.Color in project joons-renderer by joonhyublee.
the class ShadingState method specularPhong.
/**
* Computes a phong specular response to the current light samples and
* global illumination.
*
* @param spec specular color
* @param power phong exponent
* @param numRays number of glossy rays to trace
* @return shaded color
*/
public final Color specularPhong(Color spec, float power, int numRays) {
// integrate a phong specular function
Color lr = Color.black();
if (!includeSpecular || spec.isBlack()) {
return lr;
}
// reflected direction
float dn = 2 * cosND;
Vector3 refDir = new Vector3();
refDir.x = (dn * n.x) + r.dx;
refDir.y = (dn * n.y) + r.dy;
refDir.z = (dn * n.z) + r.dz;
// direct lighting
for (LightSample sample : this) {
float cosNL = sample.dot(n);
float cosLR = sample.dot(refDir);
if (cosLR > 0) {
lr.madd(cosNL * (float) Math.pow(cosLR, power), sample.getSpecularRadiance());
}
}
// indirect lighting
if (numRays > 0) {
int numSamples = getDepth() == 0 ? numRays : 1;
OrthoNormalBasis onb = OrthoNormalBasis.makeFromW(refDir);
float mul = (2.0f * (float) Math.PI / (power + 1)) / numSamples;
for (int i = 0; i < numSamples; i++) {
// specular indirect lighting
double r1 = getRandom(i, 0, numSamples);
double r2 = getRandom(i, 1, numSamples);
double u = 2 * Math.PI * r1;
double s = (float) Math.pow(r2, 1 / (power + 1));
double s1 = (float) Math.sqrt(1 - s * s);
Vector3 w = new Vector3((float) (Math.cos(u) * s1), (float) (Math.sin(u) * s1), (float) s);
w = onb.transform(w, new Vector3());
float wn = Vector3.dot(w, n);
if (wn > 0) {
lr.madd(wn * mul, traceGlossy(new Ray(p, w), i));
}
}
}
lr.mul(spec).mul((power + 2) / (2.0f * (float) Math.PI));
return lr;
}
use of org.sunflow.image.Color in project joons-renderer by joonhyublee.
the class KDTree method build.
@Override
public void build(PrimitiveList primitives) {
UI.printDetailed(Module.ACCEL, "KDTree settings");
UI.printDetailed(Module.ACCEL, " * Max Leaf Size: %d", maxPrims);
UI.printDetailed(Module.ACCEL, " * Max Depth: %d", MAX_DEPTH);
UI.printDetailed(Module.ACCEL, " * Traversal cost: %.2f", TRAVERSAL_COST);
UI.printDetailed(Module.ACCEL, " * Intersect cost: %.2f", INTERSECT_COST);
UI.printDetailed(Module.ACCEL, " * Empty bonus: %.2f", EMPTY_BONUS);
UI.printDetailed(Module.ACCEL, " * Dump leaves: %s", dump ? "enabled" : "disabled");
Timer total = new Timer();
total.start();
primitiveList = primitives;
// get the object space bounds
bounds = primitives.getWorldBounds(null);
int nPrim = primitiveList.getNumPrimitives(), nSplits = 0;
BuildTask task = new BuildTask(nPrim);
Timer prepare = new Timer();
prepare.start();
for (int i = 0; i < nPrim; i++) {
for (int axis = 0; axis < 3; axis++) {
float ls = primitiveList.getPrimitiveBound(i, 2 * axis + 0);
float rs = primitiveList.getPrimitiveBound(i, 2 * axis + 1);
if (ls == rs) {
// flat in this dimension
task.splits[nSplits] = pack(ls, PLANAR, axis, i);
nSplits++;
} else {
task.splits[nSplits + 0] = pack(ls, OPENED, axis, i);
task.splits[nSplits + 1] = pack(rs, CLOSED, axis, i);
nSplits += 2;
}
}
}
task.n = nSplits;
prepare.end();
Timer t = new Timer();
IntArray tempTree = new IntArray();
IntArray tempList = new IntArray();
tempTree.add(0);
tempTree.add(1);
t.start();
// sort it
Timer sorting = new Timer();
sorting.start();
radix12(task.splits, task.n);
sorting.end();
// build the actual tree
BuildStats stats = new BuildStats();
buildTree(bounds.getMinimum().x, bounds.getMaximum().x, bounds.getMinimum().y, bounds.getMaximum().y, bounds.getMinimum().z, bounds.getMaximum().z, task, 1, tempTree, 0, tempList, stats);
t.end();
// write out final arrays
// free some memory
task = null;
tree = tempTree.trim();
tempTree = null;
this.primitives = tempList.trim();
tempList = null;
total.end();
// display some extra info
stats.printStats();
UI.printDetailed(Module.ACCEL, " * Node memory: %s", Memory.sizeof(tree));
UI.printDetailed(Module.ACCEL, " * Object memory: %s", Memory.sizeof(this.primitives));
UI.printDetailed(Module.ACCEL, " * Prepare time: %s", prepare);
UI.printDetailed(Module.ACCEL, " * Sorting time: %s", sorting);
UI.printDetailed(Module.ACCEL, " * Tree creation: %s", t);
UI.printDetailed(Module.ACCEL, " * Build time: %s", total);
if (dump) {
try {
UI.printInfo(Module.ACCEL, "Dumping mtls to %s.mtl ...", dumpPrefix);
FileWriter mtlFile = new FileWriter(dumpPrefix + ".mtl");
int maxN = stats.maxObjects;
for (int n = 0; n <= maxN; n++) {
float blend = (float) n / (float) maxN;
Color nc;
if (blend < 0.25) {
nc = Color.blend(Color.BLUE, Color.GREEN, blend / 0.25f);
} else if (blend < 0.5) {
nc = Color.blend(Color.GREEN, Color.YELLOW, (blend - 0.25f) / 0.25f);
} else if (blend < 0.75) {
nc = Color.blend(Color.YELLOW, Color.RED, (blend - 0.50f) / 0.25f);
} else {
nc = Color.MAGENTA;
}
mtlFile.write(String.format("newmtl mtl%d\n", n));
float[] rgb = nc.getRGB();
mtlFile.write("Ka 0.1 0.1 0.1\n");
mtlFile.write(String.format("Kd %.12g %.12g %.12g\n", rgb[0], rgb[1], rgb[2]));
mtlFile.write("illum 1\n\n");
}
FileWriter objFile = new FileWriter(dumpPrefix + ".obj");
UI.printInfo(Module.ACCEL, "Dumping tree to %s.obj ...", dumpPrefix);
dumpObj(0, 0, maxN, new BoundingBox(bounds), objFile, mtlFile);
objFile.close();
mtlFile.close();
} catch (IOException e) {
Logger.getLogger(KDTree.class.getName()).log(Level.SEVERE, null, e);
}
}
}
use of org.sunflow.image.Color in project joons-renderer by joonhyublee.
the class SunSkyLight method initSunSky.
private void initSunSky() {
// perform all the required initialization of constants
sunDirWorld.normalize();
sunDir = basis.untransform(sunDirWorld, new Vector3());
sunDir.normalize();
sunTheta = (float) Math.acos(MathUtils.clamp(sunDir.z, -1, 1));
if (sunDir.z > 0) {
sunSpectralRadiance = computeAttenuatedSunlight(sunTheta, turbidity);
// produce color suitable for rendering
sunColor = RGBSpace.SRGB.convertXYZtoRGB(sunSpectralRadiance.toXYZ().mul(1e-4f)).constrainRGB();
} else {
sunSpectralRadiance = new ConstantSpectralCurve(0);
}
// sunSolidAngle = (float) (0.25 * Math.PI * 1.39 * 1.39 / (150 * 150));
float theta2 = sunTheta * sunTheta;
float theta3 = sunTheta * theta2;
float T = turbidity;
float T2 = turbidity * turbidity;
double chi = (4.0 / 9.0 - T / 120.0) * (Math.PI - 2.0 * sunTheta);
zenithY = (4.0453 * T - 4.9710) * Math.tan(chi) - 0.2155 * T + 2.4192;
zenithY *= 1000;
/* conversion from kcd/m^2 to cd/m^2 */
zenithx = (0.00165 * theta3 - 0.00374 * theta2 + 0.00208 * sunTheta + 0) * T2 + (-0.02902 * theta3 + 0.06377 * theta2 - 0.03202 * sunTheta + 0.00394) * T + (0.11693 * theta3 - 0.21196 * theta2 + 0.06052 * sunTheta + 0.25885);
zenithy = (0.00275 * theta3 - 0.00610 * theta2 + 0.00316 * sunTheta + 0) * T2 + (-0.04212 * theta3 + 0.08970 * theta2 - 0.04153 * sunTheta + 0.00515) * T + (0.15346 * theta3 - 0.26756 * theta2 + 0.06669 * sunTheta + 0.26688);
perezY[0] = 0.17872 * T - 1.46303;
perezY[1] = -0.35540 * T + 0.42749;
perezY[2] = -0.02266 * T + 5.32505;
perezY[3] = 0.12064 * T - 2.57705;
perezY[4] = -0.06696 * T + 0.37027;
perezx[0] = -0.01925 * T - 0.25922;
perezx[1] = -0.06651 * T + 0.00081;
perezx[2] = -0.00041 * T + 0.21247;
perezx[3] = -0.06409 * T - 0.89887;
perezx[4] = -0.00325 * T + 0.04517;
perezy[0] = -0.01669 * T - 0.26078;
perezy[1] = -0.09495 * T + 0.00921;
perezy[2] = -0.00792 * T + 0.21023;
perezy[3] = -0.04405 * T - 1.65369;
perezy[4] = -0.01092 * T + 0.05291;
final int w = 32, h = 32;
imageHistogram = new float[w][h];
colHistogram = new float[w];
float du = 1.0f / w;
float dv = 1.0f / h;
for (int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
float u = (x + 0.5f) * du;
float v = (y + 0.5f) * dv;
Color c = getSkyRGB(getDirection(u, v));
imageHistogram[x][y] = c.getLuminance() * (float) Math.sin(Math.PI * v);
if (y > 0) {
imageHistogram[x][y] += imageHistogram[x][y - 1];
}
}
colHistogram[x] = imageHistogram[x][h - 1];
if (x > 0) {
colHistogram[x] += colHistogram[x - 1];
}
for (int y = 0; y < h; y++) {
imageHistogram[x][y] /= imageHistogram[x][h - 1];
}
}
for (int x = 0; x < w; x++) {
colHistogram[x] /= colHistogram[w - 1];
}
jacobian = (float) (2 * Math.PI * Math.PI) / (w * h);
}
use of org.sunflow.image.Color in project joons-renderer by joonhyublee.
the class SCAsciiParser method parseColor.
protected Color parseColor() throws IOException {
String space = p.getNextToken();
Color c = null;
if (space.equals("sRGB nonlinear")) {
float r = p.getNextFloat();
float g = p.getNextFloat();
float b = p.getNextFloat();
c = new Color(r, g, b);
c.toLinear();
} else if (space.equals("sRGB linear")) {
float r = p.getNextFloat();
float g = p.getNextFloat();
float b = p.getNextFloat();
c = new Color(r, g, b);
} else {
UI.printWarning(Module.API, "Unrecognized color space: %s", space);
}
return c;
}
Aggregations