Skip to content

Commit

Permalink
Improve color serialization in scene files, remove black sky mode, an…
Browse files Browse the repository at this point in the history
…d drop redundant camera preset name. (#1784)

* Update inconsistent sky gradient color serialization.

* Remove redundant black sky mode.

* Drop the redundant camera preset name from the scene json file.

* Use consistent color serialization and parsing for fog, sky and sun.

* Use consistent color format for beacon beam color too.

* Allow changing the color serialization format to hex.

* Serialize custom water color with JsonUtil.

* Bump the scene description file version.
  • Loading branch information
leMaik authored Oct 24, 2024
1 parent eb88139 commit 030bd70
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 99 deletions.
17 changes: 4 additions & 13 deletions chunky/src/java/se/llbit/chunky/renderer/scene/Fog.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import se.llbit.math.Vector3;
import se.llbit.math.Vector4;
import se.llbit.util.JsonSerializable;
import se.llbit.util.JsonUtil;

public final class Fog implements JsonSerializable {
private final Scene scene;
Expand Down Expand Up @@ -213,11 +214,7 @@ private double sampleLayeredScatterOffset(Random random, double y1, double y2, d
jsonLayers.add(jsonLayer);
}
fogObj.add("layers", jsonLayers);
JsonObject colorObj = new JsonObject();
colorObj.add("red", fogColor.x);
colorObj.add("green", fogColor.y);
colorObj.add("blue", fogColor.z);
fogObj.add("color", colorObj);
fogObj.add("color", JsonUtil.rgbToJson(fogColor));
fogObj.add("fastFog", fastFog);
return fogObj;
}
Expand All @@ -231,10 +228,7 @@ public void importFromJson(JsonObject json, Scene scene) {
o.get("breadth").doubleValue(0),
o.get("density").doubleValue(0),
scene)).collect(Collectors.toCollection(ArrayList<FogLayer>::new));
JsonObject colorObj = json.get("color").object();
fogColor.x = colorObj.get("red").doubleValue(fogColor.x);
fogColor.y = colorObj.get("green").doubleValue(fogColor.y);
fogColor.z = colorObj.get("blue").doubleValue(fogColor.z);
JsonUtil.rgbFromJson(json.get("color"), fogColor);
fastFog = json.get("fastFog").boolValue(fastFog);
}

Expand All @@ -243,10 +237,7 @@ public void importFromLegacy(JsonObject json) {
uniformDensity = json.get("fogDensity").doubleValue(uniformDensity);
skyFogDensity = json.get("skyFogDensity").doubleValue(skyFogDensity);
layers = new ArrayList<>(0);
JsonObject colorObj = json.get("fogColor").object();
fogColor.x = colorObj.get("red").doubleValue(fogColor.x);
fogColor.y = colorObj.get("green").doubleValue(fogColor.y);
fogColor.z = colorObj.get("blue").doubleValue(fogColor.z);
JsonUtil.rgbFromJson(json.get("fogColor"), fogColor);
fastFog = json.get("fastFog").boolValue(fastFog);
}

Expand Down
25 changes: 13 additions & 12 deletions chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public class Scene implements JsonSerializable, Refreshable {
public static final String EXTENSION = ".json";

/** The current Scene Description Format (SDF) version. */
public static final int SDF_VERSION = 9;
public static final int SDF_VERSION = 10;

protected static final double fSubSurface = 0.3;

Expand Down Expand Up @@ -2568,11 +2568,7 @@ public void setUseCustomWaterColor(boolean value) {
json.add("waterVisibility", waterVisibility);
json.add("useCustomWaterColor", useCustomWaterColor);
if (useCustomWaterColor) {
JsonObject colorObj = new JsonObject();
colorObj.add("red", waterColor.x);
colorObj.add("green", waterColor.y);
colorObj.add("blue", waterColor.z);
json.add("waterColor", colorObj);
json.add("waterColor", JsonUtil.rgbToJson(waterColor));
}
currentWaterShader.save(json);
json.add("fog", fog.toJson());
Expand All @@ -2595,7 +2591,11 @@ public void setUseCustomWaterColor(boolean value) {
json.add("camera", camera.toJson());
json.add("sun", sun.toJson());
json.add("sky", sky.toJson());
json.add("cameraPresets", cameraPresets.copy());
JsonObject cameraPresets = this.cameraPresets.copy();
for (JsonMember item : cameraPresets.members) {
item.value.object().remove("name");
}
json.add("cameraPresets", cameraPresets);
JsonArray chunkList = new JsonArray();
for (ChunkPosition pos : chunks) {
JsonArray chunk = new JsonArray();
Expand Down Expand Up @@ -2873,10 +2873,7 @@ else if(waterShader.equals("SIMPLEX"))
waterVisibility = json.get("waterVisibility").doubleValue(waterVisibility);
useCustomWaterColor = json.get("useCustomWaterColor").boolValue(useCustomWaterColor);
if (useCustomWaterColor) {
JsonObject colorObj = json.get("waterColor").object();
waterColor.x = colorObj.get("red").doubleValue(waterColor.x);
waterColor.y = colorObj.get("green").doubleValue(waterColor.y);
waterColor.z = colorObj.get("blue").doubleValue(waterColor.z);
JsonUtil.rgbFromJson(json.get("waterColor"), waterColor);
}
biomeColors = json.get("biomeColorsEnabled").boolValue(biomeColors);
transparentSky = json.get("transparentSky").boolValue(transparentSky);
Expand Down Expand Up @@ -2923,7 +2920,11 @@ else if(waterShader.equals("SIMPLEX"))
}

if (json.get("cameraPresets").isObject()) {
cameraPresets = json.get("cameraPresets").object();
JsonObject cameraPresets = json.get("cameraPresets").object();
for (JsonMember member : cameraPresets.members) {
member.value.object().set("name", new JsonString(member.name));
}
this.cameraPresets = cameraPresets;
}

// Current SPP and render time are read after loading
Expand Down
51 changes: 23 additions & 28 deletions chunky/src/java/se/llbit/chunky/renderer/scene/sky/Sky.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,7 @@ public enum SkyMode {
SKYMAP_ANGULAR("Skymap (angular)"),

/** Skybox. */
SKYBOX("Skybox"),

/** A completely black sky, useful for rendering an emitter-only pass. */
BLACK("Black");
SKYBOX("Skybox");

private String name;

Expand Down Expand Up @@ -353,10 +350,6 @@ public void getSkyDiffuseColorInner(Ray ray) {
}
break;
}
case BLACK: {
ray.color.set(0, 0, 0, 1);
break;
}
}
}

Expand Down Expand Up @@ -641,11 +634,7 @@ public void setSkyCacheResolution(int resolution) {
// Always save gradient.
sky.add("gradient", gradientJson(gradient));

JsonObject colorObj = new JsonObject();
colorObj.add("red", color.x);
colorObj.add("green", color.y);
colorObj.add("blue", color.z);
sky.add("color", colorObj);
sky.add("color", JsonUtil.rgbToJson(color));

switch (mode) {
case SKYMAP_EQUIRECTANGULAR:
Expand Down Expand Up @@ -688,12 +677,17 @@ public void importFromJson(JsonObject json) {
skyExposure = json.get("skyExposure").doubleValue(skyExposure);
skyLightModifier = json.get("skyLight").doubleValue(skyLightModifier);
apparentSkyLightModifier = json.get("apparentSkyLight").doubleValue(apparentSkyLightModifier);
if (!(json.get("mode").stringValue(mode.name()).equals("SKYMAP_PANORAMIC") || json.get("mode").stringValue(mode.name()).equals("SKYMAP_SPHERICAL"))) {
mode = SkyMode.get(json.get("mode").stringValue(mode.name()));
if (json.get("mode").stringValue(mode.name()).equals("BLACK")) {
mode = SkyMode.SOLID_COLOR;
color.x = 0;
color.y = 0;
color.z = 0;
} else if (json.get("mode").stringValue(mode.name()).equals("SKYMAP_PANORAMIC")) {
mode = SkyMode.SKYMAP_EQUIRECTANGULAR;
} else if (json.get("mode").stringValue(mode.name()).equals("SKYMAP_SPHERICAL")) {
mode = SkyMode.SKYMAP_ANGULAR;
} else {
mode = SkyMode.get(json.get("mode").stringValue(mode.name()));
}
horizonOffset = json.get("horizonOffset").doubleValue(horizonOffset);
cloudsEnabled = json.get("cloudsEnabled").boolValue(cloudsEnabled);
Expand All @@ -709,15 +703,7 @@ public void importFromJson(JsonObject json) {
}
}

if (json.get("color").isObject()) {
JsonObject colorObj = json.get("color").object();
color.x = colorObj.get("red").doubleValue(1);
color.y = colorObj.get("green").doubleValue(1);
color.z = colorObj.get("blue").doubleValue(1);
} else {
// Maintain backwards-compatibility with scenes saved in older Chunky versions
color.set(JsonUtil.vec3FromJsonArray(json.get("color")));
}
JsonUtil.rgbFromJson(json.get("color"), color);

switch (mode) {
case SKYMAP_EQUIRECTANGULAR:
Expand Down Expand Up @@ -804,7 +790,11 @@ public static JsonArray gradientJson(Collection<Vector4> gradient) {
JsonArray array = new JsonArray();
for (Vector4 stop : gradient) {
JsonObject obj = new JsonObject();
obj.add("rgb", ColorUtil.toString(stop.x, stop.y, stop.z));
JsonObject colorObj = new JsonObject();
colorObj.add("red", stop.x);
colorObj.add("green", stop.y);
colorObj.add("blue", stop.z);
obj.add("color", JsonUtil.rgbToJson(stop.toVec3()));
obj.add("pos", stop.w);
array.add(obj);
}
Expand All @@ -820,13 +810,18 @@ public static List<Vector4> gradientFromJson(JsonArray array) {
JsonObject obj = array.get(i).object();
Vector3 color = new Vector3();
try {
ColorUtil.fromString(obj.get("rgb").stringValue(""), 16, color);
if (obj.get("color").isUnknown()) {
// support for old scene files (2.5.0 snapshot phase)
ColorUtil.fromString(obj.get("rgb").stringValue(""), 16, color);
} else {
JsonUtil.rgbFromJson(obj.get("color"), color);
}
Vector4 stop =
new Vector4(color.x, color.y, color.z, obj.get("pos").doubleValue(Double.NaN));
new Vector4(color.x, color.y, color.z, obj.get("pos").doubleValue(Double.NaN));
if (!Double.isNaN(stop.w)) {
gradient.add(stop);
}
} catch (NumberFormatException e) {
} catch (IllegalArgumentException e) {
// Ignored.
}
}
Expand Down
27 changes: 7 additions & 20 deletions chunky/src/java/se/llbit/chunky/renderer/scene/sky/Sun.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import se.llbit.math.Ray;
import se.llbit.math.Vector3;
import se.llbit.util.JsonSerializable;
import se.llbit.util.JsonUtil;

/**
* Sun model for ray tracing.
Expand Down Expand Up @@ -501,16 +502,8 @@ public void getRandomSunDirection(Ray reflected, Random random) {
sun.add("apparentBrightness", apparentBrightness);
sun.add("radius", radius);
sun.add("modifySunTexture", enableTextureModification);
JsonObject colorObj = new JsonObject();
colorObj.add("red", color.x);
colorObj.add("green", color.y);
colorObj.add("blue", color.z);
sun.add("color", colorObj);
JsonObject apparentColorObj = new JsonObject();
apparentColorObj.add("red", apparentColor.x);
apparentColorObj.add("green", apparentColor.y);
apparentColorObj.add("blue", apparentColor.z);
sun.add("apparentColor", apparentColorObj);
sun.add("color", JsonUtil.rgbToJson(color));
sun.add("apparentColor", JsonUtil.rgbToJson(apparentColor));
JsonObject importanceSamplingObj = new JsonObject();
importanceSamplingObj.add("chance", importanceSampleChance);
importanceSamplingObj.add("radius", importanceSampleRadius);
Expand All @@ -528,18 +521,12 @@ public void importFromJson(JsonObject json) {
radius = json.get("radius").doubleValue(radius);
enableTextureModification = json.get("modifySunTexture").boolValue(enableTextureModification);

if (json.get("color").isObject()) {
JsonObject colorObj = json.get("color").object();
color.x = colorObj.get("red").doubleValue(1);
color.y = colorObj.get("green").doubleValue(1);
color.z = colorObj.get("blue").doubleValue(1);
if (!json.get("color").isUnknown()) {
JsonUtil.rgbFromJson(json.get("color"), color);
}

if (json.get("apparentColor").isObject()) {
JsonObject apparentColorObj = json.get("apparentColor").object();
apparentColor.x = apparentColorObj.get("red").doubleValue(1);
apparentColor.y = apparentColorObj.get("green").doubleValue(1);
apparentColor.z = apparentColorObj.get("blue").doubleValue(1);
if (!json.get("apparentColor").isUnknown()) {
JsonUtil.rgbFromJson(json.get("apparentColor"), apparentColor);
}

if(json.get("importanceSampling").isObject()) {
Expand Down
3 changes: 0 additions & 3 deletions chunky/src/java/se/llbit/chunky/ui/render/tabs/SkyTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,6 @@ public SimulatedSky fromString(String string) {
case GRADIENT:
skyModeSettings.getChildren().setAll(gradientEditor);
break;
case BLACK:
skyModeSettings.getChildren().setAll(new Label("Selected mode has no settings."));
break;
case SKYBOX:
skyModeSettings.getChildren().setAll(skyboxSettings);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@

import se.llbit.chunky.resources.Texture;
import se.llbit.chunky.world.Material;
import se.llbit.json.JsonNumber;
import se.llbit.json.JsonObject;
import se.llbit.json.JsonValue;
import se.llbit.math.ColorUtil;
import se.llbit.math.Ray;
import se.llbit.math.Vector3;
import se.llbit.util.JsonUtil;

public class BeaconBeamMaterial extends Material {

public static final int DEFAULT_COLOR = 0xF9FFFE;
private int color;
private float[] beamColor = new float[4];
private float[] beamColor = new float[3];

public BeaconBeamMaterial(int color) {
super("beacon_beam", Texture.beaconBeam);
Expand All @@ -20,7 +24,7 @@ public BeaconBeamMaterial(int color) {

public void updateColor(int color) {
this.color = color;
ColorUtil.getRGBAComponents(color, beamColor);
ColorUtil.getRGBComponents(color, beamColor);
ColorUtil.toLinear(beamColor);
}

Expand Down Expand Up @@ -53,7 +57,13 @@ public float[] getColor(double u, double v) {
@Override
public void loadMaterialProperties(JsonObject json) {
super.loadMaterialProperties(json);
updateColor(json.get("color").asInt(DEFAULT_COLOR));
JsonValue color = json.get("color");
if (color instanceof JsonNumber) {
// compatibility with older scene files
updateColor(color.asInt(DEFAULT_COLOR));
} else {
updateColor(ColorUtil.getRGB(JsonUtil.rgbFromJson(color)));
}
}

public void saveMaterialProperties(JsonObject json) {
Expand All @@ -62,6 +72,8 @@ public void saveMaterialProperties(JsonObject json) {
json.add("emittance", this.emittance);
json.add("roughness", this.roughness);
json.add("metalness", this.metalness);
json.add("color", this.color);
Vector3 color = new Vector3();
ColorUtil.getRGBComponents(this.color, color);
json.add("color", JsonUtil.rgbToJson(color));
}
}
33 changes: 31 additions & 2 deletions chunky/src/java/se/llbit/math/ColorUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@ public static void getRGBComponents(int irgb, Vector4 v) {
v.z = (0xFF & irgb) / 255.f;
}

/**
* Get the RGB color components from an INT RGB value.
*/
public static void getRGBComponents(int irgb, Vector3 v) {
v.x = (0xFF & (irgb >> 16)) / 255.f;
v.y = (0xFF & (irgb >> 8)) / 255.f;
v.z = (0xFF & irgb) / 255.f;
}

/**
* Get the RGB color components from an INT RGB value.
*/
Expand Down Expand Up @@ -162,8 +171,10 @@ public static void getRGBAComponents(int irgb, Vector4 v) {
}

/**
* Get the RGBA color components from an INT ARGB value.
* Get the RGB color components from an INT RGB value.
* @deprecated Use {@link #getRGBComponents(int, Vector3)} instead, this method name is incorrect.
*/
@Deprecated
public static void getRGBAComponents(int irgb, Vector3 v) {
v.x = (0xFF & (irgb >> 16)) / 255.f;
v.y = (0xFF & (irgb >> 8)) / 255.f;
Expand Down Expand Up @@ -346,7 +357,25 @@ public static java.awt.Color toAWT(Vector3 color) {
public static void fromString(String text, int radix, Vector3 color)
throws NumberFormatException {
int rgb = Integer.parseInt(text, radix);
ColorUtil.getRGBAComponents(rgb, color);
ColorUtil.getRGBComponents(rgb, color);
}

public static void fromHexString(String hex, Vector3 color) {
if (hex.startsWith("#")) {
hex = hex.substring(1);
}

if (hex.length() == 3) {
hex = "" + hex.charAt(0) + hex.charAt(0)
+ hex.charAt(1) + hex.charAt(1)
+ hex.charAt(2) + hex.charAt(2);
}

if (hex.length() != 6) {
throw new IllegalArgumentException("Expected three or six digit hex color");
}

fromString(hex, 16, color);
}

public static javafx.scene.paint.Color toFx(Vector3 color) {
Expand Down
Loading

0 comments on commit 030bd70

Please sign in to comment.