1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
package org.sunflow.core.shader;
import org.sunflow.SunflowAPI;
import org.sunflow.core.ParameterList;
import org.sunflow.core.Ray;
import org.sunflow.core.Shader;
import org.sunflow.core.ShadingState;
import org.sunflow.core.Texture;
import org.sunflow.image.Color;
import org.sunflow.math.MathUtils;
import org.sunflow.math.OrthoNormalBasis;
import org.sunflow.math.Vector3;
public class UberShader implements Shader {
private Color diff;
private Color spec;
private Texture diffmap;
private Texture specmap;
private float diffBlend;
private float specBlend;
private float glossyness;
private int numSamples;
public UberShader() {
diff = spec = Color.GRAY;
diffmap = specmap = null;
diffBlend = specBlend = 1;
glossyness = 0;
numSamples = 4;
}
public boolean update(ParameterList pl, SunflowAPI api) {
diff = pl.getColor("diffuse", diff);
spec = pl.getColor("specular", spec);
String filename;
filename = pl.getString("diffuse.texture", null);
if (filename != null)
// EP : Made texture cache local to a SunFlow API instance
diffmap = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
filename = pl.getString("specular.texture", null);
if (filename != null)
// EP : Made texture cache local to a SunFlow API instance
specmap = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
diffBlend = MathUtils.clamp(pl.getFloat("diffuse.blend", diffBlend), 0, 1);
specBlend = MathUtils.clamp(pl.getFloat("specular.blend", diffBlend), 0, 1);
glossyness = MathUtils.clamp(pl.getFloat("glossyness", glossyness), 0, 1);
numSamples = pl.getInt("samples", numSamples);
return true;
}
public Color getDiffuse(ShadingState state) {
return diffmap == null ? diff : Color.blend(diff, diffmap.getPixel(state.getUV().x, state.getUV().y), diffBlend);
}
public Color getSpecular(ShadingState state) {
return specmap == null ? spec : Color.blend(spec, specmap.getPixel(state.getUV().x, state.getUV().y), specBlend);
}
public Color getRadiance(ShadingState state) {
// make sure we are on the right side of the material
state.faceforward();
// direct lighting
state.initLightSamples();
state.initCausticSamples();
// EP : Added transparency management
float alpha;
if (!isOpaque() && diffmap != null && (alpha = diffmap.getOpacityAlpha(state.getUV().x, state.getUV().y)) <= 0.99999) {
// Ignore glossiness for half transparent pixels
Color c = state.diffuse(getDiffuse(state));
Vector3 refrDir = state.getRay().getDirection();
Color refraction = state.traceRefraction(new Ray(state.getPoint(), refrDir), 0);
return c.mul(alpha).madd(1 - alpha, refraction);
} else {
// EP : End of modification
Color d = getDiffuse(state);
Color lr = state.diffuse(d);
if (!state.includeSpecular())
return lr;
if (glossyness == 0) {
float cos = state.getCosND();
float dn = 2 * cos;
Vector3 refDir = new Vector3();
refDir.x = (dn * state.getNormal().x) + state.getRay().getDirection().x;
refDir.y = (dn * state.getNormal().y) + state.getRay().getDirection().y;
refDir.z = (dn * state.getNormal().z) + state.getRay().getDirection().z;
Ray refRay = new Ray(state.getPoint(), refDir);
// compute Fresnel term
cos = 1 - cos;
float cos2 = cos * cos;
float cos5 = cos2 * cos2 * cos;
Color spec = getSpecular(state);
Color ret = Color.white();
ret.sub(spec);
ret.mul(cos5);
ret.add(spec);
return lr.add(ret.mul(state.traceReflection(refRay, 0)));
} else
return lr.add(state.specularPhong(getSpecular(state), 2 / glossyness, numSamples));
// EP : Added transparency management
}
// EP : End of modification
}
public void scatterPhoton(ShadingState state, Color power) {
Color diffuse, specular;
// make sure we are on the right side of the material
state.faceforward();
diffuse = getDiffuse(state);
specular = getSpecular(state);
state.storePhoton(state.getRay().getDirection(), power, diffuse);
float d = diffuse.getAverage();
float r = specular.getAverage();
double rnd = state.getRandom(0, 0, 1);
if (rnd < d) {
// photon is scattered
power.mul(diffuse).mul(1.0f / d);
OrthoNormalBasis onb = state.getBasis();
double u = 2 * Math.PI * rnd / d;
double v = state.getRandom(0, 1, 1);
float s = (float) Math.sqrt(v);
float s1 = (float) Math.sqrt(1.0 - v);
Vector3 w = new Vector3((float) Math.cos(u) * s, (float) Math.sin(u) * s, s1);
w = onb.transform(w, new Vector3());
state.traceDiffusePhoton(new Ray(state.getPoint(), w), power);
} else if (rnd < d + r) {
if (glossyness == 0) {
float cos = -Vector3.dot(state.getNormal(), state.getRay().getDirection());
power.mul(diffuse).mul(1.0f / d);
// photon is reflected
float dn = 2 * cos;
Vector3 dir = new Vector3();
dir.x = (dn * state.getNormal().x) + state.getRay().getDirection().x;
dir.y = (dn * state.getNormal().y) + state.getRay().getDirection().y;
dir.z = (dn * state.getNormal().z) + state.getRay().getDirection().z;
state.traceReflectionPhoton(new Ray(state.getPoint(), dir), power);
} else {
float dn = 2.0f * state.getCosND();
// reflected direction
Vector3 refDir = new Vector3();
refDir.x = (dn * state.getNormal().x) + state.getRay().dx;
refDir.y = (dn * state.getNormal().y) + state.getRay().dy;
refDir.z = (dn * state.getNormal().z) + state.getRay().dz;
power.mul(spec).mul(1.0f / r);
OrthoNormalBasis onb = state.getBasis();
double u = 2 * Math.PI * (rnd - r) / r;
double v = state.getRandom(0, 1, 1);
float s = (float) Math.pow(v, 1 / ((1.0f / glossyness) + 1));
float s1 = (float) Math.sqrt(1 - s * s);
Vector3 w = new Vector3((float) Math.cos(u) * s1, (float) Math.sin(u) * s1, s);
w = onb.transform(w, new Vector3());
state.traceReflectionPhoton(new Ray(state.getPoint(), w), power);
}
}
}
// EP : Added transparency management
public boolean isOpaque() {
return diffmap == null || !(diffmap.isTransparent());
}
public Color getOpacity(ShadingState state) {
return diffmap != null ? diffmap.getOpacity(state.getUV().x, state.getUV().y) : Color.WHITE;
}
// EP : End of modification
}
|