📄 sunskylight.java
字号:
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);
}
public boolean update(ParameterList pl, SunflowAPI api) {
Vector3 up = pl.getVector("up", null);
Vector3 east = pl.getVector("east", null);
if (up != null && east != null)
basis = OrthoNormalBasis.makeFromWV(up, east);
else if (up != null)
basis = OrthoNormalBasis.makeFromW(up);
numSkySamples = pl.getInt("samples", numSkySamples);
sunDirWorld = pl.getVector("sundir", sunDirWorld);
turbidity = pl.getFloat("turbidity", turbidity);
// recompute model
initSunSky();
return true;
}
public void init(String name, SunflowAPI api) {
// register this object with the api properly
api.geometry(name, this);
api.shader(name + ".shader", this);
api.parameter("shaders", name + ".shader");
api.instance(name + ".instance", name);
api.light(name + ".light", this);
}
private Color getSkyRGB(Vector3 dir) {
if (dir.z < 0)
return Color.BLACK;
if (dir.z < 0.001f)
dir.z = 0.001f;
dir.normalize();
double theta = Math.acos(MathUtils.clamp(dir.z, -1, 1));
double gamma = Math.acos(MathUtils.clamp(Vector3.dot(dir, sunDir), -1, 1));
double x = perezFunction(perezx, theta, gamma, zenithx);
double y = perezFunction(perezy, theta, gamma, zenithy);
double Y = perezFunction(perezY, theta, gamma, zenithY) * 1e-4;
XYZColor c = ChromaticitySpectrum.get((float) x, (float) y);
// XYZColor c = new ChromaticitySpectrum((float) x, (float) y).toXYZ();
float X = (float) (c.getX() * Y / c.getY());
float Z = (float) (c.getZ() * Y / c.getY());
return RGBSpace.SRGB.convertXYZtoRGB(X, (float) Y, Z);
}
public int getNumSamples() {
return 1 + numSkySamples;
}
public void getPhoton(double randX1, double randY1, double randX2, double randY2, Point3 p, Vector3 dir, Color power) {
// FIXME: not implemented
}
public float getPower() {
return 0;
}
public void getSamples(ShadingState state) {
if (Vector3.dot(sunDirWorld, state.getGeoNormal()) > 0 && Vector3.dot(sunDirWorld, state.getNormal()) > 0) {
LightSample dest = new LightSample();
dest.setShadowRay(new Ray(state.getPoint(), sunDirWorld));
dest.getShadowRay().setMax(Float.MAX_VALUE);
dest.setRadiance(sunColor, sunColor);
dest.traceShadow(state);
state.addSample(dest);
}
int n = state.getDiffuseDepth() > 0 ? 1 : numSkySamples;
for (int i = 0; i < n; i++) {
// random offset on unit square, we use the infinite version of
// getRandom because the light sampling is adaptive
double randX = state.getRandom(i, 0, n);
double randY = state.getRandom(i, 1, n);
int x = 0;
while (randX >= colHistogram[x] && x < colHistogram.length - 1)
x++;
float[] rowHistogram = imageHistogram[x];
int y = 0;
while (randY >= rowHistogram[y] && y < rowHistogram.length - 1)
y++;
// sample from (x, y)
float u = (float) ((x == 0) ? (randX / colHistogram[0]) : ((randX - colHistogram[x - 1]) / (colHistogram[x] - colHistogram[x - 1])));
float v = (float) ((y == 0) ? (randY / rowHistogram[0]) : ((randY - rowHistogram[y - 1]) / (rowHistogram[y] - rowHistogram[y - 1])));
float px = ((x == 0) ? colHistogram[0] : (colHistogram[x] - colHistogram[x - 1]));
float py = ((y == 0) ? rowHistogram[0] : (rowHistogram[y] - rowHistogram[y - 1]));
float su = (x + u) / colHistogram.length;
float sv = (y + v) / rowHistogram.length;
float invP = (float) Math.sin(sv * Math.PI) * jacobian / (n * px * py);
Vector3 localDir = getDirection(su, sv);
Vector3 dir = basis.transform(localDir, new Vector3());
if (Vector3.dot(dir, state.getGeoNormal()) > 0 && Vector3.dot(dir, state.getNormal()) > 0) {
LightSample dest = new LightSample();
dest.setShadowRay(new Ray(state.getPoint(), dir));
dest.getShadowRay().setMax(Float.MAX_VALUE);
Color radiance = getSkyRGB(localDir);
dest.setRadiance(radiance, radiance);
dest.getDiffuseRadiance().mul(invP);
dest.getSpecularRadiance().mul(invP);
dest.traceShadow(state);
state.addSample(dest);
}
}
}
public PrimitiveList getBakingPrimitives() {
return null;
}
public int getNumPrimitives() {
return 1;
}
public float getPrimitiveBound(int primID, int i) {
return 0;
}
public BoundingBox getWorldBounds(Matrix4 o2w) {
return null;
}
public void intersectPrimitive(Ray r, int primID, IntersectionState state) {
if (r.getMax() == Float.POSITIVE_INFINITY)
state.setIntersection(0, 0, 0);
}
public void prepareShadingState(ShadingState state) {
if (state.includeLights())
state.setShader(this);
}
public Color getRadiance(ShadingState state) {
return getSkyRGB(basis.untransform(state.getRay().getDirection())).constrainRGB();
}
public void scatterPhoton(ShadingState state, Color power) {
// let photon escape
}
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;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -