You are browsing as a guest. Sign up (or log in) to start making projects!

timon

@timon

Joined June 8th, 2026

  • 36Devlogs
  • 2Projects
  • 6Ships
  • 75Votes
Open comments for this post

4h 16m 26s logged

I spent some time remaking the water. Before the Waves were pretty symmetrical. I added more randomness by adding more cos and sin waves with different speed and direction.

Before:

wavePos = floor(wavePos * 16.0) / 16.0;
float wave = sin(wavePos.x * 1.5 + frameTimeCounter * 2.0) * 0.08 +
cos(wavePos.z * 1.5 + frameTimeCounter * 1.8) * 0.08;

After:

float wave = 0.0;
wave += sin(wavePos.x * 1.2 + frameTimeCounter * 1.6) * 0.07;
wave += sin(wavePos.z * 1.4 + frameTimeCounter * 1.9) * 0.05;
wave += sin((wavePos.x + wavePos.z) * 1.0 + frameTimeCounter * 1.1) * 0.04;
wave += cos((wavePos.x - wavePos.z) * 1.1 + frameTimeCounter * 1.3) * 0.045;

Then I went to the gbuffer_terrain.fsh and gbuffer_terrain.vsh. It is there fore the foundation for shadow mapping by calculating the shadow coordinates in the vertex shader and getting the shadow map.

When i finnished that i went to the composite.fsh to actually getting the shadows to run.
But first i began working on the overall lighting to make it feel much brighter and cooler.


vec3 sunLight = vec3(1.0, 0.92, 0.78) * shadow * lm.y;vec3 skyAmbient = vec3(0.3, 0.42, 0.55) * lm.y;vec3 blocklight = vec3(1.0, 0.6, 0.3) * lm.x * lm.x;vec3 lighting = sunLight + skyAmbient + blocklight + 0.03;

Now the shadows. The shadowSample() function takes the reconstructed player position and normal ( reconstructed player = 3d world position from a pixel, normal = where a surface is facing to) and transforms it into the shadow map.

I also added 6 shadow samples around the pixel (geminis advice) to make the shadows softer instead of sharp (Though i might change that because as you will se in the picture the shadow is ugly… It might be because of that).

float shadow = step(sp.z, texture2D(shadowtex0, sp.xy).r) * 0.4+ step(sp.z, texture2D(shadowtex0, sp.xy + vec2( r, r)).r) * 0.15+ step(sp.z, texture2D(shadowtex0, sp.xy + vec2(-r, r)).r) * 0.15+ step(sp.z, texture2D(shadowtex0, sp.xy + vec2( r, -r)).r) * 0.15+ step(sp.z, texture2D(shadowtex0, sp.xy + vec2(-r, -r)).r) * 0.15;

The shadow itself is actiavated in main() with:

float shadow = shadowSample(playerPos, normal);


After all that though, the shadow didnt work and i was looking for it like 30 minutes and also troubleshootign with AI and after changeing the code like 10 times it also didnt work so I reverted the changes and noticed that:

uniform float shadowDistance; is wrong because it of course needs a number :/

-> uniform float shadowDistance = 128.0;

0
0
9
Open comments for this post

1h 11m 50s logged

Im making a shader for Minecraft and after upgrading the template from 1.21.5 to 26.2 I implemented waves to water.. It took long 😭 but it wasnt that difficult. I also added a pciture here.

With mc_Entity i added blockID for specifically Water to the IDs 10034 and 10033. For the animation I used sine and cosine functions.
After i styled the Water by blending its texture with a blue tint:

vec3 waterColor = vec3(0.1, 0.4, 0.8);

Though, because it was all the same color, you couldnt really see the waved that were further away than 3 blocks, so I implented a bit of shadow:

shadow = texture(shadowtex0, shadowCoord.st).r;albedo.rgb *=mix(0.5, 1.0, shadow);

1
0
59
Open comments for this post

1h 34m 6s logged

I improved the GPU readback so the CPU no longer has to wait for the GPU every frame (Gemini noticed that this happend and with its help I fixxed it). Before the resul buffer was copied and read immediately which could cause the CPU to block while the GPU was still processing shader.

This is difficult because getting the CPU and GPU sync right is tough. As the CPU should only read a buffer when the GPU finished writing on it.
I used ID3D11Query events for it:

if (r.pending &&
context->GetData(r.query.Get(), nullptr, 0, 0) == S_OK)
{
context->Map(r.buffer.Get(), 0, D3D11_MAP_READ, 0, &m);
serial.send((const UINT*)m.pData);
context->Unmap(r.buffer.Get(), 0);
r.pending = false;
}

0
0
3
Open comments for this post

19m 39s logged

Fixed a few issues in the shader. First of all the border mapping wasnt complete and I forgot the top and left side of the LEDs.. Also removed Typos. I also added sRGB and improved the saturation handling as before they didnt match accurate. I fixed it by the colors to linear space before processing them.

Before:

float luma = dot(rgb, float3(0.2126, 0.7152, 0.0722));
rgb = saturate(lerp(luma.xxx, rgb, saturationBoost) * brightness);

After:

sum += ToLinear(desktop.Load(int3(pixel, 0)).rgb);

float3 rgb = ToSrgb(sum / (samplesAcross * samplesDeep));
rgb = saturate(BoostSaturation(rgb) * brightness);

0
0
7
Open comments for this post

58m 24s logged

Using an HLSL compute shader and [numthreads(90, 1, 1)] the GPU spawns 90 parralel threads which are calculating the average color for every LED simaultaneously.

As only picking one pixel at each led would be pretty inaccurate, we are taking zones and use the average color of ever zone.

(For now the average of every zone is picked, if I am testing it in real
life, we might change it - maybe the outer pixels are doubled for a more accurate color that looks better at the end).

I had an issue where some LEDs were using the wrong part of the screen because of incorrect index calculation. I fixed it by correcting the LED and screen coordinates:

(in the picture)

0
0
8
Open comments for this post

2h 57m 14s logged

Before doing the PC side and video capture code, I made the the code for the physical ahrdware (the esp32). I set up a Arduino sketch using FastLED library to manage the output signal on GPIO (in my case DATA_PIN 2), I configured the setup for the 90 LEDS I have on the RGB Strip (ws2812b usually have 60 LEDS per 1m and i need 1,5m). I set the communication speed to 921.600 baud.

void setup() {    FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);    FastLED.setBrightness(BRIGHTNESS);    FastLED.clear(true);    Serial.begin(921600);}

To avoid lagging, I built a simple step by step parser that handles incoming data byte by byte:

  1. Ready how many Leds are sent
  2. It Checks if the data is valid and mathces the 90 LEDS and if anything is wrong it resets and waits for the next frame.
  3. Once all 270 bytes (90 lights * 3 colors) arrive, it calls FastLED.show() to light up the strip

I started working on the communication between the PC and the LED hardware with serial. Serial is the channel used to send binary color data directly to the esp32.
To make sure the lights dont stay lit when the program closes the destructor sends a black frame on exit to turn of all lights. I didnt notice that it would be a problem but when troubleshooting for another proble, gemini noticed it:

~Serial() { black(); if (handle_ != INVALID_HANDLE_VALUE) CloseHandle(handle_); }

I am using DXGI Desktop duplication that can capture the frames directly from the gpu. This is good so the frames dont need to be loaded again for the LEDs.

0
0
107
Open comments for this post

1h 24m 16s logged

I started with creating the circuit in KiCad. I noticed that there was not the right ESP32 for me so i looked online and found this:
https://github.com/davidkleymann/doit-esp32-devkit-kicad

I build everything in KiCad just to see that the libraries are probably outdated (or i just did something wrong but i dont believe that)
After about 20 of trouble shooting I got it working but I noticed that KiCad is not the best place for what im trying to do so I gave up. I searched for a new programm and found https://wokwi.com.

It worked well. Though, they did not have splicing connectors / wago connectors so i made it with a Breadboard in this circuit instead. In the real version I will do it instead with splicing connectors.
Also the LED strip name for the negative power supply pin was VSS, i thought it should be GND and learned the difference then.

0
0
23

Followers

Loading…