From 17d1ab8651582141fe9c9c315ad2cf7dfd1631fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20J=C3=A4rvisalo?= Date: Sun, 27 Jul 2025 22:31:45 +0300 Subject: [PATCH] Domain repetitionilla hexagridi --- src/fft.cpp | 4 +- src/main.cpp | 142 ++++++++++------------------------- src/shaders/fragment.frag | 91 +++++++++++++++------- src/shaders/fragment.inl | 154 +++++++++++++++++++++----------------- 4 files changed, 188 insertions(+), 203 deletions(-) diff --git a/src/fft.cpp b/src/fft.cpp index fd85612..441604b 100644 --- a/src/fft.cpp +++ b/src/fft.cpp @@ -71,8 +71,8 @@ void compute_fft(float* time_data, float* freq_out) { for (int i = 0; i < FFT_SIZE / 2; ++i) { float mag = sqrtf(real[i] * real[i] + imag[i] * imag[i]) / FFT_SIZE; - //float db = 20.0f * log10f(mag + 1e-6f); // Decibels - //float normalized = (db + 60.0f) / 60.0f; // [0,1] + float db = 20.0f * log10f(mag + 1e-6f); // Decibels + float normalized = (db + 60.0f) / 60.0f; // [0,1] freq_out[i] = mag; } } diff --git a/src/main.cpp b/src/main.cpp index f2472a3..50d9ccc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -69,10 +69,6 @@ int __cdecl main(int argc, char* argv[]) #endif #endif - struct Vec3 { - float x, y, z; - }; - // initalize opengl context SetPixelFormat(hDC, ChoosePixelFormat(hDC, &pfd), &pfd); wglMakeCurrent(hDC, wglCreateContext(hDC)); @@ -117,8 +113,7 @@ int __cdecl main(int argc, char* argv[]) long playCursor = 0; long lastPlayCursor = -1; - volatile float maximum = 0.0; // Helper variable to calculate maximum fft output for normalization - + // Unlock buffer for next use IDirectSoundBuffer_Unlock(direct_sound_buffer, p1, SU_LENGTH_IN_SAMPLES * SU_CHANNEL_COUNT * SU_SAMPLE_SIZE, NULL, NULL); @@ -134,76 +129,18 @@ int __cdecl main(int argc, char* argv[]) static float fft_output[FFT_SIZE / 2]; // Magnitudes static float fft_uniform[FFT_SIZE / 4]; - //GLuint fftTex; - //glGenTextures(1, &fftTex); - //glBindTexture(GL_TEXTURE_2D, fftTex); - - //// Create a 512x1 2D texture using FFT output - //glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 512, 1, 0, GL_RED, GL_FLOAT, fft_uniform); - - //// Optional: improve performance - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - //// Bind to texture unit 0 PFNGLACTIVETEXTUREPROC glActiveTexture = ((PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture")); PFNGLUNIFORM1IPROC glUniform1i = ((PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i")); PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = ((PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation")); - //glActiveTexture(GL_TEXTURE0 + 0); - //glBindTexture(GL_TEXTURE_2D, fftTex); - //glUniform1i(glGetUniformLocation(pidMain, "u_fft_texture"), 0); - - - static float hexGridData[HEX_TEX_SIZE]; - - float cellW = 1.6f + 0.2f; - float cellH = 1.88f + 0.2f; - Vec3 gridOffset = { cellW * 8.0f, -5.0f, cellH * 10.0f }; - float rippleCenterX = 7.0f; - float rippleCenterY = 7.0f; - - for (int j = 0; j < GRID; ++j) { - for (int i = 0; i < GRID; ++i) { - float rowOffset = (j % 2 == 0) ? -0.5f : 0.5f; - - float x = (i + rowOffset) * cellW; - float z = j * cellH; - float y = 0.0f; - - Vec3 hexPos = { x - gridOffset.x, y - gridOffset.y, z - gridOffset.z }; - - float dx = (float)i - rippleCenterX; - float dy = (float)j - rippleCenterY; - float hexDist = sqrtf(dx * dx + dy * dy); - - int idx = (j * GRID + i) * 4; - hexGridData[idx + 0] = hexPos.x; - hexGridData[idx + 1] = hexPos.y; - hexGridData[idx + 2] = hexPos.z; - hexGridData[idx + 3] = hexDist; - } - } - - GLuint hexGridTex; - glGenTextures(1, &hexGridTex); - glBindTexture(GL_TEXTURE_2D, hexGridTex); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, GRID, GRID, 0, GL_RGBA, GL_FLOAT, hexGridData); - - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glActiveTexture(GL_TEXTURE0 + 2); - glUniform1i(glGetUniformLocation(pidMain, "u_hexGridTex"), 2); + const ULONGLONG targetIntervalMs = 1000 / 60; // For 60 FPS FFT updates do { + static ULONGLONG lastFFTTime = 0; + ULONGLONG currentTime = GetTickCount64(); + direct_sound_buffer->GetCurrentPosition((DWORD*)&playCursor, NULL); #if !(DESPERATE) @@ -233,43 +170,44 @@ int __cdecl main(int argc, char* argv[]) ((PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i"))(0, (static_cast(position*44100.0))); #endif + if (currentTime - lastFFTTime >= targetIntervalMs) { + lastFFTTime = currentTime; + /****************** + * FFT + *******************/ + LPVOID audio_ptr = NULL; + DWORD audio_size = 0; - /****************** - * FFT - *******************/ - LPVOID audio_ptr = NULL; - DWORD audio_size = 0; + // Read audio + HRESULT hr = IDirectSoundBuffer_Lock(direct_sound_buffer, 0, FFT_SIZE * sizeof(SUsample), &audio_ptr, &audio_size, NULL, NULL, DSBLOCK_FROMWRITECURSOR); - // Read audio - HRESULT hr = IDirectSoundBuffer_Lock(direct_sound_buffer, 0, FFT_SIZE * sizeof(SUsample), &audio_ptr, &audio_size, NULL, NULL, DSBLOCK_FROMWRITECURSOR); + if (SUCCEEDED(hr) && audio_ptr) { + if (playCursor < ((SU_LENGTH_IN_SAMPLES * SU_CHANNEL_COUNT * SU_SAMPLE_SIZE) - (FFT_SIZE * SU_CHANNEL_COUNT * SU_SAMPLE_SIZE))) + { + SUsample* samples = (SUsample*)audio_ptr; + for (int i = 0; i < FFT_SIZE; ++i) { + fft_input[i] = (float)samples[i]; + } + } - if (SUCCEEDED(hr) && audio_ptr) { - if (playCursor < ((SU_LENGTH_IN_SAMPLES * SU_CHANNEL_COUNT * SU_SAMPLE_SIZE) - (FFT_SIZE* SU_CHANNEL_COUNT * SU_SAMPLE_SIZE))) - { - SUsample* samples = (SUsample*)audio_ptr; - for (int i = 0; i < FFT_SIZE; ++i) { - fft_input[i] = (float)samples[i]; + IDirectSoundBuffer_Unlock(direct_sound_buffer, audio_ptr, audio_size, NULL, 0); + } + + // Calculate FFT + compute_fft(fft_input, fft_output); + + // Normalize output + for (int i = 0; i < (FFT_SIZE / 4); i++) + { + float gain = 50.0f; + float alpha = 0.10f; // "Hidastaa" FFT:n piikkej� + float threshhold = 0.05f; // Alin arvo mik� p��stet��n shaderille (v�hent�� "noisea") + float x_t = fft_output[i] * gain; + // Exponential smoothing kaava + // s(t) = alpha*x(t)+(1-alpha)*s(t-1) + fft_uniform[i] = (x_t < threshhold) ? 0.f : alpha * (x_t)+(1 - alpha) * fft_uniform[i]; } } - - IDirectSoundBuffer_Unlock(direct_sound_buffer, audio_ptr, audio_size, NULL, 0); - } - - // Calculate FFT - compute_fft(fft_input, fft_output); - - // Normalize output - for (int i = 0; i < (FFT_SIZE / 4); i++) - { - float gain = 50.0f; - float alpha = 0.15f; // "Hidastaa" FFT:n piikkejä - float threshhold = 0.05f; // Alin arvo mikä päästetään shaderille (vähentää "noisea") - float x_t = fft_output[i] * gain; - // Exponential smoothing kaava - // s(t) = alpha*x(t)+(1-alpha)*s(t-1) - fft_uniform[i] = (x_t < threshhold) ? 0.f : alpha*(x_t) + (1-alpha)*fft_uniform[i]; - } - syncs[0] = (float)playCursor / (SU_SAMPLE_RATE * SU_CHANNEL_COUNT * SU_SAMPLE_SIZE); // Aika sekunteina. for (int i = 0; i < SU_NUMSYNCS; ++i) @@ -280,13 +218,9 @@ int __cdecl main(int argc, char* argv[]) PFNGLUNIFORM1FVPROC glUniform1fvProc = ((PFNGLUNIFORM1FVPROC)wglGetProcAddress("glUniform1fv")); glUniform1fvProc(0, SU_NUMSYNCS + 1, syncs); glUniform1fvProc(8, FFT_SIZE / 4, fft_uniform); - //glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 512, 1, GL_RED, GL_FLOAT, fft_uniform); glRects(-1, -1, 1, 1); - //syncs[0] = -syncs[0]; - //glUniform1fvProc(0, SU_NUMSYNCS + 1, syncs); - // render "post process" using the opengl backbuffer #if POST_PASS glBindTexture(GL_TEXTURE_2D, 1); diff --git a/src/shaders/fragment.frag b/src/shaders/fragment.frag index ad5ef35..adf3e97 100644 --- a/src/shaders/fragment.frag +++ b/src/shaders/fragment.frag @@ -65,8 +65,9 @@ float fHexagonCircumcircle(vec3 p, vec2 h) { //return max(q.y - h.y, max(dot(vec2(cos(PI/3), sin(PI/3)), q.zx), q.z) - h.x); } -float sdHex(vec3 pos, float i, float angle) { - float d1 = fHexagonCircumcircle(pos, vec2(0.86, i)); +float sdHex(vec3 pos, vec2 id, float angle) { + pos.xz *= rot2D(0.1); + float d1 = fHexagonCircumcircle(pos, vec2(0.86, 1.)); return d1; } @@ -81,38 +82,72 @@ float getScaledFFT(int index, float scale, float offset) { return log(1.0 + raw * scale) + offset; } +// Return local coordinates inside hex AND axial ID +struct HexData { + vec3 local; // Local position inside hex + vec2 axial; // Axial ID (q, r) +}; + +HexData hexTile(vec3 p, float radius) { + float q = (sqrt(3.0)/3.0 * p.x - 1.0/3.0 * p.z) / radius; + float r = (2.0/3.0 * p.z) / radius; + + float rq = round(q); + float rr = round(r); + float rs = round(-q - r); + + float dq = abs(rq - q); + float dr = abs(rr - r); + float ds = abs(rs + q + r); + + if (dq > dr && dq > ds) rq = -rr - rs; + else if (dr > ds) rr = -rq - rs; + + float hx = radius * sqrt(3.0) * (rq + rr * 0.5); + float hz = radius * 1.5 * rr; + + HexData outData; + outData.local = p - vec3(hx, 0.0, hz); + outData.axial = vec2(rq, rr); // Hex ID + return outData; +} + +struct HexData { + vec3 local; + vec2 axial; +}; + +float hexDistance(vec2 axial) { + float q = axial.x; + float r = axial.y; + float s = -q - r; + return max(abs(q), max(abs(r), abs(s))); +} + // Modify your mapScene function vec3 mapScene(vec3 p) { - float gridsize = 16.0; // or GRID if you want full size - float hexGap = 0.2; - float d = 1e9; float mat = 0.; + float hexRadius = 0.83; + vec3 hexpos = vec3(p.x, p.y - 10.0, p.z); - vec2 rippleCenter = vec2(7.0, 7.0); + HexData hex = hexTile(hexpos, 1.0); - for(float j = 0.; j < gridsize; j++) { - for(float i = 0.; i < gridsize; i++) { - ivec2 texSize = textureSize(u_hexGridTex, 0); - vec2 texCoord = (vec2(i, j)) / vec2(texSize); + // Use axial coordinates as a stable hex ID + float distFromCenter = hexDistance(hex.axial); + int fftIndex = int(clamp(distFromCenter * 1.0, 0.0, 511.0)); // tweak 15.0 to taste - vec4 hexData = texture(u_hexGridTex, texCoord); // RGBA: x, y, z, dist + float fftVal = fft_output[fftIndex]; + float hexHeight = 1.0 + fftVal * 1.0; - vec3 hexPos = hexData.rgb; - float hexDist = hexData.a; + // Rotate individual hex tiles if needed + vec3 r = hex.local; + r.xz *= rot2D(0.5); - // Optionally use hexDist for ripple effect with FFT - int index = clamp(int((hexDist / 34.)*512.), 0, 511); - float hexSize = fft_output[index] * 5.0; - float a = sdHex(p - hexPos, 1.0 + hexSize, 0.0); - d = min(d, a); + float d1 = fHexagonCircumcircle(r, vec2(hexRadius, hexHeight)); + d = min(d,d1); - if(d == a) { - mat = 1.; - } - } - } - return vec3(d, mat, float(0)); + return vec3(d, 0.0, 0.0); } //////////////// @@ -195,20 +230,20 @@ vec3 postProcess(vec3 col) { col = smoothstep(0., 1., col); // fade out at the end - col += 1.0 - vec3(cl((46. - u_time)*.5, 0., 1.0)); + //col += 1.0 - vec3(cl((46. - u_time)*.5, 0., 1.0)); return col; } vec3 cameraPos() { // first zoom in to the gate - vec3 cPos = vec3(0., 25., 50.); + vec3 cPos = vec3(0., 25., 25.); return cPos; } vec3 cameraPointAt() { - vec3 p = vec3(0., -.5, 0.); + vec3 p = vec3(0., 0.0, -5.); return p; } @@ -221,7 +256,7 @@ vec3 sceneGate(vec2 uv) { // Initialization vec3 ro = cameraPos(), - rd = getCameraRayDir(uv, ro, cameraPointAt(), cl((43.-u_time)*-2.,2.,25.)), + rd = getCameraRayDir(uv, ro, cameraPointAt(), cl(1.0,2.,25.)), col = vec3(0.); float d = rayMarch(ro, rd,0), mat = 0.; diff --git a/src/shaders/fragment.inl b/src/shaders/fragment.inl index 173b84e..5130d24 100644 --- a/src/shaders/fragment.inl +++ b/src/shaders/fragment.inl @@ -1,136 +1,152 @@ // Generated with Shader Minifier 1.5.1 (https://github.com/laurentlb/Shader_Minifier/) #ifndef FRAGMENT_INL_ # define FRAGMENT_INL_ -# define VAR_fft_output "p" +# define VAR_fft_output "H" # define VAR_o "v" -# define VAR_syncs "s" -# define VAR_u_hexGridTex "d" +# define VAR_syncs "a" +# define VAR_u_hexGridTex "l" const char *fragment_frag = "#version 460\n" "precision mediump float;" "out vec4 v;" "const float f=2.*acos(-1.),m=sqrt(5.)*.5+.5;" - "layout(location=0)uniform float s[7];" - "layout(location=8)uniform float p[512];" - "uniform sampler2D d;" - "float y=s[0];" + "layout(location=0)uniform float a[7];" + "layout(location=8)uniform float H[512];" + "uniform sampler2D l;" + "float d=a[0];" "vec2 n=vec2(1920,1080);" - "vec3 t(vec3 v)" + "vec3 s(vec3 v)" "{" "return normalize(v);" "}" - "float t(float v,float f,float y)" + "float s(float v,float f,float m)" "{" - "return clamp(v,f,y);" + "return clamp(v,f,m);" "}" - "float t(vec2 v)" + "mat2 s()" + "{" + "float v=sin(.5),f=cos(.5);" + "return mat2(f,-v,v,f);" + "}" + "float s(vec2 v)" "{" "v=50.*fract(v*.3183099);" "return fract(v.x*v.y*(v.x+v.y));" "}" - "float t(vec2 v,float y)" + "float s(vec2 v,float x)" "{" "vec2 f=floor(v);" "v=fract(v);" "v=v*v*(3.-2.*v);" - "return-y+y*mix(mix(t(f+vec2(0)),t(f+vec2(1,0)),v.x),mix(t(f+vec2(0,1)),t(f+vec2(1)),v.x),v.y);" + "return-x+x*mix(mix(s(f+vec2(0)),s(f+vec2(1,0)),v.x),mix(s(f+vec2(0,1)),s(f+vec2(1)),v.x),v.y);" "}" - "float t(vec3 v,vec2 y)" + "float s(vec3 v,vec2 f)" "{" "v=abs(v);" - "return max(v.y-y.y,max(v.x*sqrt(3.)*.5+v.z*.5,v.z)-y.x);" + "return max(v.y-f.y,max(v.x*sqrt(3.)*.5+v.z*.5,v.z)-f.x);" + "}" + "struct HexData{vec3 local;vec2 axial;};" + "HexData t(vec3 v)" + "{" + "float f=sqrt(3.)/3.*v.x-1./3.*v.z,i=2./3.*v.z,x=round(f),m=round(i),l=round(-f-i),d=abs(x-f),s=abs(m-i);" + "f=abs(l+f+i);" + "if(d>s&&d>f)" + "x=-m-l;" + "else if(s>f)" + "m=-x-l;" + "f=sqrt(3.)*(x+m*.5);" + "i=1.5*m;" + "HexData r;" + "r.local=v-vec3(f,0,i);" + "r.axial=vec2(x,m);" + "return r;" + "}" + "struct HexData{vec3 local;vec2 axial;};" + "float t(vec2 v)" + "{" + "float f=v.x,m=v.y;" + "return max(abs(f),max(abs(m),abs(-f-m)));" "}" "vec3 x(vec3 v)" "{" - "float f=1e9,m=0.;" - "for(float y=0.;y<16.;y++)" - "for(float i=0.;i<16.;i++)" - "{" - "ivec2 x=textureSize(d,0);" - "vec2 n=vec2(i,y)/vec2(x);" - "vec4 s=texture(d,n);" - "float w=t(v-s.xyz,vec2(.86,1.+p[clamp(int(s.w/34.*512.),0,511)]*5.));" - "f=min(f,w);" - "if(f==w)" - "m=1.;" - "}" - "return vec3(f,m,float(0));" + "float f=1e9;" + "HexData m=t(vec3(v.x,v.y-10.,v.z));" + "v=m.local;" + "v.xz*=s();" + "float x=s(v,vec2(.83,1.+H[int(clamp(t(m.axial),0.,511.))]));" + "f=min(f,x);" + "return vec3(f,0,0);" "}" - "float t(vec3 v,vec3 f,int y)" + "float s(vec3 v,vec3 f,int m)" "{" - "vec3 m;" + "vec3 l;" "float i=0.;" - "for(int y=0;y<100;y++)" + "for(int r=0;r<100;r++)" "{" - "m=x(v+f*i);" - "i+=m.x;" - "if(m.x<.001||i>5e2)" + "l=x(v+f*i);" + "i+=l.x;" + "if(l.x<.001||i>5e2)" "break;" "}" "return i;" "}" "vec3 w(vec3 v)" "{" - "vec2 y=vec2(.01,0);" - "v=x(v).x-vec3(x(v-y.xyy).x,x(v-y.yxy).x,x(v-y.yyx));" - "return t(v);" + "vec2 f=vec2(.01,0);" + "return s(x(v).x-vec3(x(v-f.xyy).x,x(v-f.yxy).x,x(v-f.yyx)));" "}" - "float t(vec3 v,vec3 f,float y,float m,vec3 d,float i)" + "float s(vec3 v,vec3 f,float m,float l,vec3 x,float i)" "{" - "vec3 x=t(f-v);" - "y=t(dot(d,x)*y,0.,y)/(1.+i*length(f-v));" - "i=t(v+d*.0025,x,1);" - "if(i