📄 shadingstate.java
字号:
package org.sunflow.core;
import java.util.Iterator;
import org.sunflow.core.primitive.TriangleMesh;
import org.sunflow.image.Color;
import org.sunflow.math.Matrix4;
import org.sunflow.math.OrthoNormalBasis;
import org.sunflow.math.Point2;
import org.sunflow.math.Point3;
import org.sunflow.math.QMC;
import org.sunflow.math.Vector3;
/**
* Represents a point to be shaded and provides various options for the shading
* of this point, including spawning of new rays.
*/
public final class ShadingState implements Iterable<LightSample> {
private IntersectionState istate;
private LightServer server;
private float rx, ry;
private Color result;
private Point3 p;
private Vector3 n;
private Point2 tex;
private Vector3 ng;
private OrthoNormalBasis basis;
private float cosND;
private boolean behind;
private float hitU, hitV;
private Instance instance;
private int primitiveID;
private Ray r;
private int d; // quasi monte carlo instance variables
private int i; // quasi monte carlo instance variables
private double qmcD0I;
private double qmcD1I;
private Shader shader;
private Modifier modifier;
private int diffuseDepth;
private int reflectionDepth;
private int refractionDepth;
private boolean includeLights;
private boolean includeSpecular;
private LightSample lightSample;
private PhotonStore map;
static ShadingState createPhotonState(Ray r, IntersectionState istate, int i, PhotonStore map, LightServer server) {
ShadingState s = new ShadingState(null, istate, r, i, 4);
s.server = server;
s.map = map;
return s;
}
static ShadingState createState(IntersectionState istate, float rx, float ry, Ray r, int i, LightServer server) {
ShadingState s = new ShadingState(null, istate, r, i, 4);
s.server = server;
s.rx = rx;
s.ry = ry;
return s;
}
static ShadingState createDiffuseBounceState(ShadingState previous, Ray r, int i) {
ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
s.diffuseDepth++;
return s;
}
static ShadingState createGlossyBounceState(ShadingState previous, Ray r, int i) {
ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
s.includeLights = false;
s.includeSpecular = false;
s.reflectionDepth++;
return s;
}
static ShadingState createReflectionBounceState(ShadingState previous, Ray r, int i) {
ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
s.reflectionDepth++;
return s;
}
static ShadingState createRefractionBounceState(ShadingState previous, Ray r, int i) {
ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
s.refractionDepth++;
return s;
}
static ShadingState createFinalGatherState(ShadingState state, Ray r, int i) {
ShadingState finalGatherState = new ShadingState(state, state.istate, r, i, 2);
finalGatherState.diffuseDepth++;
finalGatherState.includeLights = false;
finalGatherState.includeSpecular = false;
return finalGatherState;
}
private ShadingState(ShadingState previous, IntersectionState istate, Ray r, int i, int d) {
this.r = r;
this.istate = istate;
this.i = i;
this.d = d;
this.instance = istate.instance; // local copy
this.primitiveID = istate.id;
this.hitU = istate.u;
this.hitV = istate.v;
if (previous == null) {
diffuseDepth = 0;
reflectionDepth = 0;
refractionDepth = 0;
} else {
diffuseDepth = previous.diffuseDepth;
reflectionDepth = previous.reflectionDepth;
refractionDepth = previous.refractionDepth;
this.server = previous.server;
this.map = previous.map;
this.rx = previous.rx;
this.ry = previous.ry;
this.i += previous.i;
this.d += previous.d;
}
behind = false;
cosND = Float.NaN;
includeLights = includeSpecular = true;
qmcD0I = QMC.halton(this.d, this.i);
qmcD1I = QMC.halton(this.d + 1, this.i);
result = null;
}
final void setRay(Ray r) {
this.r = r;
}
/**
* Create objects needed for surface shading: point, normal, texture
* coordinates and basis.
*/
public final void init() {
p = new Point3();
n = new Vector3();
tex = new Point2();
ng = new Vector3();
basis = null;
}
/**
* Run the shader at this surface point.
*
* @return shaded result
*/
public final Color shade() {
return server.shadeHit(this);
}
final void correctShadingNormal() {
// correct shading normals pointing the wrong way
if (Vector3.dot(n, ng) < 0) {
n.negate();
basis.flipW();
}
}
/**
* Flip the surface normals to ensure they are facing the current ray. This
* method also offsets the shading point away from the surface so that new
* rays will not intersect the same surface again by mistake.
*/
public final void faceforward() {
// make sure we are on the right side of the material
if (r.dot(ng) < 0) {
} else {
// this ensure the ray and the geomtric normal are pointing in the
// same direction
ng.negate();
n.negate();
basis.flipW();
behind = true;
}
cosND = Math.max(-r.dot(n), 0); // can't be negative
// offset the shaded point away from the surface to prevent
// self-intersection errors
p.x += 0.001f * ng.x;
p.y += 0.001f * ng.y;
p.z += 0.001f * ng.z;
}
/**
* Get x coordinate of the pixel being shaded.
*
* @return pixel x coordinate
*/
public final float getRasterX() {
return rx;
}
/**
* Get y coordinate of the pixel being shaded.
*
* @return pixel y coordinate
*/
public final float getRasterY() {
return ry;
}
/**
* Cosine between the shading normal and the ray. This is set by
* {@link #faceforward()}.
*
* @return cosine between shading normal and the ray
*/
public final float getCosND() {
return cosND;
}
/**
* Returns true if the ray hit the surface from behind. This is set by
* {@link #faceforward()}.
*
* @return <code>true</code> if the surface was hit from behind.
*/
public final boolean isBehind() {
return behind;
}
final IntersectionState getIntersectionState() {
return istate;
}
/**
* Get u barycentric coordinate of the intersection point.
*
* @return u barycentric coordinate
*/
public final float getU() {
return hitU;
}
/**
* Get v barycentric coordinate of the intersection point.
*
* @return v barycentric coordinate
*/
public final float getV() {
return hitV;
}
/**
* Get the instance which was intersected
*
* @return intersected instance object
*/
public final Instance getInstance() {
return instance;
}
/**
* Get the primitive ID which was intersected
*
* @return intersected primitive ID
*/
public final int getPrimitiveID() {
return primitiveID;
}
final void setResult(Color c) {
result = c;
}
/**
* Get the result of shading this point
*
* @return shaded result
*/
public final Color getResult() {
return result;
}
final LightServer getLightServer() {
return server;
}
/**
* Add the specified light sample to the list of lights to be used
*
* @param sample a valid light sample
*/
public final void addSample(LightSample sample) {
// add to list
sample.next = lightSample;
lightSample = sample;
}
/**
* Get a QMC sample from an infinite sequence.
*
* @param j sample number (starts from 0)
* @param dim dimension to sample
* @return pseudo-random value in [0,1)
*/
public final double getRandom(int j, int dim) {
switch (dim) {
case 0:
return QMC.mod1(qmcD0I + QMC.halton(0, j));
case 1:
return QMC.mod1(qmcD1I + QMC.halton(1, j));
default:
return QMC.mod1(QMC.halton(d + dim, i) + QMC.halton(dim, j));
}
}
/**
* Get a QMC sample from a finite sequence of n elements. This provides
* better stratification than the infinite version, but does not allow for
* adaptive sampling.
*
* @param j sample number (starts from 0)
* @param dim dimension to sample
* @param n number of samples
* @return pseudo-random value in [0,1)
*/
public final double getRandom(int j, int dim, int n) {
switch (dim) {
case 0:
return QMC.mod1(qmcD0I + (double) j / (double) n);
case 1:
return QMC.mod1(qmcD1I + QMC.halton(0, j));
default:
return QMC.mod1(QMC.halton(d + dim, i) + QMC.halton(dim - 1, j));
}
}
/**
* Checks to see if the shader should include emitted light.
*
* @return <code>true</code> if emitted light should be included,
* <code>false</code> otherwise
*/
public final boolean includeLights() {
return includeLights;
}
/**
* Checks to see if the shader should include specular terms.
*
* @return <code>true</code> if specular terms should be included,
* <code>false</code> otherwise
*/
public final boolean includeSpecular() {
return includeSpecular;
}
/**
* Get the shader to be used to shade this surface.
*
* @return shader to be used
*/
public final Shader getShader() {
return shader;
}
/**
* Record which shader should be executed for the intersected surface.
*
* @param shader surface shader to use to shade the current intersection
* point
*/
public final void setShader(Shader shader) {
this.shader = shader;
}
final Modifier getModifier() {
return modifier;
}
/**
* Record which modifier should be applied to the intersected surface
*
* @param modifier modifier to use the change this shading state
*/
public final void setModifier(Modifier modifier) {
this.modifier = modifier;
}
/**
* Get the current total tracing depth. First generation rays have a depth
* of 0.
*
* @return current tracing depth
*/
public final int getDepth() {
return diffuseDepth + reflectionDepth + refractionDepth;
}
/**
* Get the current diffuse tracing depth. This is the number of diffuse
* surfaces reflected from.
*
* @return current diffuse tracing depth
*/
public final int getDiffuseDepth() {
return diffuseDepth;
}
/**
* Get the current reflection tracing depth. This is the number of specular
* surfaces reflected from.
*
* @return current reflection tracing depth
*/
public final int getReflectionDepth() {
return reflectionDepth;
}
/**
* Get the current refraction tracing depth. This is the number of specular
* surfaces refracted from.
*
* @return current refraction tracing depth
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -