Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add apparent emitter brightness controls #1555

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion chunky/src/java/se/llbit/chunky/chunk/BlockPalette.java
Original file line number Diff line number Diff line change
Expand Up @@ -341,15 +341,17 @@ public static Map<String, Consumer<Block>> getDefaultMaterialProperties() {
}
});
materialProperties.put("minecraft:redstone_wall_torch", block -> {
if (block instanceof RedstoneWallTorch && ((RedstoneWallTorch) block).isLit()) {
if (block instanceof RedstoneWallTorch && ((RedstoneWallTorch) block).isLit()) {
block.emittance = 1.0f;
}
});
materialProperties.put("minecraft:torch", block -> {
block.emittance = 50.0f;
block.apparentBrightnessModifier = 0.02f;
});
materialProperties.put("minecraft:wall_torch", block -> {
block.emittance = 50.0f;
block.apparentBrightnessModifier = 0.02f;
});
materialProperties.put("minecraft:fire", block -> {
block.emittance = 1.0f;
Expand Down Expand Up @@ -448,15 +450,19 @@ public static Map<String, Consumer<Block>> getDefaultMaterialProperties() {
});
materialProperties.put("minecraft:soul_fire_torch", block -> { // MC 20w06a-20w16a
block.emittance = 35.0f;
block.apparentBrightnessModifier = 0.02f;
});
materialProperties.put("minecraft:soul_torch", block -> { // MC >= 20w17a
block.emittance = 35.0f;
block.apparentBrightnessModifier = 0.02f;
});
materialProperties.put("minecraft:soul_fire_wall_torch", block -> { // MC 20w06a-20w16a
block.emittance = 35.0f;
block.apparentBrightnessModifier = 0.02f;
});
materialProperties.put("minecraft:soul_wall_torch", block -> { // MC >= 20w17a
block.emittance = 35.0f;
block.apparentBrightnessModifier = 0.02f;
});
materialProperties.put("minecraft:soul_fire", block -> {
block.emittance = 0.6f;
Expand Down
23 changes: 12 additions & 11 deletions chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,19 +165,19 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add
if (!scene.kill(ray.depth + 1, random)) {
Ray reflected = new Ray();

float emittance = 0;
double apparentBrightness = 0;

Vector4 indirectEmitterColor = new Vector4(0, 0, 0, 0);

if (scene.emittersEnabled && (!scene.isPreventNormalEmitterWithSampling() || scene.getEmitterSamplingStrategy() == EmitterSamplingStrategy.NONE || ray.depth == 0) && currentMat.emittance > Ray.EPSILON) {

emittance = addEmitted;
apparentBrightness = addEmitted * currentMat.emittance * currentMat.apparentBrightnessModifier * scene.apparentEmitterBrightness * scene.emitterIntensity;
ray.emittance.x = ray.color.x * ray.color.x *
currentMat.emittance * scene.emitterIntensity;
currentMat.emittance * scene.emitterLightIntensity * scene.emitterIntensity;
ray.emittance.y = ray.color.y * ray.color.y *
currentMat.emittance * scene.emitterIntensity;
currentMat.emittance * scene.emitterLightIntensity * scene.emitterIntensity;
ray.emittance.z = ray.color.z * ray.color.z *
currentMat.emittance * scene.emitterIntensity;
currentMat.emittance * scene.emitterLightIntensity * scene.emitterIntensity;
hit = true;
} else if(scene.emittersEnabled && scene.emitterSamplingStrategy != EmitterSamplingStrategy.NONE && scene.getEmitterGrid() != null) {
// Sample emitter
Expand Down Expand Up @@ -235,11 +235,11 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add
reflected.diffuseReflection(ray, random);
hit = pathTrace(scene, reflected, state, 0, false) || hit;
if (hit) {
ray.color.x = ray.color.x * (emittance + directLightR * scene.sun.emittance.x + (
ray.color.x = ray.color.x * (apparentBrightness + directLightR * scene.sun.emittance.x + (
reflected.color.x + reflected.emittance.x) + (indirectEmitterColor.x));
ray.color.y = ray.color.y * (emittance + directLightG * scene.sun.emittance.y + (
ray.color.y = ray.color.y * (apparentBrightness + directLightG * scene.sun.emittance.y + (
reflected.color.y + reflected.emittance.y) + (indirectEmitterColor.y));
ray.color.z = ray.color.z * (emittance + directLightB * scene.sun.emittance.z + (
ray.color.z = ray.color.z * (apparentBrightness + directLightB * scene.sun.emittance.z + (
reflected.color.z + reflected.emittance.z) + (indirectEmitterColor.z));
} else if(indirectEmitterColor.x > Ray.EPSILON || indirectEmitterColor.y > Ray.EPSILON || indirectEmitterColor.z > Ray.EPSILON) {
hit = true;
Expand All @@ -254,11 +254,11 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add
hit = pathTrace(scene, reflected, state, 0, false) || hit;
if (hit) {
ray.color.x =
ray.color.x * (emittance + (reflected.color.x + reflected.emittance.x) + (indirectEmitterColor.x));
ray.color.x * (apparentBrightness + (reflected.color.x + reflected.emittance.x) + (indirectEmitterColor.x));
ray.color.y =
ray.color.y * (emittance + (reflected.color.y + reflected.emittance.y) + (indirectEmitterColor.y));
ray.color.y * (apparentBrightness + (reflected.color.y + reflected.emittance.y) + (indirectEmitterColor.y));
ray.color.z =
ray.color.z * (emittance + (reflected.color.z + reflected.emittance.z) + (indirectEmitterColor.z));
ray.color.z * (apparentBrightness + (reflected.color.z + reflected.emittance.z) + (indirectEmitterColor.z));
} else if(indirectEmitterColor.x > Ray.EPSILON || indirectEmitterColor.y > Ray.EPSILON || indirectEmitterColor.z > Ray.EPSILON) {
hit = true;
ray.color.x *= indirectEmitterColor.x;
Expand Down Expand Up @@ -471,6 +471,7 @@ private static void sampleEmitterFace(Scene scene, Ray ray, Grid.EmitterPosition
e *= pos.block.surfaceArea(face);
e *= emitterRay.getCurrentMaterial().emittance;
e *= scene.emitterIntensity;
e *= scene.emitterLightIntensity;
e *= scaler;

result.scaleAdd(e, emitterRay.color);
Expand Down
90 changes: 87 additions & 3 deletions chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,48 @@ public class Scene implements JsonSerializable, Refreshable {
/**
* Default emitter intensity.
*/
public static final double DEFAULT_EMITTER_INTENSITY = 13;
public static final double DEFAULT_EMITTER_INTENSITY = 1;

/**
* Minimum emitter intensity.
*/
public static final double MIN_EMITTER_INTENSITY = 0.01;
public static final double MIN_EMITTER_INTENSITY = 0;

/**
* Maximum emitter intensity.
*/
public static final double MAX_EMITTER_INTENSITY = 1000;

/**
* Default emitter light intensity.
*/
public static final double DEFAULT_EMITTER_LIGHT_INTENSITY = 13;

/**
* Minimum emitter light intensity.
*/
public static final double MIN_EMITTER_LIGHT_INTENSITY = 0;

/**
* Maximum emitter light intensity.
*/
public static final double MAX_EMITTER_LIGHT_INTENSITY = 50;

/**
* Default apparent emitter brightness.
*/
public static final double DEFAULT_APPARENT_EMITTER_BRIGHTNESS = 1;

/**
* Minimum apparent emitter brightness.
*/
public static final double MIN_APPARENT_EMITTER_BRIGHTNESS = 0;

/**
* Maximum apparent emitter brightness.
*/
public static final double MAX_APPARENT_EMITTER_BRIGHTNESS = 50;

/**
* Default exposure.
*/
Expand Down Expand Up @@ -195,6 +225,8 @@ public class Scene implements JsonSerializable, Refreshable {
protected boolean saveSnapshots = false;
protected boolean emittersEnabled = DEFAULT_EMITTERS_ENABLED;
protected double emitterIntensity = DEFAULT_EMITTER_INTENSITY;
protected double emitterLightIntensity = DEFAULT_EMITTER_LIGHT_INTENSITY;
protected double apparentEmitterBrightness = DEFAULT_APPARENT_EMITTER_BRIGHTNESS;
protected EmitterSamplingStrategy emitterSamplingStrategy = EmitterSamplingStrategy.NONE;

protected SunSamplingStrategy sunSamplingStrategy = SunSamplingStrategy.FAST;
Expand Down Expand Up @@ -459,6 +491,8 @@ public synchronized void copyState(Scene other, boolean copyChunks) {
sunSamplingStrategy = other.sunSamplingStrategy;
emittersEnabled = other.emittersEnabled;
emitterIntensity = other.emitterIntensity;
emitterLightIntensity = other.emitterLightIntensity;
apparentEmitterBrightness = other.apparentEmitterBrightness;
emitterSamplingStrategy = other.emitterSamplingStrategy;
preventNormalEmitterWithSampling = other.preventNormalEmitterWithSampling;
transparentSky = other.transparentSky;
Expand Down Expand Up @@ -1882,6 +1916,36 @@ public void setEmitterIntensity(double value) {
refresh();
}

/**
* @return The current emitter light intensity
*/
public double getEmitterLightIntensity() {
return emitterLightIntensity;
}

/**
* Set the emitter light intensity.
*/
public void setEmitterLightIntensity(double value) {
emitterLightIntensity = value;
refresh();
}

/**
* @return The current apparent emitter brightness
*/
public double getApparentEmitterBrightness() {
return apparentEmitterBrightness;
}

/**
* Set the apparent emitter brightness.
*/
public void setApparentEmitterBrightness(double value) {
apparentEmitterBrightness = value;
refresh();
}

/**
* Set the transparent sky option.
*/
Expand Down Expand Up @@ -2729,6 +2793,8 @@ public void setUseCustomWaterColor(boolean value) {
json.add("saveSnapshots", saveSnapshots);
json.add("emittersEnabled", emittersEnabled);
json.add("emitterIntensity", emitterIntensity);
json.add("emitterLightIntensity", emitterLightIntensity);
json.add("apparentEmitterBrightness", apparentEmitterBrightness);
json.add("sunSamplingStrategy", sunSamplingStrategy.getId());
json.add("stillWater", stillWater);
json.add("waterOpacity", waterOpacity);
Expand Down Expand Up @@ -3011,7 +3077,15 @@ public synchronized void importFromJson(JsonObject json) {
dumpFrequency = json.get("dumpFrequency").intValue(dumpFrequency);
saveSnapshots = json.get("saveSnapshots").boolValue(saveSnapshots);
emittersEnabled = json.get("emittersEnabled").boolValue(emittersEnabled);
emitterIntensity = json.get("emitterIntensity").doubleValue(emitterIntensity);
if (json.get("emitterLightIntensity").isUnknown()) {
// load equivalent values in scenes saved in older versions.
emitterIntensity = 1;
emitterLightIntensity = json.get("emitterIntensity").doubleValue(emitterIntensity);
} else {
emitterIntensity = json.get("emitterIntensity").doubleValue(emitterIntensity);
emitterLightIntensity = json.get("emitterLightIntensity").doubleValue(emitterLightIntensity);
}
apparentEmitterBrightness = json.get("apparentEmitterBrightness").doubleValue(apparentEmitterBrightness);

if (json.get("sunSamplingStrategy").isUnknown()) {
boolean sunSampling = json.get("sunEnabled").boolValue(false);
Expand Down Expand Up @@ -3321,6 +3395,16 @@ public void setEmittance(String materialName, float value) {
refresh(ResetReason.MATERIALS_CHANGED);
}

/**
* Modifies the apparent brightness property for the given material.
*/
public void setApparentBrightness(String materialName, float value) {
JsonObject material = materials.getOrDefault(materialName, new JsonObject()).object();
material.set("apparentBrightnessModifier", Json.of(value));
materials.put(materialName, material);
refresh(ResetReason.MATERIALS_CHANGED);
}

/**
* Modifies the specular coefficient property for the given material.
*/
Expand Down
22 changes: 20 additions & 2 deletions chunky/src/java/se/llbit/chunky/ui/render/tabs/LightingTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public class LightingTab extends ScrollPane implements RenderControlsTab, Initia
@FXML private DoubleAdjuster skyIntensity;
@FXML private DoubleAdjuster apparentSkyBrightness;
@FXML private DoubleAdjuster emitterIntensity;
@FXML private DoubleAdjuster emitterLightIntensity;
@FXML private DoubleAdjuster apparentEmitterBrightness;
@FXML private DoubleAdjuster sunIntensity;
@FXML private CheckBox drawSun;
@FXML private ComboBox<SunSamplingStrategy> sunSamplingStrategy;
Expand Down Expand Up @@ -103,13 +105,27 @@ public LightingTab() throws IOException {
enableEmitters.selectedProperty().addListener(
(observable, oldValue, newValue) -> scene.setEmittersEnabled(newValue));

emitterIntensity.setName("Emitter intensity");
emitterIntensity.setTooltip("Modifies the intensity of emitter light.");
emitterIntensity.setName("Emitter brightness");
emitterIntensity.setTooltip("Changes the brightness of emitters.");
emitterIntensity.setRange(Scene.MIN_EMITTER_INTENSITY, Scene.MAX_EMITTER_INTENSITY);
emitterIntensity.makeLogarithmic();
emitterIntensity.clampMin();
emitterIntensity.onValueChange(value -> scene.setEmitterIntensity(value));

emitterLightIntensity.setName("Emitter light intensity modifier");
emitterLightIntensity.setTooltip("Modifies the intensity of the light emitted by emitters.");
emitterLightIntensity.setRange(Scene.MIN_EMITTER_LIGHT_INTENSITY, Scene.MAX_EMITTER_LIGHT_INTENSITY);
emitterLightIntensity.makeLogarithmic();
emitterLightIntensity.clampMin();
emitterLightIntensity.onValueChange(value -> scene.setEmitterLightIntensity(value));

apparentEmitterBrightness.setName("Apparent emitter brightness modifier");
apparentEmitterBrightness.setTooltip("Modifies the apparent brightness of emitters.");
apparentEmitterBrightness.setRange(Scene.MIN_APPARENT_EMITTER_BRIGHTNESS, Scene.MAX_APPARENT_EMITTER_BRIGHTNESS);
apparentEmitterBrightness.makeLogarithmic();
apparentEmitterBrightness.clampMin();
apparentEmitterBrightness.onValueChange(value -> scene.setApparentEmitterBrightness(value));

emitterSamplingStrategy.getItems().addAll(EmitterSamplingStrategy.values());
emitterSamplingStrategy.getSelectionModel().selectedItemProperty()
.addListener((observable, oldvalue, newvalue) -> {
Expand Down Expand Up @@ -194,6 +210,8 @@ public void setController(RenderControlsFxController controller) {
skyIntensity.set(scene.sky().getSkyLight());
apparentSkyBrightness.set(scene.sky().getApparentSkyLight());
emitterIntensity.set(scene.getEmitterIntensity());
emitterLightIntensity.set(scene.getEmitterLightIntensity());
apparentEmitterBrightness.set(scene.getApparentEmitterBrightness());
sunIntensity.set(scene.sun().getIntensity());
sunLuminosity.set(scene.sun().getLuminosity());
apparentSunBrightness.set(scene.sun().getApparentBrightness());
Expand Down
17 changes: 16 additions & 1 deletion chunky/src/java/se/llbit/chunky/ui/render/tabs/MaterialsTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class MaterialsTab extends HBox implements RenderControlsTab, Initializab
private Scene scene;

private final DoubleAdjuster emittance = new DoubleAdjuster();
private final DoubleAdjuster apparentBrightnessModifier = new DoubleAdjuster();
private final DoubleAdjuster specular = new DoubleAdjuster();
private final DoubleAdjuster ior = new DoubleAdjuster();
private final DoubleAdjuster perceptualSmoothness = new DoubleAdjuster();
Expand All @@ -60,9 +61,15 @@ public MaterialsTab() {
emittance.setName("Emittance");
emittance.setRange(0, 100);
emittance.setTooltip("Intensity of the light emitted from the selected material.");
emittance.clampMin();
apparentBrightnessModifier.setName("Apparent brightness modifier");
apparentBrightnessModifier.setRange(0, 100);
apparentBrightnessModifier.setTooltip("Controls the ratio between the selected material's apparent texture brightness and its actual light output.");
apparentBrightnessModifier.clampMin();
specular.setName("Specular");
specular.setRange(0, 1);
specular.setTooltip("Reflectivity of the selected material.");
specular.clampBoth();
ior.setName("IoR");
ior.setRange(0, 5);
ior.setTooltip("Index of Refraction of the selected material.");
Expand All @@ -72,6 +79,7 @@ public MaterialsTab() {
metalness.setName("Metalness");
metalness.setRange(0, 1);
metalness.setTooltip("Metalness (texture-tinted reflectivity) of the selected material.");
metalness.clampBoth();
ObservableList<String> blockIds = FXCollections.observableArrayList();
blockIds.addAll(MaterialStore.collections.keySet());
blockIds.addAll(ExtraMaterials.idMap.keySet());
Expand All @@ -87,7 +95,7 @@ public MaterialsTab() {
settings.setSpacing(10);
settings.getChildren().addAll(
new Label("Material Properties"),
emittance, specular, perceptualSmoothness, ior, metalness,
emittance, apparentBrightnessModifier, specular, perceptualSmoothness, ior, metalness,
new Label("(set to zero to disable)"));
setPadding(new Insets(10));
setSpacing(15);
Expand All @@ -113,19 +121,22 @@ private void updateSelectedMaterial(String materialName) {
boolean materialExists = false;
if (MaterialStore.collections.containsKey(materialName)) {
double emAcc = 0;
double apparentBrightnessAcc = 0;
double specAcc = 0;
double iorAcc = 0;
double perceptualSmoothnessAcc = 0;
double metalnessAcc = 0;
Collection<Block> blocks = MaterialStore.collections.get(materialName);
for (Block block : blocks) {
emAcc += block.emittance;
apparentBrightnessAcc += block.apparentBrightnessModifier;
specAcc += block.specular;
iorAcc += block.ior;
perceptualSmoothnessAcc += block.getPerceptualSmoothness();
metalnessAcc += block.metalness;
}
emittance.set(emAcc / blocks.size());
apparentBrightnessModifier.set(apparentBrightnessAcc / blocks.size());
specular.set(specAcc / blocks.size());
ior.set(iorAcc / blocks.size());
perceptualSmoothness.set(perceptualSmoothnessAcc / blocks.size());
Expand All @@ -135,6 +146,7 @@ private void updateSelectedMaterial(String materialName) {
Material material = ExtraMaterials.idMap.get(materialName);
if (material != null) {
emittance.set(material.emittance);
apparentBrightnessModifier.set(material.apparentBrightnessModifier);
specular.set(material.specular);
ior.set(material.ior);
perceptualSmoothness.set(material.getPerceptualSmoothness());
Expand All @@ -145,6 +157,7 @@ private void updateSelectedMaterial(String materialName) {
Block block = new MinecraftBlock(materialName.substring(10), Texture.air);
scene.getPalette().applyMaterial(block);
emittance.set(block.emittance);
apparentBrightnessModifier.set(block.apparentBrightnessModifier);
specular.set(block.specular);
ior.set(block.ior);
perceptualSmoothness.set(block.getPerceptualSmoothness());
Expand All @@ -153,12 +166,14 @@ private void updateSelectedMaterial(String materialName) {
}
if (materialExists) {
emittance.onValueChange(value -> scene.setEmittance(materialName, value.floatValue()));
apparentBrightnessModifier.onValueChange(value -> scene.setApparentBrightness(materialName, value.floatValue()));
specular.onValueChange(value -> scene.setSpecular(materialName, value.floatValue()));
ior.onValueChange(value -> scene.setIor(materialName, value.floatValue()));
perceptualSmoothness.onValueChange(value -> scene.setPerceptualSmoothness(materialName, value.floatValue()));
metalness.onValueChange(value -> scene.setMetalness(materialName, value.floatValue()));
} else {
emittance.onValueChange(value -> {});
apparentBrightnessModifier.onValueChange(value -> {});
specular.onValueChange(value -> {});
ior.onValueChange(value -> {});
perceptualSmoothness.onValueChange(value -> {});
Expand Down
Loading