import { Vector2 , Vector3 , Matrix4 , Texture } from "three" ; export const rayMarchingVertexShaderSrc = [ "#ifdef GL_ES" , "precision highp float;" , "#endif" , "varying vec3 pObj;" , "void main()" , "{" , "  pObj = position;" , "  gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);" , "}" , ] . join ( "\n" ) ; export const rayMarchingFragmentShaderSrc = [ "#ifdef GL_ES" , "precision highp float;" , "#endif" , "#define M_PI 3.14159265358979323846" , "uniform vec2 iResolution;" , "uniform vec2 textureRes;" , "uniform float GAMMA_MIN;" , "uniform float GAMMA_MAX;" , "uniform float GAMMA_SCALE;" , "uniform float BRIGHTNESS;" , "uniform float DENSITY;" , "uniform float maskAlpha;" , "uniform float ATLAS_X;" , "uniform float ATLAS_Y;" , "uniform vec3 AABB_CLIP_MIN;" , "uniform float CLIP_NEAR;" , "uniform vec3 AABB_CLIP_MAX;" , "uniform float CLIP_FAR;" , "uniform sampler2D textureAtlas;" , "uniform sampler2D textureAtlasMask;" , "uniform int BREAK_STEPS;" , "uniform float SLICES;" , "uniform float isOrtho;" , "uniform float orthoThickness;" , "uniform float orthoScale;" , "uniform int maxProject;" , "uniform vec3 flipVolume;" , "uniform vec3 volumeScale;" , "uniform mat4 inverseModelViewMatrix;" , " varying vec3 pObj;" , "float powf(float a, float b){" , "  return pow(a,b);" , "}" , "float rand(vec2 co){" , "  float threadId = gl_FragCoord.x/(gl_FragCoord.y + 1.0);" , "  float bigVal = threadId*1299721.0/911.0;" , "  vec2 smallVal = vec2(threadId*7927.0/577.0, threadId*104743.0/1039.0);" , "  return fract(sin(dot(co, smallVal)) * bigVal);" , "}" , "vec4 luma2Alpha(vec4 color, float vmin, float vmax, float C){" , "  float x = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));" , "  float xi = (x-vmin)/(vmax-vmin);" , "  xi = clamp(xi,0.0,1.0);" , "  float y = pow(xi,C);" , "  y = clamp(y,0.0,1.0);" , "  color[3] = y;" , "  return(color);" , "}" , "vec2 offsetFrontBack(float t, float nx, float ny){" , "  int a = int(t);" , "  int ax = int(ATLAS_X);" , "  vec2 os = vec2(float(a-(a/ax)*ax) / ATLAS_X, float(a/ax) / ATLAS_Y);" , "  return os;" , "}" , "vec4 sampleAs3DTexture(sampler2D tex, vec4 pos) {" , "  float bounds = float(pos[0] >= 0.0 && pos[0] <= 1.0 &&" , "                       pos[1] >= 0.0 && pos[1] <= 1.0 &&" , "                       pos[2] >= 0.0 && pos[2] <= 1.0 );" , "  float nSlices = float(SLICES);" , "  vec2 loc0 = vec2(" , "    (flipVolume.x*(pos.x - 0.5) + 0.5)/ATLAS_X," , "    (flipVolume.y*(pos.y - 0.5) + 0.5)/ATLAS_Y);" , "loc0 = vec2(0.5/textureRes.x, 0.5/textureRes.y) + loc0*vec2(1.0-(ATLAS_X)/textureRes.x, 1.0-(ATLAS_Y)/textureRes.y);" , "  float z = (pos.z)*(nSlices-1.0);" , "  float zfloor = floor(z);" , "  float z0  = zfloor;" , "  float z1 = (zfloor+1.0);" , "  z1 = clamp(z1, 0.0, nSlices-1.0);" , "  float t = z-zfloor;" , "if (flipVolume.z == -1.0) {" , "    z0 = nSlices - z0 - 1.0;" , "    z1 = nSlices - z1 - 1.0;" , "    t = 1.0 - t;" , "}" , "  vec2 o0 = offsetFrontBack(z0,ATLAS_X,ATLAS_Y);//*pix;" , "  vec2 o1 = offsetFrontBack(z1,ATLAS_X,ATLAS_Y);//*pix;" , "  o0 = clamp(o0, vec2(0.0,0.0), vec2(1.0-1.0/ATLAS_X, 1.0-1.0/ATLAS_Y)) + loc0;" , "  o1 = clamp(o1, vec2(0.0,0.0), vec2(1.0-1.0/ATLAS_X, 1.0-1.0/ATLAS_Y)) + loc0;" , "  vec4 slice0Color = texture2D(tex, o0);" , "  vec4 slice1Color = texture2D(tex, o1);" , "  float slice0Mask = texture2D(textureAtlasMask, o0).x;" , "  float slice1Mask = texture2D(textureAtlasMask, o1).x;" , "  float maskVal = mix(slice0Mask, slice1Mask, t);" , "  maskVal = mix(maskVal, 1.0, maskAlpha);" , "  vec4 retval = mix(slice0Color, slice1Color, t);" , "  retval.rgb *= maskVal;" , "  return bounds*retval;" , "}" , "vec4 sampleStack(sampler2D tex, vec4 pos) {" , "  vec4 col = sampleAs3DTexture(tex, pos);" , "  col = luma2Alpha(col, GAMMA_MIN, GAMMA_MAX, GAMMA_SCALE);" , "return col;" , "}" , "bool intersectBox(in vec3 r_o, in vec3 r_d, in vec3 boxMin, in vec3 boxMax," , "                  out float tnear, out float tfar){" , "  vec3 invR = vec3(1.0,1.0,1.0) / r_d;" , "  vec3 tbot = invR * (boxMin - r_o);" , "  vec3 ttop = invR * (boxMax - r_o);" , "  vec3 tmin = min(ttop, tbot);" , "  vec3 tmax = max(ttop, tbot);" , "  float largest_tmin  = max(max(tmin.x, tmin.y), max(tmin.x, tmin.z));" , "  float smallest_tmax = min(min(tmax.x, tmax.y), min(tmax.x, tmax.z));" , "  tnear = largest_tmin;" , "  tfar = smallest_tmax;" , "  return(smallest_tmax > largest_tmin);" , "}" , "vec4 accumulate(vec4 col, float s, vec4 C) {" , "    float stepScale = (1.0 - powf((1.0-col.w),s));" , "    col.w = stepScale;" , "    col.xyz *= col.w;" , "    col = clamp(col,0.0,1.0);" , "    C = (1.0-C.w)*col + C;" , "    return C;" , "}" , "vec4 accumulateMax(vec4 col, float s, vec4 C) {" , "    if (col.x*col.w > C.x) { C.x = col.x*col.w; }" , "    if (col.y*col.w > C.y) { C.y = col.y*col.w; }" , "    if (col.z*col.w > C.z) { C.z = col.z*col.w; }" , "    if (col.w > C.w) { C.w = col.w; }" , "    return C;" , "}" , "vec4 integrateVolume(vec4 eye_o,vec4 eye_d," , "                     float tnear,   float tfar," , "                     float clipNear, float clipFar," , "                     sampler2D textureAtlas" , "                     ){" , " vec4 C = vec4(0.0);" , " float tend   = tfar;" , " float tbegin = tnear;" , "  const int maxSteps = 512;" , "  float scaledSteps = float(BREAK_STEPS) * length((eye_d.xyz/volumeScale));" , "  float csteps = clamp(float(scaledSteps), 1.0, float(maxSteps));" , "  float invstep = (tfar-tnear)/csteps;" , "  float r = (SLICES==1.0) ?  0.0 : 0.5 - 1.0*rand(eye_d.xy);" , "  float tstep = invstep*orthoThickness;" , "  float tfarsurf = r*tstep;" , "  float overflow = mod((tfarsurf - tend),tstep);" , "  float t = tbegin + overflow;" , "  t += r*tstep;" , "  float tdist = 0.0;" , "  int numSteps = 0;" , "vec4 pos, col;" , "    float s = 0.5 * float(maxSteps) / csteps;" , "for(int i=0; i<maxSteps; i++){" , "  pos = eye_o + eye_d*t;" , "  pos.xyz = (pos.xyz-(-0.5))/((0.5)-(-0.5)); //0.5 * (pos + 1.0); // map position from [boxMin, boxMax] to [0, 1] coordinates" , "  col = sampleStack(textureAtlas,pos);" , "      col.xyz *= BRIGHTNESS;" , "    if (maxProject != 0) {" , "      C = accumulateMax(col, s, C);" , "    } else {" , "      col.w *= DENSITY;" , "      C = accumulate(col, s, C);" , "    }" , "    t += tstep;" , "    numSteps = i;" , "    if (t  > tend || t > tbegin+clipFar ) break;" , "    if (C.w > 1.0 ) break;" , "}" , "  return C;" , "}" , "void main()" , "{" , "  gl_FragColor = vec4(0.0);" , "  vec2 vUv = gl_FragCoord.xy/iResolution.xy;" , "  vec3 eyeRay_o, eyeRay_d;" , "  if (isOrtho == 0.0) {" , "    eyeRay_o = (inverseModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;" , "    eyeRay_d = normalize(pObj - eyeRay_o);" , "  }" , "  else {" , "    float zDist = 2.0;" , "    eyeRay_d = (inverseModelViewMatrix*vec4(0.0, 0.0, -zDist, 0.0)).xyz;" , "    vec4 ray_o = vec4(2.0*vUv - 1.0, 1.0, 1.0);" , "    ray_o.xy *= orthoScale;" , "    ray_o.x *= iResolution.x/iResolution.y;" , "    eyeRay_o   = (inverseModelViewMatrix*ray_o).xyz;" , "  }" , "  vec3 boxMin = AABB_CLIP_MIN;" , "  vec3 boxMax = AABB_CLIP_MAX;" , "  float tnear, tfar;" , "  bool hit = intersectBox(eyeRay_o, eyeRay_d, boxMin, boxMax, tnear, tfar);" , "  if (!hit) {" , "     gl_FragColor = vec4(0.0);" , "     return;" , "  }" , "  float clipNear = 0.0;//-(dot(eyeRay_o.xyz, eyeNorm) + dNear) / dot(eyeRay_d.xyz, eyeNorm);" , "  float clipFar  = 10000.0;//-(dot(eyeRay_o.xyz,-eyeNorm) + dFar ) / dot(eyeRay_d.xyz,-eyeNorm);" , "  vec4 C = integrateVolume(vec4(eyeRay_o,1.0), vec4(eyeRay_d,0.0)," , "                           tnear,    tfar," , "                           clipNear, clipFar," , "                           textureAtlas);//,nBlocks);" , "  C = clamp(C, 0.0, 1.0);" , "  gl_FragColor = C;" , "  return;" , "}" , ] . join ( "\n" ) ; export const rayMarchingShaderUniforms = { iResolution : { type : "v2" , value : new Vector2 ( 100 , 100 ) , } , CLIP_NEAR : { type : "f" , value : 0.0 , } , CLIP_FAR : { type : "f" , value : 10000.0 , } , maskAlpha : { type : "f" , value : 1.0 , } , BRIGHTNESS : { type : "f" , value : 0.0 , } , DENSITY : { type : "f" , value : 1.0 , } , GAMMA_MIN : { type : "f" , value : 0.0 , } , GAMMA_MAX : { type : "f" , value : 1.0 , } , GAMMA_SCALE : { type : "f" , value : 1.0 , } , BREAK_STEPS : { type : "i" , value : 128 , } , ATLAS_X : { type : "f" , value : 6 , } , ATLAS_Y : { type : "f" , value : 6 , } , SLICES : { type : "f" , value : 50 , } , isOrtho : { type : "f" , value : 0.0 , } , orthoThickness : { type : "f" , value : 1.0 , } , orthoScale : { type : "f" , value : 0.5 , } , AABB_CLIP_MIN : { type : "v3" , value : new Vector3 ( - 0.5 , - 0.5 , - 0.5 ) , } , AABB_CLIP_MAX : { type : "v3" , value : new Vector3 ( 0.5 , 0.5 , 0.5 ) , } , inverseModelViewMatrix : { type : "m4" , value : new Matrix4 ( ) , } , textureAtlas : { type : "t" , value : new Texture ( ) , } , textureAtlasMask : { type : "t" , value : new Texture ( ) , } , maxProject : { type : "i" , value : 0 , } , flipVolume : { type : "v3" , value : new Vector3 ( 1.0 , 1.0 , 1.0 ) , } , volumeScale : { type : "v3" , value : new Vector3 ( 1.0 , 1.0 , 1.0 ) , } , textureRes : { type : "v2" , value : new Vector2 ( 1.0 , 1.0 ) , } , } ;