Sign in

Karl

@hexaquo.at
1.4K followers 970 following 213 posts

Researcher, teacher and activist somewhere at the intersection of landscape perception, graphics programming, open source, and climate change. Working on VR landscape visualization with Godot. Maintaining Geodot: github.com/boku-ilen/geodot-plugin

PostsRepliesMedia
Karl @hexaquo.at · 12/04/2026
Did you know you can set up a scene and render it to a texture without any nodes in #Godot, by directly using the RenderingServer? We automatically generate billboard sprites for meshes this way. There's not much info about the RenderingServer online, so I wrote about it: hexaquo.at/pages/using-...
a 3D tree asset on the left, with an arrow pointing to spritesheets on the right. The spritesheets contain 2 albedo sprites (front and side) and 2 normal sprites (also front and side).
324343
Karl @hexaquo.at · 24/03/2026
Implemented a variable-density Poisson disk sampler as a C++ GDExtension for #Godot: github.com/boku-ilen/go... It generates random points with a variable density, based on e.g. an image. should be very useful for scattering vegetation. based on this article: www.vertexfragment.com/ramblings/va...
the Godot icon, but it is depicted via randomly placed white dots with variable density. a higher density of dots causes the image to look brighter there, thus making the general contrast of the Godot robot head visible.
3646
Karl @hexaquo.at · 19/02/2026
Orchard #godot #gamedev
Screenshot of a 3D landscape in Godot. The camera stands in the middle of a row of approximately 2m tall fruit apple trees; the rows extend into the far distance, and the sun is low, making them cast long shadows.Screenshot of a 3D landscape in Godot. The camera looks at the sun, with layers of backlit apple trees in front of it.Screenshot of a 3D landscape in Godot. Apple trees again, with a higher sun, but more clouds.
4494
Karl @hexaquo.at · 13/01/2026
#godot #gamedev
Screenshot of a landscape rendered in Godot. View into a hilly landscape from a field track next to a sunflower field, with a small tree in the middle. The sun is fairly low.View up into the sky with a branch in the foreground and another tree in the distance. The sun is visible and creates some slight lens flares.View into the distance onto an expansive, slightly hilly landscape, with different agricultural fields. A few birds are flying in the distance.View over a field onto a village. The sun is low, creating a golden light.
2404
Karl @hexaquo.at · 08/01/2026
Thanks, yeah feel free to take any code that's useful! I can get some nice anamorphic glare with the right settings; if you also want to stretch the lens flare ghosts, you could probably apply the glare blur filter (streak.glsl in my repo) to the buffer used for the ghosts. (or just warp the UVs)
Screenshot of the Godot editor with the sun producing a strong horizontal anamorphic glare. To the right, the corresponding settings are visible under the "Glare" tab": Streak count 2, attenuation 0.992, samples 6
110
Karl @hexaquo.at · 08/01/2026
110
Karl @hexaquo.at · 08/01/2026
#godot #gamedev
3555
Karl @hexaquo.at · 29/12/2025
Lens Flare update: exposed all configurable parameters now. There's probably still a lot of potential for performance optimization, but I'd say it's somewhat usable :) You can check it out here, should work in any project (though requires some HDR care): github.com/kb173/godot-... #Godot #gamedev
1162
Karl @hexaquo.at · 23/12/2025
If you want your #Godot game to look like Battlefield 3, I got you
Screenshot of a Godot scene with a blue sky and the sun visible through a large window in a concrete structure. The sun (and a reflection of the sun on the concrete) have a strong glare with 6 light streaks going outwards. There is also a lens flare effect with chromatic aberration, and the bloom uses a lens dirt texture to create large circular patterns of higher brightness (like dust on a lens).
0211
Karl @hexaquo.at · 18/12/2025
040
Karl @hexaquo.at · 18/12/2025
More work on procedural lens flares in #Godot. If you want to have a look at the (still very messy!) code: github.com/kb173/godot-... Outline of how it works: 1. Clip bright spots from the rendered image 2. Warp these spots to create ghosts and a halo 3. Blur 4. Overlay based on a dirt texture
5306
Karl @hexaquo.at · 16/12/2025
Finally learning CompositorEffects #Godot Lens flare based on this blog: john-chapman-graphics.blogspot.com/2013/02/pseu...
091
Karl @hexaquo.at · 26/11/2025
I often talk about bent normals for billboards, and I keep having to mention the "if (!FRONT_FACING) NORMAL = -NORMAL" workaround for correct backface lighting. I realized I could fix that myself, so I opened a PR for an intuitive material option and render_mode: github.com/godotengine/... #Godot
Left: a plane and a sphere with billboards scattered on it. A text below says "Default", and some billboards are noticeably darker than the others.
Right: the same plane and sphere with billboards, but with smooth lighting without the dark billboards. The text below says "Keep Backface Normals".Schematic drawing. Left, titled "Original normals, matching geometry": a plane with an arrow pointing orthogonally outwards to the right, saying "original normal", and an arrow pointing into the opposite direction, saying "default behavior: flipped normal". Right, titled "Custom normals, do not match geometry": a plane with an arrow pointing straight up, parallel to the plane, saying "original normal", and the same arrow again, saying "intended backface normal". Another arrow points straight down, saying "default behavior: flipped normal".
0150
Karl @hexaquo.at · 10/11/2025
on my way to #GodotFest! hope to meet some of you there :)
Laptop on a desk in a train next to a window. A presentation is being edited on the laptop. Outside the window are houses and hills lit by sunset.View out of the train window. A church can be seen on a nearby hill, which is otherwise covered by forest.
060
Karl @hexaquo.at · 21/10/2025
🔜 #GodotFest Want to see these slides (and many more) live? Then join my presentation on November 11th at GodotFest in Munich :) #godot #gamedev
Presentation slide with the text "Plants, Polygons and Pixels: Large-Scale Vegetation Rendering in Godot". The background is a slightly blurred view over a rendered landscape.Presentation slide with the text "Geometry versus Billboards". "Geometry" is bold. On the right, a highly detailed 3D model of a tree is shown, first rendered, then shaded in white to show the intricate geometry.Presentation slide with the text "bend your normals!" and two rendered trees. The tree on the right has a clearer canopy shape due to smoother lighting. An arrow points from the left to the right tree.Presentation slide with the text "Ground-Covering Billboard Clouds" and an image of a rendered landscape. In the right half of the rendering, the plant billboards are rendered as white quads in order to show the geometry.
0579
Karl @hexaquo.at · 04/10/2025
The idea is: make the vertices stick to the camera rather than passing behind it, and use alpha to make these vertices fade out as the camera is moving through the mesh.
Schematic drawing. Left, labeled "before", shows a camera (depicted as a triangle) inside a circle. Right, labeled "after", shows the camera next to a half-circle, the wall of which is right in front of the camera.Screenshot of Godot shader code:

shader_type spatial;

uniform float radius = 2.0;

varying float inside_alpha_factor;

// I think you could get this out of the PROJECTION_MATRIX, but I was too lazy to figure that out
#define CAMERA_NEAR -0.051

void vertex() {
	// Transform vertex from model space into view space
	vec3 view_vertex = (MODELVIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;

	// Calculate a factor which goes from 1.0 (when the camera is in front of the original vertex
	// position, i.e. the vertex is right on the near plane in view space) to 0.0 (when the vertex
	// is radius * 2.0 behind the camera, i.e. we're at the opposite end of the mesh)
	inside_alpha_factor = smoothstep(radius * 2.0, CAMERA_NEAR, view_vertex.z);

	// Stick the vertex right onto the camer's near plane
	view_vertex.z = min(view_vertex.z, CAMERA_NEAR);

	// Transform back to model space and assign to VERTEX
	VERTEX = (inverse(MODELVIEW_MATRIX) * vec4(view_vertex, 1.0)).xyz;
}

void fragment() {
	// Apply the alpha
	ALPHA = inside_alpha_factor;
}
300
Karl @hexaquo.at · 04/10/2025
This got me wondering what would be the easiest way to make meshes appear like a volume when moving through them (using only shaders). This is what I came up with:
110
Karl @hexaquo.at · 25/08/2025
In the visualization project I work on I do something very similar: fade the billboard vegetation into an impostor which is a "Next Pass" of the clipmap terrain - same geometry, but moved up to match the plant height and textured by mashing the local plants' billboard textures together.
Screenshot of a landscape visualization at eye-level. There's a vegetable field underneath the camera; the landscape gently slopes downward into a meadow, until it slopes up again on a sparsely forested hill. A power pole sits on top of the hill and cables go from the left to the right of the image. Three wind turbine rotors can be seen in the distance on the left.Same screenshot as before, but annotated with a line. A text identifies the area above the line as "low LOD impostor" and the area under the line as "high LOD billboards"; the line delineates the approximate border where the high LOD is blended into the low LOD.
100
Karl @hexaquo.at · 25/08/2025
After some theory about LOD, I go over my approach to creating impostors for foliage, sharing some trickery I've learned over time. The result is a plane which behaves very similar to the grass geometry, without actually having any extra geometry. Please reach out if anything is unclear or missing!
Comparison of a mesh (a lion bust) at different levels of detail. The top shows 3 versions of the mesh at descending LOD shaded normally, the bottom shows a wireframe view of the same meshes. In the middle, the triangle count of the meshes is written: the highest LOD contains 33536 triangles, the medium LOD 1047 tris, the lowest LOD 132.Unshaded view of the high-LOD grass geometry next to the grass impostor plane. The screenshot shows off how the impostor has black spots, simulating the ground showing through in-between grass-blades, like the real geometry.A rather noisy screenshot of the impostor grass' normal map (left) and the normals of the real grass geometry (right); they look very similar.Fully shaded view comparing the grass impostor plane (left) to the real grass geometry (right). Although the plane is visibly flat, the colors and shading match the real grass closely.
030
Karl @hexaquo.at · 25/08/2025
Finally finished part 4 of my Godot Grass Rendering Series! In this one, we'll dive deep into level-of-detail and impostors to create an infinite field of grass while keeping the GPU cool: hexaquo.at/pages/grass-... #godot #gamedev
913827
Karl @hexaquo.at · 17/08/2025
New tutorial blog post! Environment and Light in Godot: Setting Up For Photorealistic 3D Graphics hexaquo.at/pages/enviro... I've been meaning to write this for a while, both as an overview over Godot's Environment, and as an entry point to realistic 3D graphics. #godot #gamedev
Demo scene in Godot consisting of a simple concrete structure with two windows walls and a tree. Godot's default environment is applied, making the scene look a bit unimpressive.Screenshot of the same demo scene from the same perspective, but with better lighting and more vivid colors.Same demo scene viewed from a slightly steeper angle, making the ground reflect more light and showing more of the sky through the window.Demo scene viewed from the back, making branches of the tree visible through the concrete window.
1326
Karl @hexaquo.at · 03/08/2025
Vineyards #godot #gamedev
Virtual 3D landscape depicting rows of wine on a gentle hill; the camera is right in front of the rowsView of a virtual vineyard from a distance; there's an acre in the foreground
0176
Karl @hexaquo.at · 26/07/2025
Your game looks interesting, are the facades from street-level images? The roads and rails (which I saw in a screenshot you posted before) look similar to the ones in our landscape visualization.
Screenshot of a realistic-looking 3D scene. The camera is standing on a bridge at eye-level, half of the street and the guardrail and fencing can be seen. In the distance, there is a channel and some buildings.Screenshot of a realistic-looking 3D scene. A railway curves through a steep forest. A high and steep mountain can be seen in the distance.
100
Karl @hexaquo.at · 17/07/2025
Larger asphalt roads do exist as thin 3D objects, but they also alter height and foliage for a banquet and a smooth transition.
Screenshot of an empty gravel pathScreenshot of the same perspective, but there is now a road on the gravel path; the terrain has been slightly altered to accommodate the street, and it's delineated with a guard rail.
000
Karl @hexaquo.at · 17/07/2025
I've been working on our road system, which can now alter both terrain and foliage in real-time. Country lanes like this don't exist as actual objects, they just write into the terrain offset and foliage maps.
Screenshot of the country lane seen in the video, but instead of the detailed country lane, it's only an empty gravel path, since the country lane renderer has been disabled.Screenshot of the country lane seen in the video, in full detail again.
141
Karl @hexaquo.at · 17/07/2025
Afternoon stroll #godot #gamedev
1181
Karl @hexaquo.at · 13/07/2025
Screenshot of the game "Just Grandma and Me": a cartoon drawing in which the eponymous grandma and her grandkid are leaving a garden onto a street, with a house on a hill in the background. There's a text saying " We went to the beach, just Grandma and me.". At the bottom there is a language selection UI (English, French, Spanish, German).
020
Karl @hexaquo.at · 12/07/2025
This article is a great overview on texture padding! I've also done a thread on it here when I found out how important it is for billboard plants; I ended up using GMIC's solidify algorithm, which works well for noisy plant textures made from photographs. Here's the script and the before/after:
Screenshot of the following bash script:

gmic -input $1 -solidify 75 -output out.png
magick $1 -alpha extract alpha.png
magick out.png -alpha on \( +clone -channel a -fx 0 \) +swap alpha.png -composite $1

rm out.png alpha.pngTexture of multiple poppy plants. The background (which is usually transparent) is black, as is default when exporting from image processing software like GIMP.Same texture of multiple poppy plants. The background (which is usually transparent) is now a blur of the nearby non-transparent colors, causing the top of the image to be mostly red (from the poppy flowers) and the middle and bottom to be a mix of greens.
1192
Karl @hexaquo.at · 06/07/2025
I just submitted a talk proposal for GodotFest! This is the session image - can you guess the topic? #godot #gamedev #godotengine
Collage of 4 screenshots of a landscape visualization:
1. overview over agricultural fields with a forest in the back
2. view into an undulating landscape dominated by grass
3. eye-level view of a forest clearing with a variety of plantsin the foreground
4. eye-level view of inside a forest with various trees and a small stream
44010
Karl @hexaquo.at · 28/05/2025
For now, each chunk has 3 possible states: fully detailed (1), simplified geometry (2), and imposter plane (3).
Screenshot of a chunk of grass where each blade bends in a detailed arc.Screenshot of a chunk of grass that looks almost the same as the previous one, but the grass blades don't bend in arcs anymore since they're a single triangle each.Grass chunk at the lowest level of detail, where there is no longer any actual grass geometry, but simply a plane that's shaded as if there was grass on it. The general structure and colors are the same as in the previous screenshots, but it's obviously flat.
110
Karl @hexaquo.at · 27/05/2025
Already working on the promised next part about LOD, especially the imposter plane at the highest distance. This will turn the grass into a fully feasible effect! For once I'm grateful for bsky's ruthless compression for making the LOD transition even more seamless 😉 #godot #gamedev #godotengine
4619
Karl @hexaquo.at · 25/05/2025
New part in the Godot Grass Rendering tutorial series! Part 3 covers wind and interaction: hexaquo.at/pages/grass-... #godot #gamedev #godotengine
39820
Karl @hexaquo.at · 07/04/2025
For example, we use a texture like this for translating large-ground-plane-UVs into as-if-it-were-billboards-UVs. It needs additional tricks since transparency isn't preserved, but it's useful for getting the general structure to look similar.
140
Karl @hexaquo.at · 07/04/2025
This is billboard vegetation, but essentially the same idea. Here we render billboards approximately up to the red line in the second picture, and further than that, it's a plane shaded as if it were multiple billboards. At that distance it's almost impossible to see the difference.
Screenshot of a landscape visualization showing a large, flat field of crops.The same screenshot, but with a red line depicting the border between billboard plants and a large imposter plane.
110
Karl @hexaquo.at · 06/04/2025
I'm writing a multi-part tutorial on grass rendering in Godot. Part 2 covers the basics of full-geometry grass, where each grass blade is a separate 3D object: hexaquo.at/pages/grass-... #godot #gamedev #godotengine
310722
Karl @hexaquo.at · 22/02/2025
Haha, my reaction to these posts reminded me so much of that meme format that I had to make one. Great list, thanks for sharing!
Vince McMahon reaction meme format (something getting better and better) with the texts:

Antichamber in the thumbnail
It's all Bandcamp links
More games I loved but haven't listened to in a long time
The soundtracks I hadn't known are amazing too
000
Karl @hexaquo.at · 14/02/2025
The idea is from @xordev.bsky.social and explained very well here: mini.gmshaders.com/p/gm-shaders... And here's my Godot implementation:
Screenshot of the Godot shader editor showing the code:

vec4 fractal_texture(sampler2D tex, vec2 uv, float depth) {
	// Find the pixel level of detail
	float lod = log(depth);
	
	// Round LOD down
	float lod_floor = floor(lod);
	
	// Compute the fract part for interpolating
	float lod_fract = lod - lod_floor;
	
	// Compute scaled uvs
	vec2 uv1 = uv / exp(lod_floor - 1.0);
	vec2 uv2 = uv / exp(lod_floor + 0.0);
	vec2 uv3 = uv / exp(lod_floor + 1.0);

	// Sample at 3 scales
	vec4 tex0 = texture(tex, uv1);
	vec4 tex1 = texture(tex, uv2);
	vec4 tex2 = texture(tex, uv3);
	
	// Blend samples together
	return (tex1 + mix(tex0, tex2, lod_fract)) * 0.5;
}

void fragment() {
	float depth = (1.0 - FRAGCOORD.z) / FRAGCOORD.w;
	vec2 scaled_uv = UV * uv_scale;
	
	ALBEDO = fractal_texture(ground_texture, scaled_uv, depth).xyz;
	NORMAL_MAP = fractal_texture(normal_texture, scaled_uv, depth).xyz;
}
2693
Karl @hexaquo.at · 14/02/2025
In contrast, here's the same shot textured traditionally: it's really pixelated up-close, but gets blurry and clearly tiled at a distance.
1160
Karl @hexaquo.at · 14/02/2025
I rarely see Fractal Texturing used anywhere but find it really useful. It makes a single texture look good at any distance, without getting pixelated or blurry and tiled, by interpolating between different scales of the same texture based on the depth. #gamedev #godot #godotengine
1133254
Karl @hexaquo.at · 10/02/2025
This raymarched cloud is just 80 lines of shader code and a NoiseTexture3D. Writing a tutorial soon! #GodotEngine #Godot #gamedev
0351
Karl @hexaquo.at · 07/02/2025
Although shader debugging can be frustrating, it's also sometimes unexpectedly beautiful. Here I was checking the ray direction (in world space) of a raymarching shader and forgot to disable transparency. #GodotEngine #Godot #gamedev
0181
Karl @hexaquo.at · 06/02/2025
I was also really eager to switch! I did need to make some additional adjustments to avoid things from looking too washed-out, especially since we had everything set up for ACES before. But with that done, it's definitely better!
Rendering of a flat landscape. The camera faces the sun; there is a tree and a small dry shrub in the foreground. Wind turbines can be seen in the far distance.
140
Karl @hexaquo.at · 06/02/2025
Played around with our herbage renderer today. It's confusing how plants can be really shiny, but also look like coarse fabric at a distance. This blog post is very helpful (and gave me confidence to mostly ignore physical reality and just fake it): c0de517e.com/017_vegetati... #godotengine #godot
Rendering of a hilly landscape. In the foreground, a wooden fence separates a grassy plain from a sunflower field. The sun is low and there is some shininess on the grass tips. Rendering of a field of young corn. The sun is low and here, too, the green leaves sticking out are a bit shiny. A tree and a wooden power pole cast shadows nearby.
150
Karl @hexaquo.at · 14/01/2025
And I just recently learned how amazingly simple it is to get a decent DTM from a DSM. You just take the DSM upside down and simulate covering it with cloth! (Image from www.mdpi.com/2072-4292/8/...)
Graphical explanation of cloth simulation for getting a DTM from a DSM. Bottom: cross-section of a DSM. Top: the same, but flipped on the vertical axis. A cloth is now draped over the inverse DSM (shown by a dotted red line). The cloth touches the DSM where the ground is bare, but due to its tension, it is suspended over a building and a tree, giving us the ground height - the DTM - when we invert it again.
000
Karl @hexaquo.at · 14/01/2025
We also use the nDSM a lot, the difference of DSM and DTM, giving the height of whatever is on the surface. That way we get the height of individual trees as well as buildings along with their roof shape, etc.
A snippet of an nDSM, approximately 1 kilometer wide and 800 meters tall. Sections where the ground is bare are pitch black, whereas brighter pixels indicate that something is placed on the ground. In this case, a height of 18 meters is pure white, and everything between 0 and 18 gets the appropriate grayscale value. With its resolution of 1 meter, you can clearly see individual trees, roofs, and even hedges.
110
Karl @hexaquo.at · 07/01/2025
I had a similar urge when I recently re-installed my system 😉 Honestly amazing how faithful it is, from Aero effects to icons down to the system sounds.
Screenshot of a desktop that looks like Windows 7, with a file explorer and terminal window open and the desktop right-clicked.
010
Karl @hexaquo.at · 30/12/2024
More yellow paint I came across within the following 15 minutes
Steps leading out of a train, marked by yellow paint.A yellow line marking where not to walk at the edge of a train station platform.A yellow line with "STOP PRIVAT" written (in yellow) above it.Stairs to a building, the first and last steps are marked by yellow lines.
060
Karl @hexaquo.at · 30/12/2024
Ha, right as I'm reading this, I'm sitting on the train right next to a line of yellow paint delineating the path to the exit. Weirdly I've never consciously paid attention to it even though I take this train regularly.
Photo of the floor in a train. Feet from people sitting nearby can be seen. Two yellow lines delineate the path in the middle (to walk to the exit) from the space provided to the people seated at the borders.
140
Karl @hexaquo.at · 29/12/2024
Inspired by a napkin!
Photo of a napkin with a print depicting a cheerful urban scene in cartoon style: some trees and flower pots next to tables with umbrellas; one person in a suit can be seen sitting at a table holding a drink. The trees look like the tree in the video in the first post which this is replying to.
050
Karl @hexaquo.at · 29/12/2024
The foliage is made up of two components: outlines and paint blotches. Both are particle systems with camera-facing billboards, randomly choosing 1 out of 3 textures. Importantly, the outlines always render on top of the paint blotches, but fade out as the angle to the camera gets steeper.
Screenshot of the tree's foliage showing only the outlines. They fade out towards the edge.Screenshot of the coloring behind the leaf outlines: an ellipsoid shape of black and green paint blotches.The two components combined, showing the finished foliage.
130