Replace project with current server release and Windows setup
Import the 2026-10-09 source release, Fastify/SQLite backend, restored source assets, and analytics-enabled server build. Replace files from the previous release while retaining the existing repository history. Make builds portable across Windows and Linux, configure local startup, normalize Windows static asset paths, and fix test fixture cleanup and file URL handling. Exclude local environment settings, databases, dependencies, validation output, and TypeScript build cache from version control. Validation: npm ci, static and server builds, 106 arrival tests, and actual local HTTP checks passed. The full suite passed 467 of 470 tests; three tests still require QA fixtures omitted from the supplied release, documented in README-서버실행.md.
This commit is contained in:
+535
@@ -0,0 +1,535 @@
|
||||
import{a as e,c as t,d as n,f as r,h as i,i as a,l as o,m as s,n as c,o as l,p as u,r as ee,u as d}from"./index-BYcEjj7E.js";var f=`uniform sampler2D uSceneTexture,uSceneDepth;
|
||||
uniform sampler2D uProtectionDepthMap;
|
||||
uniform mat4 uContentViewProjection,uContentInverseViewProjection;
|
||||
uniform mat4 uPetWorldToLocal;
|
||||
uniform vec3 uContentCameraPosition,uLightPosition,uBackgroundColor;
|
||||
uniform float uGlassZ,uSourceZ,uGridSize,uStrength,uMosaicStyle,uCurvature,uGlossStrength;
|
||||
uniform vec2 uViewOffset,uPetSize,uPaneSize;
|
||||
uniform vec2 uDepthEvidenceRange,uDepthCorrection;
|
||||
uniform float uEnvironmentStrength;
|
||||
uniform vec4 uGobangSurface;
|
||||
uniform float uGobangEnvironmentStrength;
|
||||
uniform float uGobangBevelRound;
|
||||
uniform vec4 uPaneRect;
|
||||
uniform sampler2D uRegionPalette;
|
||||
uniform sampler2D uRegionAtlas,uRegionHistory;
|
||||
uniform vec2 uRegionAtlasSize,uRegionGridSize,uRegionPaletteSize;
|
||||
uniform float uRegionStrength,uRegionAvailable;
|
||||
varying vec2 vUv;
|
||||
vec2 projectUv(vec3 p){vec4 c=uContentViewProjection*vec4(p,1.);float w=abs(c.w)<.0001?(c.w<0.?-.0001:.0001):c.w;return c.xy/w*.5+.5;}
|
||||
vec4 sampleScene(vec2 uv){return texture2D(uSceneTexture,clamp(uv,0.,1.));}
|
||||
vec4 samplePane(vec2 pane){return sampleScene(projectUv(vec3((pane-.5)*uPaneSize,uGlassZ)));}
|
||||
float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}
|
||||
vec2 hash2(vec2 p){return vec2(hash(p),hash(p+vec2(19.19,73.73)));}
|
||||
vec2 cellBlurStep(vec2 cell,vec2 cellSize,float style){
|
||||
if(style<=.5)return cellSize*mix(.006,.018,hash(cell+vec2(5.)));
|
||||
return cellSize*mix(.006,.012,hash(cell+vec2(5.)));
|
||||
}
|
||||
vec4 sampleCell(vec2 pane,vec2 sourceUv,float strength,vec2 cell,vec2 cellSize,float style){
|
||||
vec2 center=mix(pane,sourceUv,strength);
|
||||
vec2 blurOffset=strength*cellBlurStep(cell,cellSize,style);
|
||||
vec4 color;
|
||||
if(style<=.5){
|
||||
color=samplePane(center)*.6;
|
||||
color+=samplePane(center+vec2(blurOffset.x,0.))*.1;
|
||||
color+=samplePane(center-vec2(blurOffset.x,0.))*.1;
|
||||
color+=samplePane(center+vec2(0.,blurOffset.y))*.1;
|
||||
color+=samplePane(center-vec2(0.,blurOffset.y))*.1;
|
||||
}else{
|
||||
color=samplePane(center)*.4;
|
||||
color+=samplePane(center+vec2(blurOffset.x,0.))*.15;
|
||||
color+=samplePane(center-vec2(blurOffset.x,0.))*.15;
|
||||
color+=samplePane(center+vec2(0.,blurOffset.y))*.15;
|
||||
color+=samplePane(center-vec2(0.,blurOffset.y))*.15;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
float safeZ(float z){return abs(z)<.0001?(z<0.?-.0001:.0001):z;}
|
||||
vec3 bend(vec3 i,vec3 n){vec3 r=refract(i,n,.75);return length(r)<.0001?i:r;}
|
||||
float softLimit(float value,float limit){return value*limit/(limit+abs(value));}
|
||||
float surfaceCurvature(){float curvature=clamp(uCurvature,-1.,1.),excess=max(curvature-.65,0.);return curvature-(.25/.35)*excess*excess;}
|
||||
float signedCurvatureScale(){return clamp(surfaceCurvature()/.65,-1.25,1.25);}
|
||||
float regionDistance(vec3 a,vec3 b){vec3 d=a-b;float y=dot(d,vec3(.299,.587,.114));return dot(d,d)+.35*y*y;}
|
||||
float regionLuminance(vec3 c){return dot(c,vec3(.299,.587,.114));}
|
||||
vec3 regionColor(vec2 cell,float index){vec2 uv=(vec2(cell.x*5.+index,cell.y)+.5)/uRegionPaletteSize;return texture2D(uRegionPalette,uv).rgb;}
|
||||
float nearestRegion(vec3 color,vec2 cell){float best=0.,distance=regionDistance(color,regionColor(cell,0.));for(int i=1;i<4;i++){float candidate=regionDistance(color,regionColor(cell,float(i)));if(candidate<distance){distance=candidate;best=float(i);}}return best;}
|
||||
float nearestRegion(vec3 color,vec3 p0,vec3 p1,vec3 p2,vec3 p3){float best=0.,distance=regionDistance(color,p0);float candidate=regionDistance(color,p1);if(candidate<distance){distance=candidate;best=1.;}candidate=regionDistance(color,p2);if(candidate<distance){distance=candidate;best=2.;}candidate=regionDistance(color,p3);if(candidate<distance)best=3.;return best;}
|
||||
vec3 selectRegion(vec3 p0,vec3 p1,vec3 p2,vec3 p3,float index){if(index<.5)return p0;if(index<1.5)return p1;if(index<2.5)return p2;return p3;}
|
||||
vec3 regionAtlasColor(vec2 cell,vec2 texel){vec2 uv=(cell*8.+clamp(texel,vec2(0.),vec2(7.))+.5)/uRegionAtlasSize;return texture2D(uRegionAtlas,uv).rgb;}
|
||||
bool reconstructScenePoint(vec2 sceneUv,out vec3 worldPoint){
|
||||
if(sceneUv.x<0.||sceneUv.x>1.||sceneUv.y<0.||sceneUv.y>1.)return false;
|
||||
float depth=texture2D(uSceneDepth,sceneUv).x;
|
||||
if(depth>=.999999)return false;
|
||||
vec4 clip=vec4(sceneUv*2.-1.,depth*2.-1.,1.);
|
||||
vec4 world=uContentInverseViewProjection*clip;
|
||||
if(abs(world.w)<.0001)return false;
|
||||
worldPoint=world.xyz/world.w;
|
||||
return true;
|
||||
}
|
||||
float regionSurfaceValid(vec2 sceneUv,vec3 glassHit){
|
||||
vec3 worldPoint;
|
||||
if(!reconstructScenePoint(sceneUv,worldPoint))return 0.;
|
||||
float axialGap=glassHit.z-worldPoint.z;
|
||||
if(axialGap<=.0001)return 0.;
|
||||
return 1.;
|
||||
}
|
||||
float regionProtectionWeight(vec2 sceneUv){
|
||||
vec3 worldPoint;
|
||||
if(!reconstructScenePoint(sceneUv,worldPoint))return 0.;
|
||||
vec3 localPoint=(uPetWorldToLocal*vec4(worldPoint,1.)).xyz;
|
||||
if(localPoint.x<-.5||localPoint.x>.5||localPoint.y<-.5||localPoint.y>.5)return 0.;
|
||||
vec2 sourceUv=localPoint.xy+.5;
|
||||
float sourceDepth=texture2D(uProtectionDepthMap,sourceUv).r;
|
||||
if(uDepthEvidenceRange.y-uDepthEvidenceRange.x<.0001)return 0.;
|
||||
return smoothstep(uDepthEvidenceRange.x,uDepthEvidenceRange.y,sourceDepth);
|
||||
}
|
||||
// Screen-depth refinement of an artistic ray. Occluded surfaces are unavailable;
|
||||
// retain the original sample if the visible-depth solve cannot converge.
|
||||
vec3 refineSceneHit(vec3 glassHit,vec3 ray,vec3 artisticHit,float cellWorld){
|
||||
vec3 planeHit=glassHit+ray*((uSourceZ-glassHit.z)/safeZ(ray.z));
|
||||
vec3 origin=glassHit+vec3(artisticHit.xy-planeHit.xy,0.);
|
||||
vec3 hit=artisticHit,surface;
|
||||
for(int iteration=0;iteration<3;iteration++){
|
||||
if(!reconstructScenePoint(projectUv(hit),surface))return artisticHit;
|
||||
vec3 localPoint=(uPetWorldToLocal*vec4(surface,1.)).xyz;
|
||||
if(any(greaterThan(abs(localPoint.xy),vec2(.5)))||surface.z>=uGlassZ-.0001)return artisticHit;
|
||||
hit=origin+ray*((surface.z-origin.z)/safeZ(ray.z));
|
||||
}
|
||||
if(!reconstructScenePoint(projectUv(hit),surface))return artisticHit;
|
||||
if(surface.z>=uGlassZ-.0001)return artisticHit;
|
||||
float confidence=1.-smoothstep(cellWorld*.05,cellWorld*.25,abs(hit.z-surface.z));
|
||||
// Compare at the same reference Z, so only the projected sampling position changes.
|
||||
vec3 viewRay=hit-uContentCameraPosition;
|
||||
vec3 projected=uContentCameraPosition+viewRay*((uSourceZ-uContentCameraPosition.z)/safeZ(viewRay.z));
|
||||
vec2 delta=projected.xy-artisticHit.xy;
|
||||
float limit=cellWorld*uDepthCorrection.y;
|
||||
delta*=min(1.,limit/max(length(delta),.00001));
|
||||
return artisticHit+vec3(delta*uDepthCorrection.x*confidence,0.);
|
||||
}
|
||||
#ifdef REGION_ATLAS
|
||||
float regionAtlasEvidence(vec2 sceneUv,vec3 color,vec3 glassHit){
|
||||
if(regionSurfaceValid(sceneUv,glassHit)<=0.)return 0.;
|
||||
return regionProtectionWeight(sceneUv)*(1.-smoothstep(.10,.20,regionLuminance(color)));
|
||||
}
|
||||
vec4 regionAtlasProbe(vec3 sceneHit,vec2 worldOffset,vec3 glassHit){
|
||||
vec2 probeSceneUv=projectUv(sceneHit+vec3(worldOffset,0.));
|
||||
vec4 probe=sampleScene(probeSceneUv);
|
||||
return vec4(probe.rgb,regionAtlasEvidence(probeSceneUv,probe.rgb,glassHit));
|
||||
}
|
||||
vec4 regionAtlasScore(vec3 centerColor,float centerEvidence,vec3 probeColor,float probeEvidence){
|
||||
float evidenceGain=probeEvidence-centerEvidence,darkGain=regionLuminance(centerColor)-regionLuminance(probeColor),blend=0.;
|
||||
if(probeEvidence>.05&&evidenceGain>.02&&darkGain>.015)blend=min(.4,evidenceGain*2.)*min(1.,max(0.,darkGain*4.));
|
||||
return vec4(blend,probeEvidence,0.,0.);
|
||||
}
|
||||
vec3 regionAtlasRepresentative(vec3 centerColor,float centerEvidence,vec3 sceneHit,vec3 glassHit,out float evidence){
|
||||
vec3 bestColor=centerColor;float bestEvidence=centerEvidence,bestBlend=0.;
|
||||
vec2 probeStep=uPaneSize/(uRegionGridSize*8.)*.25;
|
||||
vec4 probe,score;
|
||||
probe=regionAtlasProbe(sceneHit,vec2(probeStep.x,0.),glassHit);score=regionAtlasScore(centerColor,centerEvidence,probe.rgb,probe.a);if(score.x>bestBlend){bestColor=mix(centerColor,probe.rgb,score.x);bestEvidence=max(centerEvidence,probe.a);bestBlend=score.x;}
|
||||
probe=regionAtlasProbe(sceneHit,vec2(-probeStep.x,0.),glassHit);score=regionAtlasScore(centerColor,centerEvidence,probe.rgb,probe.a);if(score.x>bestBlend){bestColor=mix(centerColor,probe.rgb,score.x);bestEvidence=max(centerEvidence,probe.a);bestBlend=score.x;}
|
||||
probe=regionAtlasProbe(sceneHit,vec2(0.,probeStep.y),glassHit);score=regionAtlasScore(centerColor,centerEvidence,probe.rgb,probe.a);if(score.x>bestBlend){bestColor=mix(centerColor,probe.rgb,score.x);bestEvidence=max(centerEvidence,probe.a);bestBlend=score.x;}
|
||||
probe=regionAtlasProbe(sceneHit,vec2(0.,-probeStep.y),glassHit);score=regionAtlasScore(centerColor,centerEvidence,probe.rgb,probe.a);if(score.x>bestBlend){bestColor=mix(centerColor,probe.rgb,score.x);bestEvidence=max(centerEvidence,probe.a);bestBlend=score.x;}
|
||||
evidence=bestEvidence;
|
||||
return bestColor;
|
||||
}
|
||||
#endif
|
||||
void evaluateCell(vec2 cell,vec2 local,vec2 grid,vec2 cellSize,vec2 cellDimensions,float cellWorld,float opticalTravel,float style,out vec2 affineUv,out mat2 transform,out vec2 curvedSlope,out vec2 facetSlope){
|
||||
vec2 random=hash2(cell),widths;
|
||||
if(style>.5){
|
||||
widths=mix(vec2(.82),vec2(1.12),hash2(cell+vec2(11.4,9.8)));
|
||||
float angle=(random.x-.5)*.08,c=cos(angle),s=sin(angle);
|
||||
transform=mat2(widths.x*c,-widths.y*s,widths.x*s,widths.y*c);
|
||||
float centerJitter=.16;
|
||||
vec2 sourceCenter=(cell+.5)/grid+(random-.5)*centerJitter*cellSize;
|
||||
affineUv=sourceCenter+transform*(local*cellSize);
|
||||
}else{
|
||||
// Default style keeps a single continuous image footprint across cells.
|
||||
transform=mat2(1.);
|
||||
affineUv=(cell+.5)/grid+local*cellSize;
|
||||
}
|
||||
|
||||
// Positive height bulges toward the observer (+Z); negative height is concave.
|
||||
float curvature=clamp(uCurvature,-1.,1.),surfaceCurvatureValue=surfaceCurvature();
|
||||
vec2 q=clamp(2.*local,-1.,1.),q2=q*q,q3=q2*q,b=1.-q2*q2;
|
||||
if(style>.5){
|
||||
float amplitude=mix(.92,1.08,hash(cell+vec2(41.7,17.3))),height=.009*cellWorld*surfaceCurvatureValue*amplitude;
|
||||
vec2 skew=(hash2(cell+vec2(23.8,61.2))-.5)*.28;float asym=1.+dot(skew,q);
|
||||
vec2 dhdq=height*vec2(-4.*q3.x*b.y*asym+b.x*b.y*skew.x,-4.*q3.y*b.x*asym+b.x*b.y*skew.y);
|
||||
vec2 grad=-2.*dhdq/cellDimensions;
|
||||
curvedSlope=grad+(random-.5)*.012;facetSlope=(random-.5)*.012;
|
||||
}else{
|
||||
curvedSlope=.30*cellDimensions/max(abs(opticalTravel),.6)*signedCurvatureScale()*sin(6.2831853*local);
|
||||
facetSlope=vec2(0.);
|
||||
}
|
||||
}
|
||||
#ifndef REGION_ATLAS
|
||||
// Broad prism faces, with narrow rounded transitions at the ridge and center.
|
||||
// The height and slope meet at cell boundaries; no outline is painted on top.
|
||||
float gobangProfile(float coordinate,out float derivative){
|
||||
float span=.5-uGobangSurface.y;
|
||||
float t=clamp((abs(coordinate)-uGobangSurface.y)/span,0.,1.);
|
||||
float rounding=uGobangBevelRound,ramp=t-rounding*.5,slope=1.;
|
||||
if(t<rounding){ramp=t*t/(2.*rounding);slope=t/rounding;}
|
||||
else if(t>1.-rounding){ramp=1.-rounding-(1.-t)*(1.-t)/(2.*rounding);slope=(1.-t)/rounding;}
|
||||
derivative=-slope*sign(coordinate)/(span*(1.-rounding));
|
||||
return 1.-ramp/(1.-rounding);
|
||||
}
|
||||
void gobangSurface(vec2 paneUv,vec2 grid,vec2 dimensions,float cellWorld,out float height,out vec3 normal){
|
||||
vec2 local=fract(paneUv*grid)-.5;
|
||||
float dx,dy;
|
||||
float px=gobangProfile(local.x,dx),py=gobangProfile(local.y,dy);
|
||||
// Crossing directional ribs produce rectangular optical pieces. A minimum
|
||||
// of X/Y profiles would instead produce conspicuous diagonal triangles.
|
||||
float shape=.25*px+.55*py+.20*px*py;
|
||||
vec2 shapeDerivative=vec2((.25+.20*py)*dx,(.55+.20*px)*dy);
|
||||
// A small continuous ripple bends the ribs without independent cell crops.
|
||||
vec2 phase=paneUv*grid*6.2831853;
|
||||
float ripple=.008*sin(phase.x*3.+sin(phase.y))*sin(phase.y);
|
||||
vec2 rippleDerivative=.008*6.2831853*vec2(3.*cos(phase.x*3.+sin(phase.y))*sin(phase.y),cos(phase.x*3.+sin(phase.y))*cos(phase.y)*sin(phase.y)+sin(phase.x*3.+sin(phase.y))*cos(phase.y));
|
||||
float amplitude=uGobangSurface.x*cellWorld*clamp(uCurvature,-1.,1.);
|
||||
height=amplitude*(shape+ripple);
|
||||
vec2 gradient=amplitude*(shapeDerivative+rippleDerivative)/dimensions;
|
||||
normal=normalize(vec3(-gradient,1.));
|
||||
}
|
||||
vec4 renderGobang(vec3 incident,vec3 glassHit,vec2 paneUv,vec2 grid,float cellWorld){
|
||||
vec2 dimensions=uPaneSize/grid;
|
||||
float height;vec3 normal;
|
||||
gobangSurface(paneUv,grid,dimensions,cellWorld,height,normal);
|
||||
// Two refinements locate the shallow front surface along this camera ray.
|
||||
vec3 frontHit=glassHit;
|
||||
for(int iteration=0;iteration<2;iteration++){
|
||||
frontHit=uContentCameraPosition+incident*((uGlassZ+height-uContentCameraPosition.z)/safeZ(incident.z));
|
||||
gobangSurface(frontHit.xy/uPaneSize+.5,grid,dimensions,cellWorld,height,normal);
|
||||
}
|
||||
float ior=uGobangSurface.z;
|
||||
vec3 internalRay=refract(incident,normal,1./ior);
|
||||
float backZ=uGlassZ-uGobangSurface.w-uGobangSurface.x*cellWorld;
|
||||
vec3 backHit=frontHit+internalRay*((backZ-frontHit.z)/safeZ(internalRay.z));
|
||||
vec3 exitRay=refract(internalRay,vec3(0.,0.,1.),ior);
|
||||
float transmission=step(.0001,dot(exitRay,exitRay));
|
||||
if(transmission<.5)exitRay=incident;
|
||||
vec3 sourceHit=backHit+exitRay*((uSourceZ-backHit.z)/safeZ(exitRay.z));
|
||||
vec3 straightSource=glassHit+incident*((uSourceZ-glassHit.z)/safeZ(incident.z));
|
||||
float edgeDistance=min(min(paneUv.x,paneUv.y),min(1.-paneUv.x,1.-paneUv.y));
|
||||
float paneWeight=smoothstep(0.,max(1./grid.x,1./grid.y)*.75,edgeDistance);
|
||||
float amount=clamp(uStrength,0.,1.)*paneWeight;
|
||||
sourceHit=mix(straightSource,sourceHit,amount);
|
||||
// Reuse the visible-depth solve; hidden surfaces still fall back to the plane.
|
||||
sourceHit=refineSceneHit(backHit,normalize(mix(incident,exitRay,amount)),sourceHit,cellWorld);
|
||||
vec4 result=sampleScene(projectUv(sourceHit));
|
||||
|
||||
// One static room environment; the same surface normal controls its reflection.
|
||||
vec3 viewDirection=-incident,reflected=reflect(incident,normal);
|
||||
float fresnel=.04+.96*pow(1.-clamp(dot(normal,viewDirection),0.,1.),5.);
|
||||
vec3 room=mix(vec3(.09,.13,.17),vec3(.78,.84,.86),smoothstep(-.4,.65,reflected.y));
|
||||
float lightTravel=(uLightPosition.z-frontHit.z)/safeZ(reflected.z);
|
||||
vec2 lightUv=(frontHit.xy+reflected.xy*lightTravel-uLightPosition.xy)/(min(uPaneSize.x,uPaneSize.y)*vec2(.38,.52));
|
||||
vec2 window=1.-smoothstep(vec2(.75),vec2(1.1),abs(lightUv));
|
||||
float windowLight=window.x*window.y*step(0.,lightTravel)*step(.001,reflected.z);
|
||||
room=mix(room,vec3(.94,.97,1.),windowLight);
|
||||
float mullion=1.-smoothstep(.015,.06,abs(reflected.x+.12));
|
||||
room=mix(room,vec3(.12,.16,.20),mullion*.55);
|
||||
float gloss=clamp(uGlossStrength,0.,1.);
|
||||
float reflectionWeight=gloss*uGobangEnvironmentStrength*(.35+.65*fresnel)*amount;
|
||||
reflectionWeight=mix(reflectionWeight,1.,(1.-transmission)*amount);
|
||||
result.rgb=mix(result.rgb,room,reflectionWeight);
|
||||
result.a=1.;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
void main(){
|
||||
vec2 screenUv=vUv;
|
||||
#ifdef REGION_ATLAS
|
||||
vec2 atlasPixel=floor(vUv*uRegionAtlasSize),atlasCell=floor(atlasPixel/8.),atlasLocal=(mod(atlasPixel,8.)+.5)/8.;
|
||||
vec2 atlasPaneUv=(atlasCell+atlasLocal)/uRegionGridSize;
|
||||
screenUv=projectUv(vec3((atlasPaneUv-.5)*uPaneSize,uGlassZ));
|
||||
#endif
|
||||
if(uStrength<=.001){
|
||||
#ifdef REGION_ATLAS
|
||||
gl_FragColor=vec4(sampleScene(screenUv).rgb,0.);
|
||||
#else
|
||||
gl_FragColor=sampleScene(screenUv);
|
||||
#include <colorspace_fragment>
|
||||
#endif
|
||||
return;}
|
||||
vec4 f=uContentInverseViewProjection*vec4(screenUv*2.-1.,1.,1.);float fw=abs(f.w)<.0001?(f.w<0.?-.0001:.0001):f.w;vec3 farWorld=f.xyz/fw;vec3 i=normalize(farWorld-uContentCameraPosition);float gt=(uGlassZ-uContentCameraPosition.z)/safeZ(i.z);vec3 gh=uContentCameraPosition+i*gt;
|
||||
vec2 paneUv=gh.xy/uPaneSize+.5;vec2 grid=vec2(uGridSize,max(1.,uGridSize*uPaneSize.y/uPaneSize.x));vec2 gridUv=paneUv*grid,cell=floor(gridUv),local=fract(gridUv)-.5,cellSize=1./grid;float style=clamp(uMosaicStyle,0.,2.),cellWorld=min(uPaneSize.x/grid.x,uPaneSize.y/grid.y);
|
||||
#ifdef REGION_ATLAS
|
||||
paneUv=atlasPaneUv;grid= uRegionGridSize;gridUv=paneUv*grid;cell=floor(gridUv);local=fract(gridUv)-.5;cellSize=1./grid;cellWorld=min(uPaneSize.x/grid.x,uPaneSize.y/grid.y);
|
||||
#endif
|
||||
if(paneUv.x<0.||paneUv.x>1.||paneUv.y<0.||paneUv.y>1.){
|
||||
#ifdef REGION_ATLAS
|
||||
gl_FragColor=vec4(uBackgroundColor,0.);
|
||||
#else
|
||||
gl_FragColor=vec4(uBackgroundColor,1.);
|
||||
#include <colorspace_fragment>
|
||||
#endif
|
||||
return;}
|
||||
#ifndef REGION_ATLAS
|
||||
if(style>1.5){
|
||||
gl_FragColor=renderGobang(i,gh,paneUv,grid,cellWorld);
|
||||
#include <colorspace_fragment>
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
vec2 cellDimensions=uPaneSize/grid;
|
||||
float opticalTravel=-max(abs(uSourceZ-gh.z),.6);
|
||||
vec2 affineUv,curvedSlope,facetSlope;mat2 transform;
|
||||
evaluateCell(cell,local,grid,cellSize,cellDimensions,cellWorld,opticalTravel,style,affineUv,transform,curvedSlope,facetSlope);
|
||||
if(style<=.5){
|
||||
vec2 smoothFacet=.003*vec2(sin(6.2831853*paneUv.x),sin(6.2831853*paneUv.y));
|
||||
curvedSlope+=smoothFacet;facetSlope=smoothFacet;
|
||||
}else{
|
||||
vec2 edge=.5-abs(local),neighborSign=mix(vec2(-1.),vec2(1.),step(vec2(0.),local));
|
||||
float normalBlend=.16;
|
||||
vec2 weights=1.-smoothstep(vec2(-normalBlend),vec2(normalBlend),edge);
|
||||
float xSplitWeight=weights.x*(1.-weights.y),ySplitWeight=(1.-weights.x)*weights.y;
|
||||
float diagonalSplitWeight=weights.x*weights.y,centerSplitWeight=(1.-weights.x)*(1.-weights.y);
|
||||
if(weights.x>0.||weights.y>0.){
|
||||
vec2 neighborAffine,neighborCurved,neighborFacet;mat2 neighborTransform;
|
||||
vec2 xWeight=vec2(xSplitWeight,0.);
|
||||
vec2 yWeight=vec2(0.,ySplitWeight);
|
||||
affineUv*=centerSplitWeight;transform*=centerSplitWeight;curvedSlope*=centerSplitWeight;facetSlope*=centerSplitWeight;
|
||||
if(xWeight.x>0.){
|
||||
vec2 offset=vec2(neighborSign.x,0.);
|
||||
evaluateCell(cell+offset,local-offset,grid,cellSize,cellDimensions,cellWorld,opticalTravel,style,neighborAffine,neighborTransform,neighborCurved,neighborFacet);
|
||||
affineUv+=neighborAffine*xWeight.x;transform+=neighborTransform*xWeight.x;curvedSlope+=neighborCurved*xWeight.x;facetSlope+=neighborFacet*xWeight.x;
|
||||
}
|
||||
if(yWeight.y>0.){
|
||||
vec2 offset=vec2(0.,neighborSign.y);
|
||||
evaluateCell(cell+offset,local-offset,grid,cellSize,cellDimensions,cellWorld,opticalTravel,style,neighborAffine,neighborTransform,neighborCurved,neighborFacet);
|
||||
affineUv+=neighborAffine*yWeight.y;transform+=neighborTransform*yWeight.y;curvedSlope+=neighborCurved*yWeight.y;facetSlope+=neighborFacet*yWeight.y;
|
||||
}
|
||||
if(diagonalSplitWeight>0.){
|
||||
vec2 offset=neighborSign;
|
||||
evaluateCell(cell+offset,local-offset,grid,cellSize,cellDimensions,cellWorld,opticalTravel,style,neighborAffine,neighborTransform,neighborCurved,neighborFacet);
|
||||
affineUv+=neighborAffine*diagonalSplitWeight;transform+=neighborTransform*diagonalSplitWeight;curvedSlope+=neighborCurved*diagonalSplitWeight;facetSlope+=neighborFacet*diagonalSplitWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
vec3 nCurved=normalize(vec3(curvedSlope,1.)),nFacet=normalize(vec3(facetSlope,1.));
|
||||
vec3 straightHit=gh+i*((uSourceZ-gh.z)/safeZ(i.z));
|
||||
vec3 curvedRay=bend(i,nCurved),curvedHit=gh+curvedRay*((uSourceZ-gh.z)/safeZ(curvedRay.z));
|
||||
// Keep the artistic Mosaic optical path independent of physical glass-to-photo contact distance.
|
||||
vec2 rawDelta=(curvedRay.xy/safeZ(curvedRay.z)-i.xy/safeZ(i.z))*opticalTravel;
|
||||
vec2 worldDelta=vec2(softLimit(rawDelta.x,cellWorld*.55),softLimit(rawDelta.y,cellWorld*.55));
|
||||
if(style>.5){
|
||||
vec3 facetRay=bend(i,nFacet);vec3 facetHit=gh+facetRay*((uSourceZ-gh.z)/safeZ(facetRay.z));
|
||||
vec2 base=facetHit.xy-straightHit.xy,curve=curvedHit.xy-facetHit.xy;
|
||||
worldDelta=vec2(softLimit(base.x,cellWorld*.08),softLimit(base.y,cellWorld*.08));
|
||||
vec2 d=curve/cellWorld;
|
||||
worldDelta+=vec2(.3*d.x/(.3+abs(d.x)),.3*d.y/(.3+abs(d.y)))*cellWorld;
|
||||
}else{
|
||||
vec3 referenceI=normalize(gh-vec3(0.,0.,uContentCameraPosition.z)),referenceRay=bend(referenceI,nCurved);
|
||||
vec2 incidenceDelta=curvedRay.xy/max(-curvedRay.z,.0001)-referenceRay.xy/max(-referenceRay.z,.0001);
|
||||
vec2 boundedIncidence=incidenceDelta/sqrt(incidenceDelta*incidenceDelta+vec2(.025*.025));
|
||||
vec2 cellEnvelope=.5+.5*cos(6.2831853*local);
|
||||
worldDelta+=boundedIncidence*cellEnvelope*cellDimensions*signedCurvatureScale()*.18;
|
||||
}
|
||||
vec2 sampleUv=affineUv+transform*(worldDelta/uPaneSize);
|
||||
float edgeDistance=min(min(paneUv.x,paneUv.y),min(1.-paneUv.x,1.-paneUv.y));float edgeTaper=style<=.5?1.25:.75;float edgeWeight=smoothstep(0.,max(cellSize.x,cellSize.y)*edgeTaper,edgeDistance);float strength=clamp(uStrength,0.,1.)*edgeWeight;
|
||||
vec4 color;vec3 sceneHit=straightHit+vec3(worldDelta*strength,0.);vec2 finalSceneUv=projectUv(sceneHit);
|
||||
if(style<=.5){
|
||||
sceneHit=refineSceneHit(gh,normalize(mix(i,curvedRay,strength)),sceneHit,cellWorld);
|
||||
finalSceneUv=projectUv(sceneHit);
|
||||
}
|
||||
#ifdef REGION_ATLAS
|
||||
vec3 atlasCenterColor=sampleScene(finalSceneUv).rgb;
|
||||
float atlasEvidence=regionProtectionWeight(finalSceneUv)*(1.-smoothstep(.10,.20,regionLuminance(atlasCenterColor)));
|
||||
#endif
|
||||
#ifdef REGION_ATLAS
|
||||
if(style<=.5){
|
||||
float representativeEvidence=atlasEvidence;
|
||||
color=vec4(regionAtlasRepresentative(atlasCenterColor,atlasEvidence,sceneHit,gh,representativeEvidence),representativeEvidence);
|
||||
atlasEvidence=representativeEvidence;
|
||||
}else{
|
||||
color=sampleCell(paneUv,sampleUv,strength,cell,cellSize,style);
|
||||
}
|
||||
#else
|
||||
if(style<=.5){
|
||||
color=sampleScene(finalSceneUv);
|
||||
}else{
|
||||
color=sampleCell(paneUv,sampleUv,strength,cell,cellSize,style);
|
||||
}
|
||||
#endif
|
||||
#ifndef REGION_ATLAS
|
||||
if(uRegionAvailable>.5&&uRegionStrength>.001&&uMosaicStyle<.5){
|
||||
vec3 p0=regionColor(cell,0.),p1=regionColor(cell,1.),p2=regionColor(cell,2.),p3=regionColor(cell,3.);
|
||||
float ownLabel=nearestRegion(color.rgb,p0,p1,p2,p3);vec4 votes=vec4(0.);float totalWeight=0.,ownWeight=0.;
|
||||
vec2 texelCoord=fract(gridUv)*8.-.5,anchor=floor(texelCoord+.5);
|
||||
for(int y=-1;y<=1;y++)for(int x=-1;x<=1;x++){
|
||||
vec2 offset=vec2(float(x),float(y)),delta=anchor+offset-texelCoord;
|
||||
float weight=pow(max(0.,1.-length(delta)/1.5),2.);
|
||||
if(weight>0.){
|
||||
vec3 atlasColor=regionAtlasColor(cell,anchor+offset);float label=nearestRegion(atlasColor,p0,p1,p2,p3);
|
||||
votes+=vec4(step(abs(label-vec4(0.,1.,2.,3.)),vec4(.1)))*weight;totalWeight+=weight;
|
||||
ownWeight+=step(abs(label-ownLabel),.1)*weight;
|
||||
}
|
||||
}
|
||||
float winningLabel=ownLabel,winningWeight=ownWeight;
|
||||
if(votes.x>winningWeight){winningLabel=0.;winningWeight=votes.x;}if(votes.y>winningWeight){winningLabel=1.;winningWeight=votes.y;}if(votes.z>winningWeight){winningLabel=2.;winningWeight=votes.z;}if(votes.w>winningWeight){winningLabel=3.;winningWeight=votes.w;}
|
||||
bool simplify=totalWeight>0.&&winningWeight/totalWeight>.55&&ownWeight/totalWeight<.40;
|
||||
float radialLabel=simplify?winningLabel:ownLabel;vec3 radialColor=selectRegion(p0,p1,p2,p3,radialLabel);
|
||||
vec2 historyTexel=clamp(floor(fract(gridUv)*8.),vec2(0.),vec2(7.));
|
||||
vec2 historyUv=(cell*8.+historyTexel+.5)/uRegionAtlasSize;
|
||||
vec4 splitHistory=texture2D(uRegionHistory,historyUv);
|
||||
vec3 splitColor=splitHistory.a>.00001?splitHistory.rgb/splitHistory.a:radialColor;
|
||||
vec3 candidateColor=mix(radialColor,splitColor,splitHistory.a);
|
||||
color.rgb=mix(color.rgb,candidateColor,clamp(uRegionStrength*clamp(uStrength,0.,1.)*regionSurfaceValid(finalSceneUv,gh),0.,1.));
|
||||
}
|
||||
#endif
|
||||
#ifndef REGION_ATLAS
|
||||
color.a=1.;
|
||||
vec3 v=normalize(uContentCameraPosition-gh),reflected=reflect(-v,nCurved); float lightT=(uLightPosition.z-gh.z)/safeZ(reflected.z); vec2 lightHit=gh.xy+reflected.xy*lightT; vec2 halfSize=vec2(.32,.42)*min(uPaneSize.x,uPaneSize.y); vec2 windowCoord=abs(lightHit-uLightPosition.xy)/halfSize; vec2 windowMask=1.-smoothstep(vec2(.45),vec2(1.15),windowCoord); float surfaceReflectionWeight=mix(.35,1.,edgeWeight); float glossStrength=clamp(uGlossStrength,0.,1.); float spec=windowMask.x*windowMask.y*step(.0001,reflected.z)*step(0.,lightT); float specGloss=spec*glossStrength*.12*surfaceReflectionWeight*clamp(uStrength,0.,1.); vec2 broadWindowMask=1.-smoothstep(vec2(.15),vec2(1.75),windowCoord); float broadFacing=pow(max(dot(nCurved,v),0.),2.); float broadReflection=broadWindowMask.x*broadWindowMask.y*broadFacing*glossStrength*.035*surfaceReflectionWeight*clamp(uStrength,0.,1.); color.rgb=mix(color.rgb,vec3(1.),specGloss+broadReflection); gl_FragColor=color;
|
||||
// Common, static room environment. Reflected direction varies with the same
|
||||
// curved normal as transmission; no image relighting or timed sparkle.
|
||||
float fresnel=.04+.96*pow(1.-clamp(dot(nCurved,v),0.,1.),5.);
|
||||
float environmentWeight=uEnvironmentStrength*glossStrength*(.35+.65*fresnel)*surfaceReflectionWeight*clamp(uStrength,0.,1.);
|
||||
vec3 environmentColor=mix(vec3(.10,.13,.18),vec3(.65,.72,.80),smoothstep(-.35,.65,reflected.y));
|
||||
if(style<=.5)color.rgb=mix(color.rgb,environmentColor,environmentWeight);
|
||||
gl_FragColor=color;
|
||||
#include <colorspace_fragment>
|
||||
#else
|
||||
color.a=atlasEvidence;
|
||||
gl_FragColor=color;
|
||||
#endif
|
||||
}
|
||||
`,p=`uniform sampler2D uSceneTexture; uniform mat4 uContentViewProjection; uniform mat4 uContentInverseViewProjection; uniform vec3 uContentCameraPosition,uBackgroundColor; uniform float uSceneZoom; uniform float uGlassZ,uSourceZ,uGridSize,uStrength,uTime; uniform vec2 uSceneOffset,uViewOffset,uResolution,uPetSize,uPaneSize;
|
||||
varying vec2 vUv;
|
||||
// Preserve the existing 1x material coordinates as the common projection magnifies and translates.
|
||||
vec2 patternScreenUv(vec2 uv){return (uv-.5-uSceneOffset*.5)/max(uSceneZoom,1.)+.5;}
|
||||
vec2 projectUv(vec3 p){vec4 c=uContentViewProjection*vec4(p,1.);float w=abs(c.w)<.0001?(c.w<0.?-.0001:.0001):c.w;return c.xy/w*.5+.5;} vec4 sampleScene(vec2 uv){if(any(lessThan(uv,vec2(0.)))||any(greaterThan(uv,vec2(1.))))return vec4(.005605,.009721,.016807,1.);return texture2D(uSceneTexture,uv);} float hash(float x){return fract(sin(x*91.7)*43758.5453);} float safeZ(float z){return abs(z)<.0001?(z<0.?-.0001:.0001):z;} vec3 bend(vec3 i,vec3 n){vec3 r=refract(i,n,.75);return length(r)<.0001?i:r;}
|
||||
void main(){if(uStrength<=.001){gl_FragColor=texture2D(uSceneTexture,vUv);
|
||||
#include <colorspace_fragment>
|
||||
return;}vec2 q=vUv*2.-1.;vec4 fh=uContentInverseViewProjection*vec4(q,1.,1.);float fwDen=abs(fh.w)<.0001?(fh.w<0.?-.0001:.0001):fh.w;vec3 fw=fh.xyz/fwDen;vec3 i=normalize(fw-uContentCameraPosition);float gt=(uGlassZ-uContentCameraPosition.z)/safeZ(i.z);vec3 gh=uContentCameraPosition+i*gt;vec2 paneUv=gh.xy/uPaneSize+.5;if(any(lessThan(paneUv,vec2(0.)))||any(greaterThan(paneUv,vec2(1.)))){gl_FragColor=vec4(uBackgroundColor,1.);
|
||||
#include <colorspace_fragment>
|
||||
return;}float count=max(1.,uGridSize*uPetSize.x/uPetSize.y),coord=patternScreenUv(vUv).x*count,cell=floor(coord),phase=fract(coord)*6.2831853,ridge=sin(phase+uViewOffset.x*.9),variation=mix(.92,1.08,hash(cell));vec3 r=bend(i,normalize(vec3(-ridge*.34*variation,0.,1.)));vec3 sh=gh+i*((uSourceZ-gh.z)/safeZ(i.z)),bh=gh+r*((uSourceZ-gh.z)/safeZ(r.z));vec2 ru=vUv+projectUv(bh)-projectUv(sh);vec2 uv=mix(vUv,ru,clamp(uStrength,0.,1.));vec4 c=sampleScene(uv);c.a=1.;gl_FragColor=c;
|
||||
#include <colorspace_fragment>
|
||||
}
|
||||
`,m=`uniform sampler2D uSceneTexture; uniform mat4 uContentViewProjection; uniform mat4 uContentInverseViewProjection; uniform vec3 uContentCameraPosition,uBackgroundColor; uniform float uSceneZoom; uniform float uGlassZ,uSourceZ,uGridSize,uStrength,uTime; uniform vec2 uSceneOffset,uViewOffset,uResolution,uPetSize,uPaneSize;
|
||||
varying vec2 vUv;
|
||||
// Preserve the existing 1x material coordinates as the common projection magnifies and translates.
|
||||
vec2 patternScreenUv(vec2 uv){return (uv-.5-uSceneOffset*.5)/max(uSceneZoom,1.)+.5;}
|
||||
vec2 projectUv(vec3 p){vec4 c=uContentViewProjection*vec4(p,1.);float w=abs(c.w)<.0001?(c.w<0.?-.0001:.0001):c.w;return c.xy/w*.5+.5;} vec4 sampleScene(vec2 uv){if(any(lessThan(uv,vec2(0.)))||any(greaterThan(uv,vec2(1.))))return vec4(.005605,.009721,.016807,1.);return texture2D(uSceneTexture,uv);} float hash(vec2 p){return fract(sin(dot(p,vec2(41.3,17.9)))*15731.743);} float noise(vec2 p){vec2 i=floor(p),f=fract(p);f=f*f*(3.-2.*f);return mix(mix(hash(i),hash(i+vec2(1.,0.)),f.x),mix(hash(i+vec2(0.,1.)),hash(i+vec2(1.)),f.x),f.y);} float safeZ(float z){return abs(z)<.0001?(z<0.?-.0001:.0001):z;} vec3 bend(vec3 i,vec3 n){vec3 r=refract(i,n,.75);return length(r)<.0001?i:r;}
|
||||
void main(){if(uStrength<=.001){gl_FragColor=texture2D(uSceneTexture,vUv);
|
||||
#include <colorspace_fragment>
|
||||
return;}vec2 q=vUv*2.-1.;vec4 fh=uContentInverseViewProjection*vec4(q,1.,1.);float fwDen=abs(fh.w)<.0001?(fh.w<0.?-.0001:.0001):fh.w;vec3 fw=fh.xyz/fwDen;vec3 i=normalize(fw-uContentCameraPosition);float gt=(uGlassZ-uContentCameraPosition.z)/safeZ(i.z);vec3 gh=uContentCameraPosition+i*gt;vec2 paneUv=gh.xy/uPaneSize+.5;if(any(lessThan(paneUv,vec2(0.)))||any(greaterThan(paneUv,vec2(1.)))){gl_FragColor=vec4(uBackgroundColor,1.);
|
||||
#include <colorspace_fragment>
|
||||
return;}vec2 st=patternScreenUv(vUv)*(uResolution/max(uResolution.y,1.)),np=st*9.+uViewOffset*.6,nn=vec2(noise(np),noise(np+vec2(23.7)))-vec2(.5);vec3 r=bend(i,normalize(vec3(nn*.32,1.)));vec3 sh=gh+i*((uSourceZ-gh.z)/safeZ(i.z)),bh=gh+r*((uSourceZ-gh.z)/safeZ(r.z));vec2 ru=vUv+projectUv(bh)-projectUv(sh),center=mix(vUv,ru,clamp(uStrength,0.,1.)),rad=vec2(.008)*uSceneZoom*clamp(uStrength,0.,1.);vec4 c=vec4(0.);c+=sampleScene(center+vec2(-rad.x,-rad.y));c+=sampleScene(center+vec2(0.,-rad.y));c+=sampleScene(center+vec2(rad.x,-rad.y));c+=sampleScene(center+vec2(-rad.x,0.));c+=sampleScene(center);c+=sampleScene(center+vec2(rad.x,0.));c+=sampleScene(center+vec2(-rad.x,rad.y));c+=sampleScene(center+vec2(0.,rad.y));c+=sampleScene(center+vec2(rad.x,rad.y));c/=9.;c.a=1.;gl_FragColor=c;
|
||||
#include <colorspace_fragment>
|
||||
}
|
||||
`,h=`varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = vec4(position.xy, 0.0, 1.0);
|
||||
}
|
||||
`,g=`uniform sampler2D uRegionAtlas;
|
||||
uniform vec2 uRegionAtlasSize,uRegionGridSize;
|
||||
varying vec2 vUv;
|
||||
|
||||
float regionLuminance(vec3 c){return dot(c,vec3(.299,.587,.114));}
|
||||
float distanceColor(vec3 a,vec3 b){vec3 d=a-b;float y=dot(d,vec3(.299,.587,.114));return dot(d,d)+.35*y*y;}
|
||||
float sideColorCost(vec4 votes,vec3 target,vec3 c0,vec3 c1,vec3 c2,vec3 c3){return votes.x*distanceColor(c0,target)+votes.y*distanceColor(c1,target)+votes.z*distanceColor(c2,target)+votes.w*distanceColor(c3,target);}
|
||||
vec4 atlasSampleData(vec2 cell,vec2 local){vec2 uv=(cell*8.+local+.5)/uRegionAtlasSize;return texture2D(uRegionAtlas,uv);}
|
||||
vec3 atlasSample(vec2 cell,vec2 local){return atlasSampleData(cell,local).rgb;}
|
||||
float nearestLabel(vec3 color,vec3 c0,vec3 c1,vec3 c2,vec3 c3){float d0=distanceColor(color,c0),d1=distanceColor(color,c1),d2=distanceColor(color,c2),d3=distanceColor(color,c3);if(d0<=d1&&d0<=d2&&d0<=d3)return 0.;if(d1<=d2&&d1<=d3)return 1.;if(d2<=d3)return 2.;return 3.;}
|
||||
float majorityLabel(vec4 votes){float label=0.,count=votes.x;if(votes.y>count){label=1.;count=votes.y;}if(votes.z>count){label=2.;count=votes.z;}if(votes.w>count)label=3.;return label;}
|
||||
void main(){
|
||||
vec2 pixel=floor(gl_FragCoord.xy);float paletteIndex=mod(pixel.x,5.);vec3 cell=vec3(floor(pixel.x/5.),pixel.y,0.);
|
||||
vec3 darkest=vec3(1.),lightest=vec3(0.);float minLum=2.,maxLum=-1.;
|
||||
for(int y=0;y<8;y++)for(int x=0;x<8;x++){
|
||||
vec3 c=atlasSample(cell.xy,vec2(float(x),float(y)));float l=regionLuminance(c);
|
||||
if(l<minLum){minLum=l;darkest=c;}if(l>maxLum){maxLum=l;lightest=c;}
|
||||
}
|
||||
vec3 third=darkest;float thirdDistance=-1.;
|
||||
for(int y=0;y<8;y++)for(int x=0;x<8;x++){
|
||||
vec3 c=atlasSample(cell.xy,vec2(float(x),float(y)));float d=min(distanceColor(c,darkest),distanceColor(c,lightest));
|
||||
if(d>thirdDistance){thirdDistance=d;third=c;}
|
||||
}
|
||||
vec3 fourth=darkest;float fourthDistance=-1.;
|
||||
for(int y=0;y<8;y++)for(int x=0;x<8;x++){
|
||||
vec3 c=atlasSample(cell.xy,vec2(float(x),float(y)));float d=min(distanceColor(c,darkest),min(distanceColor(c,lightest),distanceColor(c,third)));
|
||||
if(d>fourthDistance){fourthDistance=d;fourth=c;}
|
||||
}
|
||||
vec3 c0=darkest,c1=lightest,c2=third,c3=fourth;
|
||||
for(int iteration=0;iteration<2;iteration++){
|
||||
vec3 sum0=vec3(0.),sum1=vec3(0.),sum2=vec3(0.),sum3=vec3(0.);float n0=0.,n1=0.,n2=0.,n3=0.;
|
||||
for(int y=0;y<8;y++)for(int x=0;x<8;x++){
|
||||
vec3 c=atlasSample(cell.xy,vec2(float(x),float(y)));
|
||||
float d0=distanceColor(c,c0),d1=distanceColor(c,c1),d2=distanceColor(c,c2),d3=distanceColor(c,c3);
|
||||
if(d0<=d1&&d0<=d2&&d0<=d3){sum0+=c;n0+=1.;}
|
||||
else if(d1<=d2&&d1<=d3){sum1+=c;n1+=1.;}
|
||||
else if(d2<=d3){sum2+=c;n2+=1.;}
|
||||
else{sum3+=c;n3+=1.;}
|
||||
}
|
||||
if(n0>0.)c0=sum0/n0;if(n1>0.)c1=sum1/n1;if(n2>0.)c2=sum2/n2;if(n3>0.)c3=sum3/n3;
|
||||
}
|
||||
|
||||
vec4 metadata=vec4(0.);
|
||||
if(paletteIndex>3.5){
|
||||
vec4 wholeVotes=vec4(0.);float cellEvidence=0.;
|
||||
for(int y=0;y<8;y++)for(int x=0;x<8;x++){
|
||||
vec4 sampleData=atlasSampleData(cell.xy,vec2(float(x),float(y)));vec3 c=sampleData.rgb;float label=nearestLabel(c,c0,c1,c2,c3);
|
||||
wholeVotes+=vec4(step(abs(label-vec4(0.,1.,2.,3.)),vec4(.1)));
|
||||
cellEvidence+=sampleData.a;
|
||||
}
|
||||
float singleMajority=max(max(wholeVotes.x,wholeVotes.y),max(wholeVotes.z,wholeVotes.w))/64.;
|
||||
float bestCost=1e20,bestConfidence=0.,bestAxis=0.,bestCut=4.,bestA=0.,bestB=0.;
|
||||
for(int axis=0;axis<2;axis++)for(int candidateIndex=0;candidateIndex<5;candidateIndex++){
|
||||
float cut=4.;
|
||||
if(candidateIndex==1)cut=3.;else if(candidateIndex==2)cut=5.;else if(candidateIndex==3)cut=2.;else if(candidateIndex==4)cut=6.;
|
||||
vec4 votesA=vec4(0.),votesB=vec4(0.),weightedVotesA=vec4(0.),weightedVotesB=vec4(0.);
|
||||
for(int y=0;y<8;y++)for(int x=0;x<8;x++){
|
||||
vec4 sampleData=atlasSampleData(cell.xy,vec2(float(x),float(y)));vec3 c=sampleData.rgb;float label=nearestLabel(c,c0,c1,c2,c3);
|
||||
vec4 oneHot=vec4(step(abs(label-vec4(0.,1.,2.,3.)),vec4(.1)));float sampleWeight=1.+3.*sampleData.a;
|
||||
float coordinate=axis==0?float(x)+.5:float(y)+.5;
|
||||
if(coordinate<cut){votesA+=oneHot;weightedVotesA+=oneHot*sampleWeight;}
|
||||
else{votesB+=oneHot;weightedVotesB+=oneHot*sampleWeight;}
|
||||
}
|
||||
float labelA=0.,labelB=0.,pairCost=1e20,pairVotes=0.;
|
||||
for(int a=0;a<4;a++)for(int b=0;b<4;b++){
|
||||
if(a!=b&&votesA[a]>0.&&votesB[b]>0.){
|
||||
vec3 colorA=a==0?c0:(a==1?c1:(a==2?c2:c3));
|
||||
vec3 colorB=b==0?c0:(b==1?c1:(b==2?c2:c3));
|
||||
float candidateCost=sideColorCost(weightedVotesA,colorA,c0,c1,c2,c3)+sideColorCost(weightedVotesB,colorB,c0,c1,c2,c3);
|
||||
if(candidateCost<pairCost){pairCost=candidateCost;labelA=float(a);labelB=float(b);pairVotes=votesA[a]+votesB[b];}
|
||||
}
|
||||
}
|
||||
if(pairCost<1e20){
|
||||
float accuracy=pairVotes/64.,gain=accuracy-singleMajority;
|
||||
float oldConfidence=smoothstep(.55,.75,accuracy)*smoothstep(.015625,.078125,gain);
|
||||
float confidence=.85+.15*oldConfidence;
|
||||
confidence=mix(confidence,1.,smoothstep(.02,.06,cellEvidence/64.));
|
||||
if(pairCost<bestCost){bestCost=pairCost;bestConfidence=confidence;bestAxis=float(axis);bestCut=cut;bestA=labelA;bestB=labelB;}
|
||||
}
|
||||
}
|
||||
metadata=vec4((bestAxis*8.+bestCut)/255.,bestA/255.,bestB/255.,bestConfidence);
|
||||
}
|
||||
|
||||
vec3 result=c0;
|
||||
if(paletteIndex>.5&&paletteIndex<1.5)result=c1;
|
||||
else if(paletteIndex>1.5&&paletteIndex<2.5)result=c2;
|
||||
else if(paletteIndex>2.5&&paletteIndex<3.5)result=c3;
|
||||
gl_FragColor=paletteIndex>3.5?metadata:vec4(result,1.);
|
||||
}
|
||||
`,_=`uniform sampler2D uRegionPalette,uPreviousHistory;
|
||||
uniform vec2 uRegionAtlasSize,uRegionGridSize,uRegionPaletteSize;
|
||||
uniform float uHistoryBlend;
|
||||
varying vec2 vUv;
|
||||
|
||||
vec3 paletteColor(vec2 cell,float label){vec2 uv=(vec2(cell.x*5.+label,cell.y)+.5)/uRegionPaletteSize;return texture2D(uRegionPalette,uv).rgb;}
|
||||
void main(){
|
||||
vec2 pixel=floor(vUv*uRegionAtlasSize),cell=floor(pixel/8.),local=(mod(pixel,8.)+.5)/8.;
|
||||
vec2 metadataUv=(vec2(cell.x*5.+4.,cell.y)+.5)/uRegionPaletteSize;
|
||||
vec4 metadata=texture2D(uRegionPalette,metadataUv);
|
||||
float packed=floor(metadata.r*255.+.5),axis=floor(packed/8.),cut=packed-axis*8.;
|
||||
float coordinate=axis<.5?local.x:local.y;
|
||||
float label=coordinate<cut/8.?floor(metadata.g*255.+.5):floor(metadata.b*255.+.5);
|
||||
float confidence=clamp(metadata.a,0.,1.);
|
||||
vec4 current=vec4(paletteColor(cell,label)*confidence,confidence);
|
||||
if(uHistoryBlend>=.9999){gl_FragColor=current;return;}
|
||||
vec4 previous=texture2D(uPreviousHistory,vUv);
|
||||
gl_FragColor=mix(previous,current,clamp(uHistoryBlend,0.,1.));
|
||||
}
|
||||
`;function v(v){let{renderer:y,scene:b,frameScene:te,camera:x,petDepth:S,uniforms:C,depthUniforms:w,emptyTex:ne,regionHistoryUniform:T,state:E}=v,D=new n,O=new r({uniforms:C,vertexShader:h,fragmentShader:f}),k=new l(new d(2,2),O);D.add(k);let A=new n,j=new r({uniforms:C,vertexShader:h,fragmentShader:f,defines:{REGION_ATLAS:1},toneMapped:!1}),M=new l(new d(2,2),j);A.add(M);let N=new n,P={uRegionAtlas:{value:null},uRegionAtlasSize:C.uRegionAtlasSize,uRegionGridSize:C.uRegionGridSize},F=new r({uniforms:P,vertexShader:h,fragmentShader:g,toneMapped:!1}),I=new l(new d(2,2),F);N.add(I);let L=new o(-1,1,1,-1,0,1),R=new i(1,1,{colorSpace:``,type:e,depthBuffer:!0});R.depthTexture=new a(1,1,s),R.depthTexture.format=ee,C.uSceneDepth.value=R.depthTexture;let z=new i(104,104,{colorSpace:``,type:e,depthBuffer:!1,minFilter:t,magFilter:t}),B=new i(65,13,{colorSpace:``,type:u,depthBuffer:!1,minFilter:t,magFilter:t}),V=[0,1].map(()=>new i(104,104,{colorSpace:``,type:e,depthBuffer:!1,minFilter:t,magFilter:t})),H=new n,U={uRegionPalette:{value:B.texture},uPreviousHistory:{value:V[0].texture},uRegionAtlasSize:C.uRegionAtlasSize,uRegionGridSize:C.uRegionGridSize,uRegionPaletteSize:C.uRegionPaletteSize,uHistoryBlend:{value:1}},W=new r({uniforms:U,vertexShader:h,fragmentShader:_,toneMapped:!1}),G=new l(new d(2,2),W);H.add(G),C.uRegionPalette.value=B.texture,P.uRegionAtlas.value=z.texture;let K=``,q=``,J=0,Y=!1;function X(){let e=Math.max(1,Math.ceil(C.uGridSize.value)),t=Math.max(1,C.uGridSize.value*C.uPaneSize.value.y/Math.max(C.uPaneSize.value.x,.001)),n=Math.ceil(t),r=e*8,i=n*8,a=e*5,o=n,s=Math.max(r,i,a,o)<=y.capabilities.maxTextureSize,c=C.uRegionAvailable.value!==+!!s||s&&(z.width!==r||z.height!==i||B.width!==a||B.height!==o||V[0].width!==r||V[0].height!==i)||C.uRegionGridSize.value.x!==C.uGridSize.value||C.uRegionGridSize.value.y!==t;s&&(z.width!==r||z.height!==i)&&z.setSize(r,i),s&&(B.width!==a||B.height!==o)&&B.setSize(a,o);for(let e of V)s&&(e.width!==r||e.height!==i)&&e.setSize(r,i);C.uRegionAvailable.value=+!!s,C.uRegionAtlasSize.value.set(s?r:z.width,s?i:z.height),C.uRegionGridSize.value.set(C.uGridSize.value,t),C.uRegionPaletteSize.value.set(s?a:B.width,s?o:B.height),P.uRegionAtlas.value=z.texture,C.uRegionPalette.value=B.texture,C.uRegionAtlas.value=z.texture,c&&(K=``)}function Z(){let{mode:e,active:t,activeIsVideo:n,effect:r,style:i}=E(),a=C.uContentViewProjection.value.elements.map(e=>e.toFixed(4)).join(`,`),o=S.matrixWorld.elements.map(e=>e.toFixed(4)).join(`,`),s=w.uDepthMap.value;return[e,t.uuid,s.uuid,a,o,C.uGridSize.value,C.uStrength.value,C.uCurvature.value,C.uMosaicStyle.value,C.uPaneSize.value.x,C.uPaneSize.value.y,w.uDepthScale.value,w.uDepthBias.value,R.width,R.height,z.width,z.height].join(`|`)}function re(){let{mode:e,active:t,effect:n,style:r}=E(),i=S.matrixWorld.elements.map(e=>e.toFixed(4)).join(`,`),a=w.uDepthMap.value;return[e,n,r,t.uuid,a.uuid,C.uRegionAvailable.value,C.uGridSize.value,C.uMosaicStyle.value,C.uStrength.value,C.uRegionStrength.value,C.uCurvature.value,C.uGlassZ.value,C.uSourceZ.value,C.uPaneSize.value.x,C.uPaneSize.value.y,i,w.uDepthScale.value,w.uDepthBias.value,R.width,R.height,z.width,z.height,B.width,B.height].join(`|`)}function ie(){let e=y.getRenderTarget(),t=y.getClearColor(new c),n=y.getClearAlpha();y.setClearColor(0,0);for(let e of V)y.setRenderTarget(e),y.clear(!0,!1,!1);y.setRenderTarget(e),y.setClearColor(t,n),J=0,Y=!1,T.value=V[0].texture}function Q(e){let{mode:t,effect:n,style:r}=E(),i=re();if(i!==q&&(ie(),q=i),!((t===`final`||t===`glass`)&&n===`mosaic`&&r===`0`&&C.uRegionAvailable.value>.5&&C.uRegionStrength.value>.001&&C.uStrength.value>.001))return;let a=1-J;U.uPreviousHistory.value=V[J].texture,U.uHistoryBlend.value=Y?1-Math.exp(-e/.07):1,y.setRenderTarget(V[a]),y.render(H,L),y.setRenderTarget(null),J=a,Y=!0,T.value=V[J].texture}function ae(){let{effect:e,style:t,activeIsVideo:n}=E();if(!(e===`mosaic`&&t===`0`&&C.uRegionAvailable.value>.5&&C.uRegionStrength.value>.001&&C.uStrength.value>.001))return;let r=Z();(n||r!==K)&&(y.setRenderTarget(z),y.render(A,L),y.setRenderTarget(B),y.render(N,L),y.setRenderTarget(null),K=r)}function oe(e,t=null){let{mode:n}=E();if(n===`final`||n===`glass`){y.setRenderTarget(R),y.render(b,x),C.uSceneTexture.value=R.texture,ae(),Q(e),y.setRenderTarget(t),y.render(D,L);let n=y.autoClear;y.autoClear=!1,y.clearDepth(),y.render(te,x),y.autoClear=n}else Q(e),y.setRenderTarget(t),y.render(b,x)}let $=!1;return{render:oe,setEffect(e){O.fragmentShader=e===`reeded`?p:e===`frosted`?m:f,O.needsUpdate=!0},resize(e,t){R.setSize(e,t),X()},invalidate(){K=``,q=``,Y=!1},dispose(){if(!$){$=!0,R.dispose(),z.dispose(),B.dispose(),V.forEach(e=>e.dispose());for(let e of[k,M,I,G])e.geometry.dispose();for(let e of[O,j,F,W])e.dispose();D.clear(),A.clear(),N.clear(),H.clear()}}}}export{v as createOriginalGlassRenderer};
|
||||
Reference in New Issue
Block a user