Author Topic: How to create a BBP_GLSL plugin  (Read 864 times)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 2008
    • zapsolution
How to create a BBP_GLSL plugin
« on: December 30, 2025, 06:22:41 pm »
BassBox GLSL Plugin – Minimal Tutorial (Template Walkthrough)

This post explains how to use the provided bbp_GLSL.cpp + GLSL.h template
to build a simple GLSL-based visual plugin for BassBox64 / MBox64.

The goal is not to introduce “modern OpenGL”, but to show how a GLSL fragment shader
is integrated cleanly into the existing BassBox OpenGL pipeline.

The template uses:
- a legacy full-screen quad (glBegin / glVertex)
- a minimal passthrough vertex shader
- a fragment shader driven by audio and time
- a 32-color LUT system shared between CPU and GPU


----------------------------------------------------------------
1) Plugin lifecycle (BBProc)
----------------------------------------------------------------

The host communicates with the plugin through the exported function:

    ExportC long BBProc(BBPLUGIN &BBP);

The most important messages are:

BBP_CREATE 
Called once to declare plugin identity and rendering mode.
Here you set:
- title
- author
- version
- BBP_OPENGL (mandatory for GLSL plugins)

BBP_INIT 
Called once when the plugin is initialized.
This is where you:
- bind the host OpenGL context (wglMakeCurrent)
- reset OpenGL state
- initialize time and audio variables
- create textures (including the LUT)
- compile and link GLSL shaders
- cache uniform and sampler locations

BBP_RENDER 
Called every frame.
This is where you:
- update time and audio values
- send uniforms to the shader
- bind textures
- draw a full-screen quad

BBP_SIZE 
Called when the plugin window is resized.
You must update glViewport and internal width/height.

BBP_DESTROY 
Called when the plugin is unloaded.
You must delete:
- GLSL program
- textures
- any allocated resources


----------------------------------------------------------------
2) Rendering model
----------------------------------------------------------------

This template uses a very simple and reliable rendering model:

- A full-screen quad is drawn in clip space (-1 .. +1)
- The vertex shader simply forwards gl_Vertex to gl_Position
- The fragment shader runs once per pixel

No VBO, no VAO, no FBO, no multipass.
This keeps the focus on the shader logic itself.


----------------------------------------------------------------
3) Core uniforms provided to the shader
----------------------------------------------------------------

The following uniforms are automatically filled by the plugin:

uniform vec3 iResolution; 
- x = viewport width in pixels 
- y = viewport height in pixels 
- z = 1.0 (convention)

uniform float iTime; 
- Accumulated animation time
- Already modulated by audio on the CPU side
- Suitable for driving motion directly

uniform float iAudio; 
- Smoothed audio level
- Typically in the range 0.0 .. 1.0 (may slightly exceed)
- Stable enough for visual modulation

uniform vec3 iLutColor; 
- One color selected from the 32-color LUT
- Chosen on the CPU side according to audio peaks
- Already normalized (0..1)

uniform vec3 iMouse; 
- Present for compatibility
- Currently set to (0,0,0) in the template
- Can be wired later via BBP_MOUSE

uniform vec4 iDate; 
- Only iDate.w is used in the template
- Contains raw system time in seconds
- Useful if you need a non-audio-modulated time source


----------------------------------------------------------------
4) LUT system (CPU + GPU)
----------------------------------------------------------------

The template defines a 32-color palette:

- On the CPU:
  - gP.color[32]  : packed ARGB
  - gP.fR/G/B[32]: normalized float values

- On the GPU:
  - a 32x1 RGB texture bound to iChannel1

You can:
- use iLutColor for a single selected color
- sample iChannel1 in the shader for custom palette logic

The LUT texture uses:
- GL_NEAREST filtering
- GL_CLAMP_TO_EDGE wrapping


----------------------------------------------------------------
5) Demo fragment shader (what it shows)
----------------------------------------------------------------

The provided demo shader demonstrates:

- coordinate normalization using iResolution
- time-based animation using iTime
- audio-driven modulation using iAudio
- color tinting using iLutColor
- a simple ring/pulse effect
- a subtle vignette

It does NOT require:
- any texture input
- any mouse interaction
- any advanced OpenGL features

Alpha output is set to 1.0, producing an opaque image.


----------------------------------------------------------------
6) Where to modify things
----------------------------------------------------------------

To change the visual effect: 
Edit the quoted GLSL string inside:

    static GLuint CompileShaderFromString()

To add textures: 
Populate gP.mt[] in BBP_INIT and sample them as iChannel0..3.

To enable transparency: 
- Output alpha < 1.0 in gl_FragColor
- Enable blending in BBP_INIT or BBP_RENDER
- Ensure the host compositing mode supports it

To react more strongly to audio: 
- Adjust the scaling of audioNow
- Modify smoothing factor
- Use iAudio directly in the shader


----------------------------------------------------------------
7) Why this template matters
----------------------------------------------------------------

This template is intentionally:

- minimal
- stable
- legacy-compatible
- host-friendly

It avoids:
- undefined OpenGL state
- hidden multipass logic
- fragile modern-only constructs

Once this base works reliably, more complex shaders and techniques
can be layered on top with confidence.


----------------------------------------------------------------
End of tutorial
----------------------------------------------------------------

The VS 2022 bbp_GLSL.zip is attached to this post
« Last Edit: December 30, 2025, 07:38:24 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 2008
    • zapsolution
BBP_Cubism.cpp
« Reply #1 on: January 04, 2026, 10:46:22 am »
BBP_Cubism

Converted from https://www.shadertoy.com/view/ftGfDK
Original created by mrange on 2022-10-08
Audio + color LUT + BBP_plugin integration by Patrice Terrier



Paste this in the BBProc section
Code: [Select]
    case BBP_CREATE:
        // Host asks: "who are you and what do you render to?"
        strcpy(BBP.title,"Cubism experiment");
        strcpy(BBP.author, "Mrange (Shadertoy)");
        BBP.version  = MAKEWORD(1,0);

        // Critical: This plugin renders using OpenGL into the host-provided GL context.
        BBP.renderto = BBP_OPENGL;

        // Default background ARGB used by host (informational/fallback).
        BBP.backargb = bbpARGB(255,0,0,0);
        break;

Paste this in the GLSL.h section
Code: [Select]
static GLuint CompileShaderFromString() {
    const char* CharBuffer =
    "#version 330 core\n"
    "\n"
    "uniform vec3  iResolution;\n"
    "uniform float iTime;\n"
    "uniform float iAudio;\n"
    "uniform vec3  iLutColor;   // RGB directly from host (lutR,lutG,lutB)\n"
    "\n"
    "out vec4 FragColor;\n"
    "\n"
    "#define TIME        iTime\n"
    "#define RESOLUTION  iResolution\n"
    "#define PI          3.141592654\n"
    "#define TAU         (2.0*PI)\n"
    "#define ROT(a)      mat2(cos(a), sin(a), -sin(a), cos(a))\n"
    "\n"
    "#define TOLERANCE       0.0005\n"
    "#define MAX_RAY_LENGTH  20.0\n"
    "#define MAX_RAY_MARCHES 80\n"
    "#define MAX_SHD_MARCHES 20\n"
    "#define NORM_OFF        0.005\n"
    "\n"
    "const mat2 rot0 = ROT(0.0);\n"
    "mat2 g_rot0 = rot0;\n"
    "\n"
    "const vec4 hsv2rgb_K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"
    "#define HSV2RGB(c)  (c.z * mix(hsv2rgb_K.xxx, clamp(abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www) - hsv2rgb_K.xxx, 0.0, 1.0), c.y))\n"
    "\n"
    "const float hoff = 0.0;\n"
    "\n"
    "// Keep sky exactly as original\n"
    "const vec3 skyCol     = HSV2RGB(vec3(hoff+0.57, 0.90, 0.25));\n"
    "const vec3 skylineCol = HSV2RGB(vec3(hoff+0.02, 0.95, 0.5));\n"
    "const vec3 sunCol     = HSV2RGB(vec3(hoff+0.07, 0.95, 0.5));\n"
    "\n"
    "const vec3 sunDir1    = normalize(vec3(0., 0.05, -1.0));\n"
    "\n"
    "const vec3 lightPos1  = vec3(10.0, 10.0, 10.0);\n"
    "const vec3 lightPos2  = vec3(-10.0, 10.0, -10.0);\n"
    "\n"
    "vec3 sRGB(vec3 t) {\n"
    "  return mix(1.055*pow(t, vec3(1./2.4)) - 0.055, 12.92*t, step(t, vec3(0.0031308)));\n"
    "}\n"
    "\n"
    "vec3 aces_approx(vec3 v) {\n"
    "  v = max(v, 0.0);\n"
    "  v *= 0.6;\n"
    "  float a = 2.51;\n"
    "  float b = 0.03;\n"
    "  float c = 2.43;\n"
    "  float d = 0.59;\n"
    "  float e = 0.14;\n"
    "  return clamp((v*(a*v+b))/(v*(c*v+d)+e), 0.0, 1.0);\n"
    "}\n"
    "\n"
    "float tanh_approx(float x) {\n"
    "  float x2 = x*x;\n"
    "  return clamp(x*(27.0 + x2)/(27.0+9.0*x2), -1.0, 1.0);\n"
    "}\n"
    "\n"
    "float rayPlane(vec3 ro, vec3 rd, vec4 p) {\n"
    "  return -(dot(ro,p.xyz)+p.w)/dot(rd,p.xyz);\n"
    "}\n"
    "\n"
    "float box(vec2 p, vec2 b) {\n"
    "  vec2 d = abs(p)-b;\n"
    "  return length(max(d,0.0)) + min(max(d.x,d.y),0.0);\n"
    "}\n"
    "\n"
    "float box(vec3 p, vec3 b) {\n"
    "  vec3 q = abs(p) - b;\n"
    "  return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0);\n"
    "}\n"
    "\n"
    "float ref(inout vec3 p, vec3 r) {\n"
    "  float d = dot(p, r);\n"
    "  p -= r*min(0.0, d)*2.0;\n"
    "  return d < 0.0 ? 0.0 : 1.0;\n"
    "}\n"
    "\n"
    "vec3 render0(vec3 ro, vec3 rd) {\n"
    "  vec3 col = vec3(0.0);\n"
    "  float sf = 1.0001-max(dot(sunDir1, rd), 0.0);\n"
    "  col += skyCol*pow((1.0-abs(rd.y)), 8.0);\n"
    "  col += clamp(vec3(mix(0.0025, 0.125, tanh_approx(.005/sf))/abs(rd.y))*skylineCol, 0.0, 10.0);\n"
    "  sf *= sf;\n"
    "  col += sunCol*0.00005/sf;\n"
    "\n"
    "  float tp1  = rayPlane(ro, rd, vec4(vec3(0.0, -1.0, 0.0), 6.0));\n"
    "\n"
    "  if (tp1 > 0.0) {\n"
    "    vec3 pos  = ro + tp1*rd;\n"
    "    vec2 pp = pos.xz;\n"
    "    float db = box(pp, vec2(5.0, 9.0))-3.0;\n"
    "    col += vec3(4.0)*skyCol*rd.y*rd.y*smoothstep(0.25, 0.0, db);\n"
    "    col += vec3(0.8)*skyCol*exp(-0.5*max(db, 0.0));\n"
    "  }\n"
    "\n"
    "  return clamp(col, 0.0, 10.0);\n"
    "}\n"
    "\n"
    "float df(vec3 p) {\n"
    "  p.xz *= g_rot0;\n"
    "  vec3 p0 = p;\n"
    "  vec3 p1 = p;\n"
    "  vec3 p2 = p;\n"
    "\n"
    "  // --- AUDIO BREATHING (SHRINK ON LOUD TO AVOID COLLISIONS) ---\n"
    "  float a = max(iAudio, 0.0);\n"
    "  a = 1.0 - exp(-1.5 * a);\n"
    "  float breathe = 1.0 - 0.10 * a;\n"
    "  breathe = clamp(breathe, 0.75, 1.0);\n"
    "\n"
    "  const float ss = 1.;\n"
    "  p0.y -= -0.2;\n"
    "  p0.z = abs(p0.z);\n"
    "  p0.x = -abs(p0.x);\n"
    "  p0.x -= -0.4*ss;\n"
    "  ref(p0, normalize(vec3(1.0, -0.05, -1.0)));\n"
    "  p0.x -= 1.3*ss;\n"
    "  ref(p0, normalize(vec3(1.0, 0.30, 1.0)));\n"
    "  p0.x -= 1.4*ss;\n"
    "  p0.z -= 0.3*ss;\n"
    "  ref(p0, normalize(vec3(1.0, -1.0, 0.5)));\n"
    "  p0.x -= 1.25*ss;\n"
    "  p0.z -= -0.5*ss;\n"
    "  p0.y -= -0.3*ss;\n"
    "  float d0 = box(p0, vec3(0.5) * breathe)-0.0125;\n"
    "\n"
    "  p1.x -= 0.4;\n"
    "  p1.y -= 0.75;\n"
    "  float d1 = box(p1, vec3(1.25) * breathe)-0.0125;\n"
    "\n"
    "  p2.y += 2.0;\n"
    "  float d2 = p2.y;\n"
    "\n"
    "  float d = d1;\n"
    "  d = min(d, d0);\n"
    "  d = min(d, d2);\n"
    "  return d;\n"
    "}\n"
    "\n"
    "vec3 normal(vec3 pos) {\n"
    "  vec2  eps = vec2(NORM_OFF,0.0);\n"
    "  vec3 nor;\n"
    "  nor.x = df(pos+eps.xyy) - df(pos-eps.xyy);\n"
    "  nor.y = df(pos+eps.yxy) - df(pos-eps.yxy);\n"
    "  nor.z = df(pos+eps.yyx) - df(pos-eps.yyx);\n"
    "  return normalize(nor);\n"
    "}\n"
    "\n"
    "float rayMarch(vec3 ro, vec3 rd, float initt) {\n"
    "  float t = initt;\n"
    "  for (int i = 0; i < MAX_RAY_MARCHES; ++i) {\n"
    "    if (t > MAX_RAY_LENGTH) { t = MAX_RAY_LENGTH; break; }\n"
    "    float d = df(ro + rd*t);\n"
    "    if (d < TOLERANCE) break;\n"
    "    t += d;\n"
    "  }\n"
    "  return t;\n"
    "}\n"
    "\n"
    "float shadow(vec3 lp, vec3 ld, float mint, float maxt) {\n"
    "  const float ds = 1.0-0.4;\n"
    "  float t = mint;\n"
    "  float nd = 1E6;\n"
    "  const float soff = 0.05;\n"
    "  const float smul = 1.5;\n"
    "  for (int i=0; i < MAX_SHD_MARCHES; ++i) {\n"
    "    vec3 p = lp + ld*t;\n"
    "    float d = df(p);\n"
    "    if (d < TOLERANCE || t >= maxt) {\n"
    "      float sd = 1.0-exp(-smul*max(t/maxt-soff, 0.0));\n"
    "      return t >= maxt ? mix(sd, 1.0, smoothstep(0.0, 0.025, nd)) : sd;\n"
    "    }\n"
    "    nd = min(nd, d);\n"
    "    t += ds*d;\n"
    "  }\n"
    "  float sd = 1.0-exp(-smul*max(t/maxt-soff, 0.0));\n"
    "  return sd;\n"
    "}\n"
    "\n"
    "vec3 boxCol(vec3 col, vec3 nsp, vec3 rd, vec3 nnor, vec3 nrcol, float nshd1, float nshd2) {\n"
    "  // --- LUT-driven cube palette (from host RGB) ---\n"
    "  vec3 lut  = clamp(iLutColor, 0.0, 1.0);\n"
    "  vec3 diff1 = lut;\n"
    "  vec3 diff2 = mix(lut, vec3(1.0), 0.25);\n"
    "  vec3 rim   = mix(lut, vec3(1.0), 0.50);\n"
    "\n"
    "  float nfre  = 1.0+dot(rd, nnor);\n"
    "  nfre        *= nfre;\n"
    "\n"
    "  vec3 nld1   = normalize(lightPos1-nsp);\n"
    "  vec3 nld2   = normalize(lightPos2-nsp);\n"
    "\n"
    "  float ndif1 = max(dot(nld1, nnor), 0.0);\n"
    "  ndif1       *= ndif1;\n"
    "\n"
    "  float ndif2 = max(dot(nld2, nnor), 0.0);\n"
    "  ndif2       *= ndif2;\n"
    "\n"
    "  vec3 scol = vec3(0.0);\n"
    "  float rf = smoothstep(1.0, 0.9, nfre);\n"
    "  scol += diff1*ndif1*nshd1;\n"
    "  scol += diff2*ndif2*nshd2;\n"
    "  scol += 0.1*(skyCol+skylineCol);\n"
    "  scol += nrcol*0.75*mix(vec3(0.25), rim, nfre);\n"
    "\n"
    "  col = mix(col, scol, rf*smoothstep(90.0, 20.0, dot(nsp, nsp)));\n"
    "  return col;\n"
    "}\n"
    "\n"
    "vec3 render1(vec3 ro, vec3 rd) {\n"
    "  vec3 skyCol0 = render0(ro, rd);\n"
    "  vec3 col = skyCol0;\n"
    "\n"
    "  float nt = rayMarch(ro, rd, 0.0);\n"
    "  if (nt < MAX_RAY_LENGTH) {\n"
    "    vec3 nsp  = ro + rd*nt;\n"
    "    vec3 nnor = normal(nsp);\n"
    "\n"
    "    vec3 nref  = reflect(rd, nnor);\n"
    "    float nrt  = rayMarch(nsp, nref, 0.2);\n"
    "    vec3 nrcol = render0(nsp, nref);\n"
    "\n"
    "    if (nrt < MAX_RAY_LENGTH) {\n"
    "      vec3 nrsp  = nsp + nref*nrt;\n"
    "      vec3 nrnor = normal(nrsp);\n"
    "      vec3 nrref = reflect(nref, nrnor);\n"
    "      nrcol = boxCol(nrcol, nrsp, nref, nrnor, render0(nrsp, nrref), 1.0, 1.0);\n"
    "    }\n"
    "\n"
    "    float nshd1 = mix(0.0, 1.0, shadow(nsp, normalize(lightPos1 - nsp), 0.1, distance(lightPos1, nsp)));\n"
    "    float nshd2 = mix(0.0, 1.0, shadow(nsp, normalize(lightPos2 - nsp), 0.1, distance(lightPos2, nsp)));\n"
    "\n"
    "    col = boxCol(col, nsp, rd, nnor, nrcol, nshd1, nshd2);\n"
    "  }\n"
    "\n"
    "  return col;\n"
    "}\n"
    "\n"
    "vec3 effect(vec2 p) {\n"
    "  g_rot0 = ROT(-0.2*TIME);\n"
    "\n"
    "  const float fov = tan(TAU/6.0);\n"
    "  const vec3 ro = vec3(0.0, 2.5, 5.0);\n"
    "  const vec3 la = vec3(0.0, 0.0, 0.0);\n"
    "  const vec3 up = vec3(0.1, 1.0, 0.0);\n"
    "\n"
    "  vec3 ww = normalize(la - ro);\n"
    "  vec3 uu = normalize(cross(up, ww));\n"
    "  vec3 vv = cross(ww,uu);\n"
    "  vec3 rd = normalize(-p.x*uu + p.y*vv + fov*ww);\n"
    "\n"
    "  return render1(ro, rd);\n"
    "}\n"
    "\n"
    "void main() {\n"
    "  vec2 fragCoord = gl_FragCoord.xy;\n"
    "  vec2 q = fragCoord/RESOLUTION.xy;\n"
    "  vec2 p = -1. + 2. * q;\n"
    "  p.x *= RESOLUTION.x/RESOLUTION.y;\n"
    "\n"
    "  vec3 col = effect(p);\n"
    "  col = aces_approx(col);\n"
    "  col = sRGB(col);\n"
    "  FragColor = vec4(col, 1.0);\n"
    "}\n";

    GLuint fs = CompileShader(GL_FRAGMENT_SHADER, CharBuffer);
    return fs;
}
Patrice
(Always working with the latest Windows version available...)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 2008
    • zapsolution
BBP_Glow plugin
« Reply #2 on: January 05, 2026, 10:19:41 am »
BBP_Glow

Converted from https://www.shadertoy.com/view/W3tSR4
Original created by Xor on 2025-08-23
Audio + color LUT + BBP_plugin integration by Patrice Terrier



Paste this in the BBProc section
Code: [Select]
    case BBP_CREATE:
        // Host asks: "who are you and what do you render to?"
        strcpy(BBP.title,"Volumetric Glow");
        strcpy(BBP.author, "Xor (Shadertoy)");
        BBP.version  = MAKEWORD(1,0);

        // Critical: This plugin renders using OpenGL into the host-provided GL context.
        BBP.renderto = BBP_OPENGL;

        // Default background ARGB used by host (informational/fallback).
        BBP.backargb = bbpARGB(255,0,0,0);
        break;

Paste this in the GLSL.h section
Code: [Select]
static GLuint CompileShaderFromString() {
    const char* CharBuffer =
    "#version 330 core\n"
    "\n"
    "uniform vec3  iResolution;\n"
    "uniform float iTime;\n"
    "uniform float iAudio;\n" // smoothed audio level (0..~1)
    "\n"
    "out vec4 FragColor;\n"
    "\n"
    "#define STEPS 50.0\n"
    "#define FOV   1.0\n"
    "#define BASE_DENSITY 1.5\n"
    "\n"
    "float Audio01() {\n"
    "    float a = max(iAudio, 0.0);\n"
    "    a = 1.0 - exp(-1.8 * a);\n"
    "    return clamp(a, 0.0, 1.0);\n"
    "}\n"
    "\n"
    "float volumeField(vec3 p, float density, float wfreq) {\n"
    "    float l = length(p);\n"
    "    vec3 v = cos(abs(p) * wfreq / max(4.0, l) + iTime);\n"
    "    return length(vec4(max(v, v.yzx) - 0.9, l - 4.0)) / density;\n"
    "}\n"
    "\n"
    "vec3 rotate90(vec3 p, vec3 a) {\n"
    "    return a * dot(p, a) + cross(p, a);\n"
    "}\n"
    "\n"
    "// MOIRE FIX: tiny stable per-pixel hash (no noise texture needed)\n"
    "float hash12(vec2 p) {\n"
    "    vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n"
    "    p3 += dot(p3, p3.yzx + 33.33);\n"
    "    return fract((p3.x + p3.y) * p3.z);\n"
    "}\n"
    "\n"
    "void main() {\n"
    "    vec2 fragCoord = gl_FragCoord.xy;\n"
    "    vec2 center = 2.0 * fragCoord - iResolution.xy;\n"
    "\n"
    "    float a = Audio01();\n"
    "\n"
    "    float breathe = 1.0 - 0.08 * a;\n"
    "\n"
    "    float density = BASE_DENSITY * (1.0 + 1.2 * a);\n"
    "    float wfreq   = 8.0 * mix(1.0, 0.65, a);\n"
    "    float brightness = 0.002 * (1.0 + 0.6 * a);\n"
    "\n"
    "    vec3 axis = normalize(cos(vec3(0.5 * iTime) + vec3(0.0, 2.0, 4.0)));\n"
    "\n"
    "    vec3 dir = rotate90(normalize(vec3(center, FOV * iResolution.y)), axis);\n"
    "\n"
    "    float camZ = -8.0 * mix(1.0, 0.92, a);\n"
    "    vec3 cam = rotate90(vec3(0.0, 0.0, camZ), axis);\n"
    "\n"
    "    // Start point\n"
    "    vec3 pos = cam;\n"
    "\n"
    "    // MOIRE FIX: jitter the start along the ray by a tiny amount (breaks band alignment)\n"
    "    float j = hash12(floor(fragCoord));\n"
    "    pos += dir * (j - 0.5) * 0.10;\n"
    "\n"
    "    vec3 col = vec3(0.0);\n"
    "\n"
    "    for (float i = 0.0; i < STEPS; i += 1.0) {\n"
    "        float vol = volumeField(pos * breathe, density, wfreq);\n"
    "        pos += dir * vol;\n"
    "        float inv = 1.0 / max(vol, 0.02);\n"
    "        col += (cos(pos.z / (1.0 + vol) + iTime + vec3(6.0, 1.0, 2.0)) + 1.2) * inv;\n"
    "    }\n"
    "\n"
    "    col = tanh(brightness * col);\n"
    "    FragColor = vec4(col, 1.0);\n"
    "}\n";

    GLuint fs = CompileShader(GL_FRAGMENT_SHADER, CharBuffer);
    return fs;
}
Patrice
(Always working with the latest Windows version available...)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 2008
    • zapsolution
BBP_DiscoBall plugin
« Reply #3 on: January 08, 2026, 01:54:21 pm »
BBP_DiscoBall

Converted from https://www.shadertoy.com/view/ssycDR
Original created by Shane on 2022-06-08
Audio + accumulator + BBP_plugin integration by Patrice Terrier



This plugin is based on a GLSL shader by Shane and required a true temporal accumulator to reproduce the original visual quality.

The effect relies on stochastic sampling and progressive convergence over time, which means a classic single-pass shader is not sufficient.
A floating-point ping-pong accumulator is used to achieve stable lighting, clean reflections, and low noise in dark areas.

This version goes further by adding audio-driven behavior:
  • Monotonic, audio-sensitive sphere rotation.
  • Automatic accumulation freeze during strong motion to avoid blur.
  • High sample count for stable dark regions.
  • Fully functional in landscape and portrait modes (BassBox64)
The result is a physically coherent, music-reactive disco sphere without geometry tricks or artificial brightness.

The full VS2022 source code is attached to this post.
You must also copy the OrganicUD.jpg texture, inside the bbplugin\texture folder.
« Last Edit: January 17, 2026, 09:54:33 am by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)