The Code Therapy

noise3DTexture

Just a visual representation for the initial implementation tests of a sampler3D built-in pre-loaded noise texture.

Created by marcogomez on Wed, 06 Oct 2021 15:39:10 GMT.


#version 300 es
// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp sampler3D;
precision highp float;

uniform sampler3D noise3DTexture;
uniform vec2 resolution;
uniform vec2 mouselerp;
uniform float time;

out vec4 fragColor;

const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const int marchSteps = 256;
const int sdfDetectSteps = 64;
const float maxDist = 250.0;
const float minDist = 0.2;

struct Box { vec3 Position; vec3 EdgeLength; };
Box mBox = Box(vec3(0.0), vec3(16.0));
struct Camera { vec3 Position; vec3 LookAt; float ImageHeight; float FocalDistance; };
Camera mCamera = Camera(vec3(120.0, 20.0, -165.0), vec3(0.0), 2.0, 7.0 );

float sdBox(vec3 p, vec3 b) {
  vec3 q = abs(p) - b;
  return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)),0.0);
}

float volumeDistField(vec3 pos) {
  float sdfValue = sdBox(pos - mBox.Position, mBox.EdgeLength);
  return sdfValue;
}

float intersectRayMarch(vec3 rayOrigin, vec3 rayDirection) {
  float d = 0.0;
  for (int i = 0; i < sdfDetectSteps; i++) {
    float dist = volumeDistField(rayOrigin + rayDirection * d);
    if (dist < minDist || d > maxDist) { break; }
    d += dist;
  }
  return d >= maxDist ? -1.0 : d;
}

vec3 camOrbit(float speedRatio) {
  float theta = time * speedRatio;
  float radius = 165.0;
  vec2 m = (length(mouselerp) > 0.001)
    ? mouselerp
    : vec2(sin(theta), cos(theta) * sin(theta)) * 0.5;
  return vec3(
    radius * cos(m.x * PI),
    radius * cos((m.y * 0.5 + 0.5) * PI),
    radius * sin(m.x * PI)
  );
}

void setCam(vec2 uv, float ar, out vec3 rayOrigin, out vec3 rayDir) {
  float imageWidth = mCamera.ImageHeight * ar;
  vec3 position = camOrbit(0.3);
  vec3 camView = mCamera.LookAt - position;
  float camViewLength = length(camView);
  vec3 camViewDir = camView / camViewLength;
  vec3 camRight = cross(camViewDir, vec3(0.0, 1.0, 0.0));
  vec3 camUp = cross(camRight, camViewDir);
  vec3 focalPoint = position - mCamera.FocalDistance * camViewDir;
  vec3 point = position;
  point += camRight * (uv.x * 2.0 - 1.0) * imageWidth * 0.5;
  point += camUp * (uv.y * 2.0 - 1.0) * mCamera.ImageHeight * 0.5;
  rayOrigin = focalPoint;
  rayDir = normalize(point - focalPoint);
}

vec3 getLight(void) { return vec3(0.03); }

vec3 render(vec3 rayOrigin, vec3 rayDirection) {
  float volumeDepth = intersectRayMarch(rayOrigin, rayDirection);
  vec3 volumetricColor = vec3(0.0);
  if (volumeDepth > 0.0) {
    float signedDistance = 0.0;
    for (int i = 0; i < marchSteps; i++) {
      volumeDepth += max(minDist, signedDistance);
      vec3 position = rayOrigin + volumeDepth * rayDirection;
      signedDistance = volumeDistField(position);
      if (signedDistance < 0.0) {
        float scale = 32.0;
        vec3 conner = mBox.Position - mBox.EdgeLength;
        float value = texture(noise3DTexture, (position - conner) / scale).x;
        float target = 0.5;
        if (value < target || value > target + (minDist / 4.0)) { value = 0.0; }
        volumetricColor += value * getLight();
      }
    }
  }
  return min(volumetricColor, 1.0);
}

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  float ar = resolution.x /  resolution.y;
  float i = (floor((sin(time) * 0.5 + 0.5) * 32.0) + 0.5) / 32.0;
  vec3 bgCol = texture(noise3DTexture,vec3(uv * vec2(1.0, ar) * vec2(2.02, 1.0), i)).rrr;
  vec4 bg = vec4(bgCol, 1.0) * 0.1;
  vec3 rayOrigin, rayDirection;
  setCam(uv, ar, rayOrigin, rayDirection);
  vec3 color = render(rayOrigin, rayDirection);
  fragColor = bg + vec4(color, 1.0);
}