-
Notifications
You must be signed in to change notification settings - Fork 0
DevLog
Date: 2025-01-27
Let’s talk a bit about the textures I’m currently using.
To keep things simple, I decided to create all block textures procedurally. For this, I’m using a texture atlas. Each block type is assigned a base color, and each block gets its own row in the atlas. Within each row, six different brightness levels of the block texture are generated. This allows each face of a block to be assigned a specific texture, simulating directional lighting.
Additionally, there’s an option to render an informational overlay that displays the row, column, and block type. This makes debugging UV coordinates and face-to-texture assignments much easier.
There’s also an option to add a 16x16 noise overlay to the textures, which adds a bit more detail. For now, this means I don’t need to worry too much about designing textures; I simply choose a color.
The texture size is flexible, and I’m currently using 128px x 128px for each block texture, with the noise overlay being 16x16 and scaled accordingly. The following image shows an example scene with noise and the informational overlay enabled.
In the next image, we can see a scene without the noise overlay.
The brightness variations of the individual block textures are created using an alpha overlay:
// Fake light
g2d.setColor(new Color(0, 0, 0, 255 / 6 * col));
g2d.fillRect(baseX, baseY, tileSize, tileSize);
To make things visually more appealing, I’m planning to experiment with hue shifting for the shadows today. Is it necessary? Not really, but it’s a nice-to-have feature, and it’s fun—so why not? Let’s see where this goes!
Initial Approach
We start with a simple approach: shifting the hue values by a specific degree for each column. Currently, the hue is shifted by 15 degrees per column.
private Color shiftHue(Color color, float shiftDegrees) {
float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
float shiftedHue = (hsb[0] + shiftDegrees / 360f) % 1f;
return Color.getHSBColor(shiftedHue, hsb[1], hsb[2]);
}
The following image shows the result. Compared to the original textures without hue shifting, there is already a significant visual difference.
This approach is effective but still quite basic, as we are only shifting in one direction. Anyone familiar with the technique of hue shifting, commonly used in pixel art, knows that shifting typically occurs in both directions from the base color. This depends on whether the color is being adjusted for highlights/bright areas or for darker/shadowed areas. Additionally, saturation and brightness are often incorporated into the process for more nuanced results.
We currently use six steps, one for each side of the cube:
0 1 2 3 4 5
This means that our base color lies somewhere in between, ideally in the center. For columns 0, 1, 2, the hue is shifted toward yellow on the color wheel, and for columns 3, 4, 5, the hue is shifted toward purple.
0 1 2 <- Hue towards yellow (base color) Hue towards purple -> 3 4 5
The final image demonstrates hue shifting in two directions with adjustments to both brightness and saturation. While this is still in the experimental phase and requires further fine-tuning and customization, it's a promising start and was an enjoyable process.
Date: 2025-01-27
Minecraft has always been more than just a game to me—it was a creative playground where I could build, experiment, and push the limits of what’s possible. While the game’s sandbox kept me hooked, I quickly found myself drawn to coding plugins and tools that could enhance the building experience. I became part of two large build teams, collaborating on massive projects and learning how to optimize workflows in the builder scene.
Over time, procedural content creation became my obsession. I was fascinated by how automation could speed up map generation and bring complex terrains and structures to life. When I hit limitations in tools like drububu, I didn’t stop—I coded my own voxelizer capable of processing massive OBJ-based terrains, scaling up to 4k maps and beyond. This journey has taught me so much, and I’ve built a personal library of tools, plugins, and knowledge over the years.
Now, I feel it’s time to bring all of this together. My goal is to create a voxel engine and build tool that combines everything I’ve learned—procedural generation, large-scale voxelization, and workflow optimization—to turn ambitious ideas into reality.
Date: 2025-01-24
Today, I continued optimizing the voxel engine and added backface culling to improve rendering performance.
Backface culling is a technique in 3D graphics where polygons (or faces) of an object that are not visible to the camera (i.e., their "back side") are not rendered. This reduces the number of faces processed by the GPU and helps improve performance, especially in complex scenes.
Processing does not provide direct access to this feature, so I utilized the PGL
graphics context to implement it myself. To make it reusable, I added two new methods to my custom graphics context:
void enableFaceCulling();
void disableFaceCulling();
The Processing-specific implementation looks as follows:
public void enableFaceCulling() {
PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
pgl.pgl.frontFace(PGL.CCW); // Counter-clockwise winding order for front faces
pgl.pgl.enable(PGL.CULL_FACE); // Enable face culling
pgl.pgl.cullFace(PGL.BACK); // Cull back faces
}
public void disableFaceCulling() {
PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
pgl.pgl.disable(PGL.CULL_FACE); // Disable face culling
}
By enabling face culling, only the outer faces of the objects are rendered, significantly reducing the number of rendered polygons. This is especially useful in voxel-based systems where many internal faces are hidden and unnecessary for rendering.
https://forum.processing.org/one/topic/disable-backface-culling.html
Date: 2025-01-24