载入中...
搜索中...
未找到
eve::graphics::shaders 命名空间参考

变量

constexpr const char * kAoCommon
 
constexpr const char * kSsao
 
constexpr const char * kHbao
 
constexpr const char * kGtao
 
constexpr const char * kBlur
 
constexpr const char * kOverlay
 
constexpr const char * kFromDepth
 
constexpr const char * kBloomGaussian
 Gaussian-scatter HDR bloom stages. @lifetime Static process storage.
 
constexpr const char * kGrassVertWgsl
 
constexpr const char * kGrassFragWgsl
 
constexpr const char * kHairFragWgsl
 Hair fragment shader WGSL source. @ownership Borrowed immutable string literal; callers must not free it. @lifetime Static storage duration, valid for the entire process lifetime. @thread Safe for concurrent reads.
 
constexpr const char * kPostCommon
 
constexpr const char * kBloomDownsample
 
constexpr const char * kBloomUpsample
 
constexpr const char * kExposureMeter
 
constexpr const char * kExposureAdapt
 
constexpr const char * kExposureApply
 
constexpr const char * kDepthOfField
 
constexpr const char * kDepthPyramidDownsample
 
constexpr const char * kFxaa
 
constexpr const char * kNfaa
 
constexpr const char * kTaa
 
constexpr const char * kSmaa
 
constexpr const char * kSsaa
 
constexpr const char * kOutline
 
constexpr const char * kDofGaussian
 
constexpr const char * kReflectionProbeFilterWgsl
 
constexpr const char * kScreenEffectCommon
 
constexpr const char * kSsgi
 
constexpr const char * kSsr
 
constexpr const char * kSsrTemporal
 
constexpr const char * kTreeWindVertWgsl
 Immutable WGSL source. @ownership Program image. @lifetime Entire process.
 
constexpr const char * kVolCommon
 
constexpr const char * kVolScreen
 
constexpr const char * kVolRay
 
constexpr const char * kVolFog
 
constexpr const char * kVolCloud
 
constexpr const char * kVolFroxel
 
constexpr char kVolDirectionalCookie []
 
constexpr const char * kWaterfallFragWgsl
 Waterfall fragment shader WGSL source. @ownership Borrowed immutable string literal; callers must not free it. @lifetime Static storage duration, valid for the entire process lifetime. @thread Safe for concurrent reads.
 
constexpr char kWaterVertWgsl []
 Vertex-displaced low-frequency water layers for the WebGPU backend.
 
constexpr char kWaterFragWgsl []
 Backend-parity stylized-water WGSL source with depth foam and scene-color refraction.
 

变量说明

◆ kAoCommon

constexpr const char* eve::graphics::shaders::kAoCommon
inlineconstexpr
初始值:
= R"wgsl(
struct FSIn { @location(0) color: vec4f, @location(1) uv: vec2f };
struct Externals { data: array<vec4f, 8> };
@group(0) @binding(0) var mainTex: texture_2d<f32>;
@group(0) @binding(1) var normalTex: texture_2d<f32>;
@group(0) @binding(2) var mainSamp: sampler;
@group(0) @binding(4) var<uniform> u: Externals;
fn p(i: u32) -> f32 { return u.data[i / 4u][i % 4u]; }
fn inv_vp() -> mat4x4f { return mat4x4f(u.data[0], u.data[1], u.data[2], u.data[3]); }
fn depth(uv: vec2f) -> f32 { return textureSampleLevel(mainTex, mainSamp, clamp(uv, vec2f(0), vec2f(1)), 0).r; }
fn normal_load(uv:vec2f)->vec3f{let d=textureDimensions(normalTex);let q=vec2i(clamp(uv,vec2f(0),vec2f(1))*vec2f(d));return textureLoad(normalTex,clamp(q,vec2i(0),vec2i(d)-1),0).xyz;}
fn world(m: mat4x4f, uv: vec2f, z: f32) -> vec3f {
let h = m * vec4f(uv * 2 - 1, clamp(z, 0, 1), 1);
return h.xyz / max(h.w, 0.000001);
}
fn hash12(q: vec2f) -> f32 {
var q3 = fract(vec3f(q.x, q.y, q.x) * 0.1031);
q3 += dot(q3, q3.yzx + 33.33);
return fract((q3.x + q3.y) * q3.z);
}
)wgsl"

在文件 AmbientOcclusionWgsl.h 第 7 行定义.

◆ kBloomDownsample

constexpr const char* eve::graphics::shaders::kBloomDownsample
inlineconstexpr
初始值:
= R"wgsl(
fn bloom_luma(c:vec3f)->f32{return dot(c,vec3f(.2126,.7152,.0722));}
fn bloom_prefilter(c0:vec3f)->vec3f{let c=max(c0,vec3f(0));let threshold=max(p(3),0);let knee=max(p(4),.0001);let brightness=max(c.r,max(c.g,c.b));let soft=clamp((brightness-threshold+knee)/(2*knee),0,1);let contribution=max(brightness-threshold,0)+soft*soft*knee;return c*(contribution/max(brightness,.0001));}
fn bloom_sample(uv:vec2f)->vec3f{let c=tex(uv).rgb;return select(c,bloom_prefilter(c),p(2)>.5);}
fn bloom_karis(a:vec3f,b:vec3f,c:vec3f,d:vec3f)->vec3f{let w=vec4f(1/(1+bloom_luma(a)),1/(1+bloom_luma(b)),1/(1+bloom_luma(c)),1/(1+bloom_luma(d)));return (a*w.x+b*w.y+c*w.z+d*w.w)/max(dot(w,vec4f(1)),.0001);}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let t=vec2f(p(0),p(1));let center=bloom_sample(i.uv);let inner=bloom_karis(bloom_sample(i.uv+t*vec2f(-1,-1)),bloom_sample(i.uv+t*vec2f(1,-1)),bloom_sample(i.uv+t*vec2f(-1,1)),bloom_sample(i.uv+t*vec2f(1,1)));let outer=bloom_karis(bloom_sample(i.uv+t*vec2f(-2,-2)),bloom_sample(i.uv+t*vec2f(2,-2)),bloom_sample(i.uv+t*vec2f(-2,2)),bloom_sample(i.uv+t*vec2f(2,2)));let axial=bloom_karis(bloom_sample(i.uv+t*vec2f(-2,0)),bloom_sample(i.uv+t*vec2f(2,0)),bloom_sample(i.uv+t*vec2f(0,-2)),bloom_sample(i.uv+t*vec2f(0,2)));return vec4f((center*.25+inner*.5+(outer+axial)*.125)*i.color.rgb,1);}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 PostProcessWgsl.h 第 29 行定义.

被这些函数引用 eve::graphics::Bloom::Bloom().

◆ kBloomGaussian

constexpr const char* eve::graphics::shaders::kBloomGaussian
inlineconstexpr

Gaussian-scatter HDR bloom stages. @lifetime Static process storage.

在文件 BloomGaussianWgsl.h 第 4 行定义.

◆ kBloomUpsample

constexpr const char* eve::graphics::shaders::kBloomUpsample
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let t=vec2f(p(0),p(1))*max(p(2),.5);var c=tex(i.uv).rgb*4;c+=tex(i.uv+vec2f(-t.x,0)).rgb*2;c+=tex(i.uv+vec2f(t.x,0)).rgb*2;c+=tex(i.uv+vec2f(0,-t.y)).rgb*2;c+=tex(i.uv+vec2f(0,t.y)).rgb*2;c+=tex(i.uv+vec2f(-t.x,-t.y)).rgb;c+=tex(i.uv+vec2f(t.x,-t.y)).rgb;c+=tex(i.uv+vec2f(-t.x,t.y)).rgb;c+=tex(i.uv+vec2f(t.x,t.y)).rgb;return vec4f(c*(1.0/16.0)*i.color.rgb,1);}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 PostProcessWgsl.h 第 38 行定义.

被这些函数引用 eve::graphics::Bloom::Bloom().

◆ kBlur

constexpr const char* eve::graphics::shaders::kBlur
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let tw=max(p(0),.00001);let th=max(p(1),.00001);let ds=max(p(2),.0001);let k=clamp(p(3),1,4);
let c=textureSampleLevel(mainTex,mainSamp,i.uv,0);var sum=c.r;var ws=1.0;
for(var y=-2;y<=2;y++){for(var x=-2;x<=2;x++){if x==0&&y==0{continue;}let d=length(vec2f(f32(x),f32(y)));if d>k+.1{continue;}
let s=textureSampleLevel(mainTex,mainSamp,clamp(i.uv+vec2f(f32(x)*tw,f32(y)*th),vec2f(0),vec2f(1)),0);let dz=abs(s.a-c.a);
let w=exp(-d*d/(2*k*k))*exp(-(dz*dz)/(2*ds*ds));sum+=s.r*w;ws+=w;}}
let ao=sum/max(ws,.00001);return vec4f(ao,ao,ao,c.a)*i.color;}
)wgsl"

在文件 AmbientOcclusionWgsl.h 第 96 行定义.

◆ kDepthOfField

constexpr const char* eve::graphics::shaders::kDepthOfField
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let t=vec2f(p(0),p(1));let distance=mix(p(5),p(6),aux_load(i.uv).r);let coc=clamp(abs(distance-p(2))/max(p(3),.0001),0,1);let r=t*coc*max(p(4),0);var c=tex(i.uv)*.2;c+=(tex(i.uv+vec2f(r.x,0))+tex(i.uv-vec2f(r.x,0))+tex(i.uv+vec2f(0,r.y))+tex(i.uv-vec2f(0,r.y)))*.1;c+=(tex(i.uv+r)+tex(i.uv-r)+tex(i.uv+vec2f(r.x,-r.y))+tex(i.uv+vec2f(-r.x,r.y)))*.1;return vec4f(c.rgb*i.color.rgb,tex(i.uv).a);}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 PostProcessWgsl.h 第 59 行定义.

◆ kDepthPyramidDownsample

constexpr const char* eve::graphics::shaders::kDepthPyramidDownsample
inlineconstexpr
初始值:
= R"wgsl(
fn depth_range(uv:vec2f)->vec2f{let v=tex(uv);return select(v.rg,vec2f(v.r),p(2)>.5);}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let t=vec2f(p(0),p(1));let a=depth_range(i.uv+t*vec2f(-.5,-.5));let b=depth_range(i.uv+t*vec2f(.5,-.5));let c=depth_range(i.uv+t*vec2f(-.5,.5));let d=depth_range(i.uv+t*vec2f(.5,.5));return vec4f(min(min(a.x,b.x),min(c.x,d.x)),max(max(a.y,b.y),max(c.y,d.y)),0,1);}
)wgsl"

在文件 PostProcessWgsl.h 第 62 行定义.

被这些函数引用 eve::graphics::DepthPyramid::DepthPyramid().

◆ kDofGaussian

constexpr const char* eve::graphics::shaders::kDofGaussian
inlineconstexpr
初始值:
= R"wgsl(
fn viewz(z:f32)->f32{let n=max(p(7),.0001);let f=max(p(8),n+.001);return n*f/max(f-z*(f-n),.000001);}
fn coc(viewZ:f32)->f32{let focus=max(p(4),0);let range=max(p(5),.001);let maxBlur=max(p(6),0);var t=clamp(abs(viewZ-focus)/range,0,1);t=t*t*(3-2*t);return t*maxBlur;}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{
let maxBlur=max(p(6),0);if maxBlur<=.0001{return tex(i.uv)*i.color;}
let ndc=aux_load(i.uv).r;let vz=viewz(ndc);let radius=coc(vz);
if radius<.35||ndc>=.9999{return tex(i.uv)*i.color;}
let stepUv=vec2f(p(2),p(3))*vec2f(p(0),p(1))*radius;
let kw=array<f32,5>(.227027,.1945946,.1216216,.054054,.016216);
var color=tex(i.uv).rgb*kw[0];var weight=kw[0];
for(var s=1;s<5;s++){let off=stepUv*f32(s);let uvA=clamp(i.uv+off,vec2f(0),vec2f(1));let uvB=clamp(i.uv-off,vec2f(0),vec2f(1));
let wA=kw[s]*select(0.0,1.0,coc(viewz(aux_load(uvA).r))>=radius*.35);let wB=kw[s]*select(0.0,1.0,coc(viewz(aux_load(uvB).r))>=radius*.35);
color+=tex(uvA).rgb*wA;color+=tex(uvB).rgb*wB;weight+=wA+wB;}
return vec4f(color/max(weight,.0001),1)*i.color;}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 PostProcessWgsl.h 第 129 行定义.

◆ kExposureAdapt

constexpr const char* eve::graphics::shaders::kExposureAdapt
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let target=max(tex(vec2f(.5)).r,.00001);let previous=max(aux_load(vec2f(.5)).r,.00001);let speed=select(max(p(2),0),max(p(1),0),target>previous);let blend=select(1-exp(-speed*max(p(0),0)),1.0,p(3)>.5);let exposure=mix(previous,target,clamp(blend,0,1));return vec4f(exposure,log2(exposure),0,1);}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 PostProcessWgsl.h 第 49 行定义.

被这些函数引用 eve::graphics::Exposure::Exposure().

◆ kExposureApply

constexpr const char* eve::graphics::shaders::kExposureApply
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let centered=i.uv-vec2f(.5);var sampleUv=i.uv;let lensIntensity=clamp(p(6),0,1)*100;if(lensIntensity>.0001){sampleUv=centered/clamp(p(17),.01,5)+vec2f(.5);let ruv=sampleUv-vec2f(.5);let ru=length(ruv);let theta=radians(min(160.0,1.6*max(lensIntensity,1.0)));let sigma=2*tan(theta*.5);let factor=tan(ru*theta)/(max(ru,.000001)*sigma);sampleUv+=ruv*(factor-1);}sampleUv=clamp(sampleUv,vec2f(.001),vec2f(.999));let hdr=tex(sampleUv);let lift=vec3f(p(7),p(8),p(9));let invGamma=max(vec3f(p(10),p(11),p(12)),vec3f(.001));let gain=vec3f(p(13),p(14),p(15));let pre=hdr.rgb*gain+lift;let graded=sign(pre)*pow(abs(pre),invGamma);let automatic=select(1.0,aux_load(vec2f(.5)).r,p(1)>.5);let colorFilter=max(vec3f(p(2),p(3),p(4)),vec3f(0));var vd=abs(sampleUv-vec2f(.5))*clamp(p(5),0,1)*3;vd.x*=f32(textureDimensions(MainTex).x)/f32(textureDimensions(MainTex).y);let vignette=pow(clamp(1-dot(vd,vd),0,1),clamp(p(16),.01,1)*5);return vec4f(graded*max(p(0),0)*automatic*colorFilter*vignette,hdr.a);}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 PostProcessWgsl.h 第 54 行定义.

被这些函数引用 eve::graphics::Exposure::Exposure().

◆ kExposureMeter

constexpr const char* eve::graphics::shaders::kExposureMeter
inlineconstexpr
初始值:
= R"wgsl(
fn exposure_luma(c:vec3f)->f32{return max(dot(max(c,vec3f(0)),vec3f(.2126,.7152,.0722)),.00001);}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{var v:array<f32,16>;var n=0;for(var y=0;y<4;y++){for(var x=0;x<4;x++){let uv=(vec2f(f32(x),f32(y))+.5)*.25;v[n]=log2(exposure_luma(tex(uv).rgb));n++;}}for(var a=1;a<16;a++){let value=v[a];var b=a-1;loop{if b<0||v[b]<=value{break;}v[b+1]=v[b];b--;}v[b+1]=value;}var average=0.0;for(var q=2;q<14;q++){average+=v[q];}average/=12;let ev=clamp(log2(.18)-average,p(0),p(1));return vec4f(exp2(ev),ev,0,1);}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 PostProcessWgsl.h 第 43 行定义.

被这些函数引用 eve::graphics::Exposure::Exposure().

◆ kFromDepth

constexpr const char* eve::graphics::shaders::kFromDepth
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{
let m=inv_vp();let nz=max(p(16),.001);let fz=max(p(17),nz+.001);let r=max(p(18),.0001);let bias=max(p(19),0);let count=i32(clamp(p(22),4,24));
let tw=max(p(23),.00001);let th=max(p(24),.00001);let z=depth(i.uv);if z>=.9999{return vec4f(0);}let pos=world(m,i.uv,z);
var n:vec3f;if p(25)>.5{let q=normal_load(i.uv)*2-1;n=normalize(select(vec3f(0,1,0),q,length(q)>.001));}
else{n=normalize(cross(world(m,i.uv+vec2f(tw,0),depth(i.uv+vec2f(tw,0)))-pos,world(m,i.uv+vec2f(0,th),depth(i.uv+vec2f(0,th)))-pos));}
let eh=m*vec4f(0,0,0,1);if dot(n,eh.xyz/max(eh.w,.000001)-pos)<0{n=-n;}var occ=0.0;
for(var s=1;s<=24;s++){if s>count{break;}let a=f32(s)*2.39996323;let q=f32(s)/f32(count);let uv=clamp(i.uv+vec2f(cos(a),sin(a))*q*r/max(mix(nz,fz,z),.001)*.25,vec2f(0),vec2f(1));
let sz=depth(uv);let d=world(m,uv,sz)-pos;let l=length(d);if l>.00001&&l<r&&dot(n,d/l)>bias&&sz<z-bias{occ+=1-l/r;}}
var ao=1-occ/f32(max(count,1));ao=clamp(pow(max(ao,0),max(p(21),.01)),0,1);let dark=clamp((1-ao)*max(p(20),0),0,1);return vec4f(0,0,0,dark)*i.color;
}
)wgsl"

在文件 AmbientOcclusionWgsl.h 第 111 行定义.

◆ kFxaa

constexpr const char* eve::graphics::shaders::kFxaa
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{
let t=vec2f(p(0),p(1));let c=tex(i.uv);let lm=luma(c.rgb);let n=luma(tex(i.uv-vec2f(0,t.y)).rgb);let s=luma(tex(i.uv+vec2f(0,t.y)).rgb);
let e=luma(tex(i.uv+vec2f(t.x,0)).rgb);let w=luma(tex(i.uv-vec2f(t.x,0)).rgb);let lo=min(lm,min(min(n,s),min(e,w)));let hi=max(lm,max(max(n,s),max(e,w)));
let range=hi-lo;if range<max(max(p(3),0),hi*max(p(2),.0001)){return vec4f(c.rgb*i.color.rgb,1);}
let gx=e-w;let gy=s-n;let tangent=normalize(vec2f(-gy,gx)+vec2f(.000001));let amount=clamp(range/max(hi,.00001)*clamp(p(4),0,1),0,.75);
let a=tex(i.uv-tangent*t*.75).rgb;let b=tex(i.uv+tangent*t*.75).rgb;return vec4f(mix(c.rgb,(a+b)*.5,amount)*i.color.rgb,1);
}
)wgsl"

在文件 PostProcessWgsl.h 第 67 行定义.

◆ kGrassFragWgsl

constexpr const char* eve::graphics::shaders::kGrassFragWgsl
inlineconstexpr

在文件 GrassWgsl.h 第 124 行定义.

被这些函数引用 eve::graphics::grass::createShader().

◆ kGrassVertWgsl

constexpr const char* eve::graphics::shaders::kGrassVertWgsl
inlineconstexpr

在文件 GrassWgsl.h 第 6 行定义.

被这些函数引用 eve::graphics::grass::createShader().

◆ kGtao

constexpr const char* eve::graphics::shaders::kGtao
inlineconstexpr
初始值:
= R"wgsl(
fn integrate(a:f32,b:f32)->f32{return clamp(.25*(-cos(2*b)+cos(2*a)+2*(b-a)),0,1);}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{
let m=inv_vp();let nz=max(p(16),.001);let fz=max(p(17),nz+.001);let r=max(p(18),.0001);let bias=max(p(19),0);
let dirs=i32(clamp(p(22),2,8));let steps=i32(clamp(p(23),2,8));let tw=max(p(24),.00001);let th=max(p(25),.00001);let thick=max(p(26),r*.5);
let z=depth(i.uv);if z>=.999||z<=.00001{return vec4f(1,1,1,z);}let pos=world(m,i.uv,z);
var n=normalize(cross(world(m,i.uv+vec2f(tw,0),depth(i.uv+vec2f(tw,0)))-pos,world(m,i.uv+vec2f(0,th),depth(i.uv+vec2f(0,th)))-pos));
let eh=m*vec4f(0,0,0,1);if dot(n,eh.xyz/max(eh.w,.000001)-pos)<0{n=-n;}let sr=clamp(r/max(mix(nz,fz,z),.001)*.4,tw*4,.25);
let rnd=hash12(i.uv*vec2f(640,480));let hp=-1.5707963+bias;var vis=0.0;
for(var d=0;d<8;d++){if d>=dirs{break;}let a=(f32(d)+rnd)/f32(dirs)*3.14159265;let dir=vec2f(cos(a),sin(a));var h1=hp;var h2=hp;
for(var s=1;s<=8;s++){if s>steps{break;}let q=sr*f32(s)/f32(steps);
let dp=world(m,i.uv+dir*q,depth(i.uv+dir*q))-pos;let dn=world(m,i.uv-dir*q,depth(i.uv-dir*q))-pos;let lp=length(dp);let ln=length(dn);
if lp>.0001&&lp<r{h1=max(h1,mix(-1.5707963,asin(clamp(dot(normalize(dp),n),-1,1)),1-lp/r));}
if ln>.0001&&ln<r{h2=max(h2,mix(-1.5707963,asin(clamp(dot(normalize(dn),n),-1,1)),1-ln/r));}}
let c=.5*(integrate(-1.5707963,clamp(h1,-1.5707963,1.5707963))+integrate(-1.5707963,clamp(h2,-1.5707963,1.5707963)));
let thin=smoothstep(0,1,(h1+h2+3.14159265)/max(thick/max(r,.001),.001));vis+=mix(c,max(c,.85),.2*(1-thin));}
vis/=f32(max(dirs,1));var ao=clamp(pow(max(vis,0),max(p(21),.01)),0,1);ao=mix(1,ao,clamp(p(20),0,2));return vec4f(ao,ao,ao,z)*i.color;
}
)wgsl"

在文件 AmbientOcclusionWgsl.h 第 76 行定义.

◆ kHairFragWgsl

constexpr const char* eve::graphics::shaders::kHairFragWgsl
inlineconstexpr
初始值:
=R"wgsl(
struct Light3D{posRadius:vec4f,color:vec4f,spot:vec4f};struct Frame{mvp:mat4x4f,model:mat4x4f,lightDir:vec4f,lightColor:vec4f,tint:vec4f,cameraPos:vec4f,ambient:vec4f,lights:array<Light3D,8>,texBomb:vec4f,parallax:vec4f,surface:vec4f,view:mat4x4f,clipInfo:vec4f,cloud:vec4f,cloudWind:vec4f};struct Params{data:array<vec4f,8>};
struct FSIn{@location(0)vNormal:vec3f,@location(1)vUV:vec2f,@location(2)vTint:vec4f,@location(3)vWorldPos:vec3f,@location(4)vCameraPos:vec3f,@location(5)vViewPos:vec3f,@builtin(position)fragCoord:vec4f};
@group(0)@binding(0)var<uniform>ubo:Frame;@group(0)@binding(1)var albedo:texture_2d<f32>;@group(0)@binding(7)var samp:sampler;@group(0)@binding(15)var<uniform>hp:Params;fn p(i:u32)->f32{return hp.data[i/4u][i%4u];}
fn kajiya(T:vec3f,L:vec3f,V:vec3f,e:f32)->f32{let tl=dot(T,L);let tv=dot(T,V);return pow(max(sqrt(max(1.-tl*tl,0.))*sqrt(max(1.-tv*tv,0.))+tl*tv,0.),e);}
fn saturate(x:f32)->f32{return clamp(x,0.,1.);}
@fragment fn fs_main(i:FSIn)->@location(0)vec4f{let base=textureSample(albedo,samp,i.vUV)*i.vTint;if base.a<p(4){discard;}let n=normalize(i.vNormal);let v=normalize(i.vCameraPos-i.vWorldPos);let l=normalize(ubo.lightDir.xyz);var t=vec3f(p(6),p(7),p(8));if length(t)<.001{t=normalize(cross(n,vec3f(.001,1,0)));}else{t=normalize(t-n*dot(t,n));}let a=normalize(t+n*p(2));let b=normalize(t+n*p(3));let c=normalize(t-n*p(2)*.5);let lobeR=max(p(9),0.);let lobeTT=max(p(10),0.);let lobeTRT=max(p(11),0.);let selfStr=saturate(p(12));let selfBias=saturate(p(13));let rootAoStr=saturate(p(14));let r=kajiya(a,l,v,max(p(0),4.))*lobeR;let tt=kajiya(b,l,v,max(p(0)*.65,1.))*0.45*lobeTT;let trt=kajiya(c,-l,v,max(p(0)*.35,1.))*0.35*lobeTRT;let diffuse=max(dot(n,l),0.)*.65+.35;let rim=pow(1.-max(dot(n,v),0.),2.)*max(p(5),0.);let fiber=mix(1.,smoothstep(-selfBias,1.-selfBias,dot(n,l)),selfStr);let rootAo=mix(1.,pow(saturate(i.vUV.y),1.25),rootAoStr);let shadow=saturate(fiber*rootAo);let rgb=(base.rgb*(ubo.ambient.rgb+ubo.lightColor.rgb*diffuse)+ubo.lightColor.rgb*((r+tt+trt)*max(p(1),0.)+rim))*shadow;return vec4f(rgb,base.a);}
)wgsl"

Hair fragment shader WGSL source. @ownership Borrowed immutable string literal; callers must not free it. @lifetime Static storage duration, valid for the entire process lifetime. @thread Safe for concurrent reads.

在文件 HairWgsl.h 第 8 行定义.

被这些函数引用 eve::graphics::hair::createShader().

◆ kHbao

constexpr const char* eve::graphics::shaders::kHbao
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i: FSIn) -> @location(0) vec4f {
let m=inv_vp(); let nz=max(p(16),.001); let fz=max(p(17),nz+.001); let r=max(p(18),.0001);
let bias=max(p(19),0); let dirs=i32(clamp(p(22),2,8)); let steps=i32(clamp(p(23),2,8));
let tw=max(p(24),.00001); let th=max(p(25),.00001); let z=depth(i.uv); if z>=.999||z<=.00001{return vec4f(1,1,1,z);}
let pos=world(m,i.uv,z); var n=normalize(cross(world(m,i.uv+vec2f(tw,0),depth(i.uv+vec2f(tw,0)))-pos,world(m,i.uv+vec2f(0,th),depth(i.uv+vec2f(0,th)))-pos));
let eh=m*vec4f(0,0,0,1); if dot(n,eh.xyz/max(eh.w,.000001)-pos)<0{n=-n;}
let sr=clamp(r/max(mix(nz,fz,z),.001)*.35,tw*4,.25); let rnd=hash12(i.uv*vec2f(900,700)); var sum=0.0;
for(var d=0;d<8;d++){if d>=dirs{break;} let a=(f32(d)+rnd)/f32(dirs)*6.2831853; let dir=vec2f(cos(a),sin(a)); var h=bias;
for(var s=1;s<=8;s++){if s>steps{break;} let uv=i.uv+dir*sr*f32(s)/f32(steps); let delta=world(m,uv,depth(uv))-pos; let dist=length(delta);
if dist>.00001&&dist<r {h=max(h,dot(normalize(delta),n)*(1-clamp(dist/r,0,1)));}}
sum+=1-clamp(h,0,1);
}
var ao=sum/f32(max(dirs,1)); ao=clamp(pow(max(ao,0),max(p(21),.01)),0,1); ao=mix(1,ao,clamp(p(20),0,2)); return vec4f(ao,ao,ao,z)*i.color;
}
)wgsl"

在文件 AmbientOcclusionWgsl.h 第 59 行定义.

◆ kNfaa

constexpr const char* eve::graphics::shaders::kNfaa
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let t=vec2f(p(0),p(1));let c=tex(i.uv).rgb;
let g=vec2f(luma(tex(i.uv+vec2f(t.x,0)).rgb)-luma(tex(i.uv-vec2f(t.x,0)).rgb),luma(tex(i.uv+vec2f(0,t.y)).rgb)-luma(tex(i.uv-vec2f(0,t.y)).rgb));
let gl=length(g);if gl<.00001{return vec4f(c*i.color.rgb,1);}let tangent=vec2f(-g.y,g.x)/gl;let amt=clamp(p(2),0,2)*pow(clamp(gl*4,0,1),max(p(3),.1));let o=tangent*t*clamp(p(4),.5,2.5)*amt;
let f=(tex(i.uv-o*1.5).rgb+2*tex(i.uv-o*.5).rgb+2*c+2*tex(i.uv+o*.5).rgb+tex(i.uv+o*1.5).rgb)/8;
return vec4f(mix(c,f,clamp(amt,0,1))*i.color.rgb,1);}
)wgsl"

在文件 PostProcessWgsl.h 第 77 行定义.

◆ kOutline

constexpr const char* eve::graphics::shaders::kOutline
inlineconstexpr
初始值:
= R"wgsl(
fn aux(uv:vec2f)->vec3f{let n=aux_load(uv).xyz*2-1;return select(vec3f(0,0,1),normalize(n),length(n)>.001);}
fn viewz(z:f32)->f32{let n=max(p(10),.0001);let f=max(p(11),n+.001);return n*f/max(f-z*(f-n),.000001);}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let color=vec3f(p(5),p(6),p(7));let z=tex(i.uv).r;if z>=.9999{return vec4f(color,0);}let t=vec2f(max(p(8),.00001),max(p(9),.00001))*max(p(0),.5);let nc=aux(i.uv);let dc=viewz(z);var de=0.0;var ne=0.0;
let offsets=array<vec2f,8>(vec2f(1,0),vec2f(-1,0),vec2f(0,1),vec2f(0,-1),vec2f(.707,.707),vec2f(-.707,-.707),vec2f(-.707,.707),vec2f(.707,-.707));
for(var q=0;q<8;q++){let uv=i.uv+offsets[q]*t;let cut=max(p(1),0)+dc*max(p(2),0);let dd=abs(dc-viewz(tex(uv).r));let soft=clamp(p(4),0,1);de=max(de,smoothstep(cut*(1-soft),cut,dd));ne=max(ne,1-clamp(dot(nc,aux(uv)),-1,1));}
let nt=clamp(p(3),0,2);let edge=max(de,smoothstep(nt*(1-clamp(p(4),0,1)),nt+clamp(p(4),0,1),ne));return vec4f(color,clamp(edge,0,1))*i.color;}
)wgsl"

在文件 PostProcessWgsl.h 第 119 行定义.

◆ kOverlay

constexpr const char* eve::graphics::shaders::kOverlay
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{var ao=depth(i.uv);ao=clamp(pow(max(ao,0),max(p(1),.01)),0,1);let d=clamp((1-ao)*max(p(0),0),0,1);return vec4f(0,0,0,d)*i.color;}
)wgsl"

在文件 AmbientOcclusionWgsl.h 第 105 行定义.

◆ kPostCommon

constexpr const char* eve::graphics::shaders::kPostCommon
inlineconstexpr
初始值:
= R"wgsl(
struct FSIn { @location(0) color: vec4f, @location(1) uv: vec2f };
struct Externals { data: array<vec4f, 8> };
@group(0) @binding(0) var mainTex: texture_2d<f32>;
@group(0) @binding(1) var auxTex: texture_2d<f32>;
@group(0) @binding(2) var samp: sampler;
@group(0) @binding(4) var<uniform> u: Externals;
@group(0) @binding(5) var motionTex: texture_2d<f32>;
@group(0) @binding(6) var motionSamp: sampler;
fn p(i:u32)->f32{return u.data[i/4u][i%4u];}
fn tex(uv:vec2f)->vec4f{return textureSampleLevel(mainTex,samp,clamp(uv,vec2f(0),vec2f(1)),0);}
fn luma(c:vec3f)->f32{return dot(c,vec3f(.299,.587,.114));}
fn aux_load(uv:vec2f)->vec4f{let d=textureDimensions(auxTex);let q=vec2i(clamp(uv,vec2f(0),vec2f(1))*vec2f(d));return textureLoad(auxTex,clamp(q,vec2i(0),vec2i(d)-1),0);}
fn motion_load(uv:vec2f)->vec4f{return textureSampleLevel(motionTex,motionSamp,clamp(uv,vec2f(0),vec2f(1)),0);}
fn cubic_weights(t:f32)->vec4f{let t2=t*t;let t3=t2*t;return vec4f(-.5*t+t2-.5*t3,1-2.5*t2+1.5*t3,.5*t+2*t2-1.5*t3,-.5*t2+.5*t3);}
fn aux_cubic(uv:vec2f)->vec4f{let size=vec2f(textureDimensions(auxTex));let position=uv*size-.5;let base=floor(position);let f=fract(position);let wx=cubic_weights(f.x);let wy=cubic_weights(f.y);var result=vec4f(0);for(var y=0;y<4;y++){for(var x=0;x<4;x++){let suv=(base+vec2f(f32(x-1),f32(y-1))+.5)/size;result+=textureSampleLevel(auxTex,samp,clamp(suv,vec2f(0),vec2f(1)),0)*wx[x]*wy[y];}}return result;}
fn rgb_to_ycocg(c:vec3f)->vec3f{return vec3f(c.r*.25+c.g*.5+c.b*.25,c.r*.5-c.b*.5,-c.r*.25+c.g*.5-c.b*.25);}
fn ycocg_to_rgb(c:vec3f)->vec3f{return vec3f(c.x+c.y-c.z,c.x+c.z,c.x-c.y-c.z);}
fn hdr_ycocg(c:vec3f)->vec3f{let q=rgb_to_ycocg(max(c,vec3f(0)));let r=1+max(q.x,0);return vec3f(log2(r),q.yz/r);}
fn hdr_rgb(c:vec3f)->vec3f{let y=max(exp2(c.x)-1,0);let r=1+y;return max(ycocg_to_rgb(vec3f(y,c.yz*r)),vec3f(0));}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 PostProcessWgsl.h 第 6 行定义.

被这些函数引用 eve::graphics::DepthPyramid::DepthPyramid().

◆ kReflectionProbeFilterWgsl

constexpr const char* eve::graphics::shaders::kReflectionProbeFilterWgsl
inlineconstexpr

@lifetime Shader source has static storage for the process lifetime.

在文件 ReflectionProbeWgsl.h 第 6 行定义.

◆ kScreenEffectCommon

constexpr const char* eve::graphics::shaders::kScreenEffectCommon
inlineconstexpr
初始值:
= R"wgsl(
struct FSIn { @location(0) color: vec4f, @location(1) uv: vec2f };
struct Externals { data: array<vec4f,8> };
@group(0) @binding(0) var mainTex:texture_2d<f32>;
@group(0) @binding(1) var depthTex:texture_2d<f32>;
@group(0) @binding(2) var samp:sampler;
@group(0) @binding(4) var<uniform> u:Externals;
@group(0) @binding(5) var normalTex:texture_2d<f32>;
@group(0) @binding(6) var normalSamp:sampler;
@group(0) @binding(7) var albedoTex:texture_2d<f32>;
@group(0) @binding(8) var albedoSamp:sampler;
fn p(i:u32)->f32{return u.data[i/4u][i%4u];}
fn invvp()->mat4x4f{return mat4x4f(u.data[0],u.data[1],u.data[2],u.data[3]);}
fn color_at(uv:vec2f)->vec3f{return textureSampleLevel(mainTex,samp,clamp(uv,vec2f(0),vec2f(1)),0).rgb;}
fn depth_at(uv:vec2f)->f32{let d=textureDimensions(depthTex);let q=vec2i(clamp(uv,vec2f(0),vec2f(1))*vec2f(d));return textureLoad(depthTex,clamp(q,vec2i(0),vec2i(d)-1),0).r;}
fn normal_at(uv:vec2f)->vec3f{return textureSampleLevel(normalTex,normalSamp,clamp(uv,vec2f(0),vec2f(1)),0).xyz*2-1;}
fn pbr_at(uv:vec2f)->u32{return u32(round(textureSampleLevel(normalTex,normalSamp,clamp(uv,vec2f(0),vec2f(1)),0).a*255));}
fn roughness_at(uv:vec2f)->f32{return f32(pbr_at(uv)&7u)/7;}
fn metallic_at(uv:vec2f)->f32{return f32((pbr_at(uv)>>3u)&7u)/7;}
fn color_rough(uv:vec2f,r:f32)->vec3f{let d=vec2f(max(p(21),.00001),max(p(22),.00001))*(1+r*6);return color_at(uv)*.4+(color_at(uv+vec2f(d.x,0))+color_at(uv-vec2f(d.x,0))+color_at(uv+vec2f(0,d.y))+color_at(uv-vec2f(0,d.y)))*.15;}
fn world(m:mat4x4f,uv:vec2f,z:f32)->vec3f{let h=m*vec4f(uv*2-1,clamp(z,0,1),1);return h.xyz/max(h.w,.000001);}
fn history_weights(t:f32)->vec4f{let t2=t*t;let t3=t2*t;return vec4f(-.5*t+t2-.5*t3,1-2.5*t2+1.5*t3,.5*t+2*t2-1.5*t3,-.5*t2+.5*t3);}
fn history_cubic(uv:vec2f)->vec4f{let size=vec2f(textureDimensions(depthTex));let position=uv*size-.5;let base=floor(position);let f=fract(position);let wx=history_weights(f.x);let wy=history_weights(f.y);var result=vec4f(0);for(var y=0;y<4;y++){for(var x=0;x<4;x++){let suv=(base+vec2f(f32(x-1),f32(y-1))+.5)/size;result+=textureSampleLevel(depthTex,samp,clamp(suv,vec2f(0),vec2f(1)),0)*wx[x]*wy[y];}}return result;}
)wgsl"

在文件 ScreenEffectsWgsl.h 第 5 行定义.

◆ kSmaa

constexpr const char* eve::graphics::shaders::kSmaa
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let t=vec2f(p(0),p(1));let c=tex(i.uv).rgb;let m=luma(c);
let dl=abs(m-luma(tex(i.uv-vec2f(t.x,0)).rgb));let dt=abs(m-luma(tex(i.uv-vec2f(0,t.y)).rgb));let dr=abs(m-luma(tex(i.uv+vec2f(t.x,0)).rgb));let db=abs(m-luma(tex(i.uv+vec2f(0,t.y)).rgb));
let threshold=max(p(2),.0001);let mx=max(max(dl,dt),max(dr,db));var rgb=c;if dl>=threshold&&dl>=mx*max(p(3),0){rgb=(c+tex(i.uv-vec2f(t.x,0)).rgb)*.5;}
if dt>=threshold&&dt>=mx*max(p(3),0){rgb=(rgb+tex(i.uv-vec2f(0,t.y)).rgb)*.5;}return vec4f(rgb*i.color.rgb,1);}
)wgsl"

在文件 PostProcessWgsl.h 第 106 行定义.

◆ kSsaa

constexpr const char* eve::graphics::shaders::kSsaa
inlineconstexpr
初始值:
= R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let t=vec2f(p(0),p(1));let radius=clamp(p(4),.5,3);let kind=i32(clamp(p(3),0,2));var sum=vec3f(0);var ws=0.0;
for(var y=-3;y<=3;y++){for(var x=-3;x<=3;x++){if abs(f32(x))>radius||abs(f32(y))>radius{continue;}let d2=f32(x*x+y*y);var w=1.0;if kind==1{w=max(1-abs(f32(x))/(radius+.0001),0)*max(1-abs(f32(y))/(radius+.0001),0);}if kind==2{let s=max(radius*.5,.35);w=exp(-d2/(2*s*s));}sum+=tex(i.uv+vec2f(f32(x)*t.x,f32(y)*t.y)).rgb*w;ws+=w;}}
return vec4f(sum/max(ws,.0001)*i.color.rgb,1);}
)wgsl"

在文件 PostProcessWgsl.h 第 113 行定义.

◆ kSsao

constexpr const char* eve::graphics::shaders::kSsao
inlineconstexpr
初始值:
= R"wgsl(
fn kernel(i: i32) -> vec3f {
let f = f32(i); let z = fract(f * 0.6180339887); let a = f * 2.3999632297;
let r = sqrt(max(1 - z*z, 0)) * mix(0.2, 1.0, (f + 1) / 24.0);
return vec3f(cos(a)*r, sin(a)*r, z);
}
@fragment fn fs_main(i: FSIn) -> @location(0) vec4f {
let m=inv_vp(); let nZ=max(p(16),.001); let fZ=max(p(17),nZ+.001);
let rad=max(p(18),.0001); let bias=max(p(19),0); let count=i32(clamp(p(22),4,24));
let tw=max(p(23),.00001); let th=max(p(24),.00001); let z=depth(i.uv);
if z>=.999 || z<=.00001 { return vec4f(1,1,1,z); }
let pos=world(m,i.uv,z); let pr=world(m,i.uv+vec2f(tw,0),depth(i.uv+vec2f(tw,0)));
let pu=world(m,i.uv+vec2f(0,th),depth(i.uv+vec2f(0,th)));
var nor=normalize(cross(pr-pos,pu-pos)); let eh=m*vec4f(0,0,0,1); let cam=eh.xyz/max(eh.w,.000001);
if dot(nor,cam-pos)<0 { nor=-nor; }
let a=hash12(i.uv*vec2f(1024,768))*6.2831853; let up=select(vec3f(0,1,0),vec3f(1,0,0),abs(nor.y)>=.999);
var tan=normalize(up-nor*dot(up,nor)); let bit=cross(nor,tan); tan=tan*cos(a)+bit*sin(a);
let tbn=mat3x3f(tan,cross(nor,tan),nor); let rz=mix(nZ,fZ,z);
let ur=clamp((rad/max(rz,.001))*.25,tw*2,.2); var occ=0.0;
for(var s=0;s<24;s++){ if s>=count {break;} let k=kernel(s); let o=(tbn*k).xy;
let uv=clamp(i.uv+normalize(o+vec2f(.00001))*ur*length(k.xy),vec2f(0),vec2f(1));
let sz=depth(uv); let sp=world(m,uv,sz); let d=sp-pos; let dist=length(d);
if dist>.00001 { let nd=dot(nor,d/dist); let range=1-smoothstep(rad*.5,rad,dist);
if nd>bias && mix(nZ,fZ,sz)<rz-bias { occ+=range; } }
}
var ao=1-occ/f32(max(count,1))*clamp(p(20),0,2); ao=clamp(pow(max(ao,0),max(p(21),.01)),0,1);
return vec4f(ao,ao,ao,z)*i.color;
}
)wgsl"

在文件 AmbientOcclusionWgsl.h 第 29 行定义.

◆ kSsgi

constexpr const char* eve::graphics::shaders::kSsgi
inlineconstexpr
初始值:
= R"wgsl(
fn gi_depth(uv:vec2f,use:f32)->f32{if use>.5{let levels=floor(floor(p(31))/8);let q=select(uv,vec2f(uv.x*.5,uv.y),levels>.5);return depth_at(q);}return textureSampleLevel(mainTex,samp,clamp(uv,vec2f(0),vec2f(1)),0).a;}
fn gi_depth_range(uv0:vec2f,requested:i32)->vec2f{let uv=clamp(uv0,vec2f(0),vec2f(1));let levels=i32(floor(floor(p(31))/8));if levels<=0{return vec2f(depth_at(uv));}let mip=clamp(requested,0,levels-1);let atlas=textureDimensions(depthTex);var width=max(atlas.x/2u,1u);var height=max(atlas.y,1u);var offset=0u;for(var level=0;level<mip;level++){offset+=width;width=max(width/2u,1u);height=max(height/2u,1u);}let pixel=vec2u(clamp(floor(uv*vec2f(f32(width),f32(height))),vec2f(0),vec2f(f32(width-1u),f32(height-1u))));return textureLoad(depthTex,vec2i(offset+pixel.x,pixel.y),0).rg;}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{let m=invvp();let radius=max(p(18),.0001);let intensity=max(p(19),0);let count=i32(clamp(p(20),4,32));let tw=max(p(27),.00001);let th=max(p(28),.00001);let use=p(29);let z=gi_depth(i.uv,use);
if z>=select(.999,.9999,use>.5)||intensity<.0001{return vec4f(0);}let pos=world(m,i.uv,z);let nh=m*vec4f(0,0,0,1);let fh=m*vec4f(0,0,1,1);let nc=nh.xyz/max(nh.w,.000001);let fc=fh.xyz/max(fh.w,.000001);let cam=nc-normalize(fc-nc)*max(p(16),.0001);
let dr=gi_depth(i.uv+vec2f(tw,0),use);let du=gi_depth(i.uv+vec2f(0,th),use);var n=normalize(cross(world(m,i.uv+vec2f(tw,0),dr)-pos,world(m,i.uv+vec2f(0,th),du)-pos));let packed=normal_at(i.uv);let receiverMetal=select(0.0,metallic_at(i.uv),p(30)>.5);if p(30)>.5&&dot(packed,packed)>.25{n=normalize(packed);}if dot(n,cam-pos)<0{n=-n;}
let up=select(vec3f(0,1,0),vec3f(1,0,0),abs(n.y)>.999);let tangent=normalize(up-n*dot(up,n));let bit=cross(n,tangent);let vp=inverse(m);let lightDir=normalize(vec3f(p(21),p(22),p(23))+vec3f(.000001));let lightColor=max(vec3f(p(24),p(25),p(26)),vec3f(0));var bounce=vec3f(0);var weight=0.0;var hitCount=0.0;
for(var q=1;q<=32;q++){if q>count{break;}let f=f32(q);let phase=floor(p(31))-floor(floor(p(31))/8)*8;let a=(f+phase*.618033989)*2.39996323;let rr=sqrt(fract((f+phase*.754877666)*.618033989));let dir=normalize(tangent*cos(a)+bit*sin(a)+n*.55);let samplePos=pos+dir*radius*rr;let clip=vp*vec4f(samplePos,1);let suv=clip.xy/max(clip.w,.000001)*.5+.5;if any(suv<vec2f(0))||any(suv>vec2f(1)){continue;}let levels=i32(floor(floor(p(31))/8));if levels>0&&use>.5{let footprint=abs(suv-i.uv)/vec2f(tw,th);let mip=clamp(i32(floor(log2(max(max(footprint.x,footprint.y)*.125,1)))),0,levels-1);let range=gi_depth_range(suv,mip);let padding=max(.0001,max(fract(p(31)),max(radius*.08,.01))/max(p(17),.001));if ndc.z<range.x-padding||ndc.z>range.y+padding{continue;}}let sz=gi_depth(suv,use);let hit=world(m,suv,sz);let mismatch=distance(hit,samplePos);let thick=max(fract(p(31)),max(radius*.08,.01));if mismatch>thick{continue;}var sn=normal_at(suv);if p(30)<.5||dot(sn,sn)<.25{sn=n;}else{sn=normalize(sn);}let toHit=hit-pos;let dist=length(toHit);if dist<.0001||dist>radius{continue;}let l=toHit/dist;let recv=max(dot(n,l),0);let send=max(dot(sn,-l),0);let directional=mix(.35,1,max(dot(sn,lightDir),0));let w=(1-smoothstep(radius*.4,radius,dist))*recv*send*(1-smoothstep(thick*.25,thick,mismatch))*directional;bounce+=color_at(suv)*lightColor*w;weight+=w;hitCount+=1;}
if weight<.0001{return vec4f(0);}let coverage=hitCount/max(f32(count),1);let receiverAlbedo=select(color_at(i.uv),textureSampleLevel(albedoTex,albedoSamp,i.uv,0).rgb,p(29)>.5&&p(30)>.5);bounce=bounce/weight*smoothstep(.08,.35,coverage)*intensity*receiverAlbedo*(1-receiverMetal);let alpha=clamp(max(bounce.r,max(bounce.g,bounce.b)),0,1);return vec4f(bounce/max(alpha,.0001),alpha)*i.color;}
)wgsl"

在文件 ScreenEffectsWgsl.h 第 30 行定义.

◆ kSsr

constexpr const char* eve::graphics::shaders::kSsr
inlineconstexpr
初始值:
= R"wgsl(
fn ssr_depth_range(uv0:vec2f,requested:i32)->vec2f{let uv=clamp(uv0,vec2f(0),vec2f(1));if p(31)<.5{return vec2f(depth_at(uv));}let mip=clamp(requested,0,max(i32(floor(p(31)))-1,0));let atlas=textureDimensions(depthTex);var width=max(atlas.x/2u,1u);var height=max(atlas.y,1u);var offset=0u;for(var level=0;level<mip;level++){offset+=width;width=max(width/2u,1u);height=max(height/2u,1u);}let pixel=vec2u(clamp(floor(uv*vec2f(f32(width),f32(height))),vec2f(0),vec2f(f32(width-1u),f32(height-1u))));return textureLoad(depthTex,vec2i(offset+pixel.x,pixel.y),0).rg;}
fn ssr_depth(uv:vec2f)->f32{return ssr_depth_range(uv,0).r;}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{if p(28)<.5{return vec4f(0);}let z=ssr_depth(i.uv);if z>.999{return vec4f(0);}let m=invvp();let vp=inverse(m);let pos=world(m,i.uv,z);let tw=max(p(21),.00001);let th=max(p(22),.00001);let rough=roughness_at(i.uv);if rough>clamp(p(30),0,1){return vec4f(0);}
var n=normal_at(i.uv);if dot(n,n)<.25{n=normalize(cross(world(m,i.uv+vec2f(tw,0),ssr_depth(i.uv+vec2f(tw,0)))-pos,world(m,i.uv+vec2f(0,th),ssr_depth(i.uv+vec2f(0,th)))-pos));}else{n=normalize(n);}let cam=vec3f(p(16),p(17),p(18));if dot(n,cam-pos)<0{n=-n;}let v=normalize(cam-pos);let metal=metallic_at(i.uv);let surface=color_at(i.uv);let r=reflect(-v,n);if dot(r,v)>.1{return vec4f(0);}
let maxd=max(p(23),.01);let step=max(p(24),.001)*mix(.65,1.35,rough);let thickness=max(p(26),.001);let rayOrigin=pos+n*max(thickness*.02,.002);let count=i32(clamp(p(25),1,512));var ray=step;var previousRay=0.0;
for(var q=0;q<512;q++){if q>=count||ray>maxd{break;}let rayPos=rayOrigin+r*ray;let clip=vp*vec4f(rayPos,1);let ndc=clip.xyz/max(clip.w,.000001);var uv=ndc.xy*.5+.5;if any(uv<vec2f(0))||any(uv>vec2f(1))||ndc.z<0||ndc.z>1{break;}var traceMip=0;if p(31)>.5{let cone=1+rough*2*ray/max(step,.0001);traceMip=clamp(i32(floor(log2(max(cone,1)))),0,max(i32(floor(p(31)))-1,0));let range=ssr_depth_range(uv,traceMip);let padding=max(p(29),(range.y-range.x)*.25);if ndc.z<range.x-padding{previousRay=ray;ray+=step*exp2(f32(traceMip));continue;}}let scenePos=world(m,uv,ssr_depth(uv));let gap=distance(rayPos,scenePos);if ndc.z>ssr_depth(uv)-p(29)&&gap<=max(thickness,step*1.25){var lo=previousRay;var hi=ray;var refined=uv;for(var refine=0;refine<5;refine++){let mid=(lo+hi)*.5;let rc=vp*vec4f(rayOrigin+r*mid,1);let rn=rc.xyz/max(rc.w,.000001);let candidate=rn.xy*.5+.5;if rn.z>ssr_depth(candidate)-p(29){hi=mid;refined=candidate;}else{lo=mid;}}ray=hi;uv=refined;let refinedGap=distance(rayOrigin+r*ray,world(m,uv,ssr_depth(uv)));let hitAccuracy=1-smoothstep(thickness*.2,max(thickness,step*1.25),refinedGap);let hn=normal_at(uv);let hitFacing=select(1.0,smoothstep(.02,.25,dot(normalize(hn),-r)),dot(hn,hn)>.25);let center=ssr_depth(uv);let depthEdge=max(max(abs(ssr_depth(uv+vec2f(tw,0))-center),abs(ssr_depth(uv-vec2f(tw,0))-center)),max(abs(ssr_depth(uv+vec2f(0,th))-center),abs(ssr_depth(uv-vec2f(0,th))-center)));let continuity=1-smoothstep(.002,.025,depthEdge);let border=min(min(uv.x,uv.y),min(1-uv.x,1-uv.y));let sourceBorder=min(min(i.uv.x,i.uv.y),min(1-i.uv.x,1-i.uv.y));let rf=1-smoothstep(.35,1,rough)*.85;let confidence=clamp(smoothstep(.02,.12,border)*smoothstep(.01,.06,sourceBorder)*(1-smoothstep(0,maxd,ray))*max(p(27),0)*rf*hitFacing*continuity*hitAccuracy,0,1);let materialAlbedo=textureSampleLevel(albedoTex,albedoSamp,i.uv,0).rgb;let diffuseBasis=materialAlbedo*(1-metal);let safeBasis=max(diffuseBasis,vec3f(.001));let diffuseScale=max(min(surface.r/safeBasis.r,min(surface.g/safeBasis.g,surface.b/safeBasis.b)),0);let diffuseEstimate=min(diffuseBasis*diffuseScale,surface);let f0=mix(vec3f(.04),materialAlbedo,metal);let noV=max(dot(n,v),0);let brdf=rough*vec4f(-1,-.0275,-.572,.022)+vec4f(1,.0425,1.04,-.04);let a004=min(brdf.x*brdf.x,exp2(-9.28*noV))*brdf.x+brdf.y;let dfg=vec2f(-1.04,1.04)*a004+brdf.zw;let specWeight=max(f0*dfg.x+dfg.y,vec3f(0));let directionalAlbedo=max(dfg.x+dfg.y,.001);let multiScatter=vec3f(1)+f0*(min(1/directionalAlbedo,8)-1);let reflectedScene=diffuseEstimate+color_rough(uv,rough)*specWeight*multiScatter;return vec4f(reflectedScene*confidence,confidence)*i.color;}previousRay=ray;ray+=step;}
return vec4f(0);}
)wgsl"

在文件 ScreenEffectsWgsl.h 第 41 行定义.

◆ kSsrTemporal

constexpr const char* eve::graphics::shaders::kSsrTemporal
inlineconstexpr
初始值:
= R"wgsl(
fn ssr_reprojection()->mat4x4f{return mat4x4f(u.data[0],u.data[1],u.data[2],u.data[3]);}
fn temporal_decode_input(v0:vec4f)->vec4f{var v=v0;if p(23)>.5{v=vec4f(v.rgb*v.a,v.a);}return v;}
fn temporal_encode_output(v0:vec4f)->vec4f{var v=v0;if p(23)>.5{v=vec4f(v.rgb/max(v.a,.0001),v.a);}return v;}
fn temporal_spatial(uv:vec2f)->vec4f{let base=vec2f(p(16),p(17));let t=base*max(p(24),1);let centerDepth=textureSampleLevel(normalTex,normalSamp,uv,0).r;let center=temporal_decode_input(textureSampleLevel(mainTex,samp,uv,0));let centerRadiance=center.rgb/max(center.a,.05);let centerLog=log2(1+dot(max(centerRadiance,vec3f(0)),vec3f(.2126,.7152,.0722)));let dx=max(abs(textureSampleLevel(normalTex,normalSamp,uv+vec2f(base.x,0),0).r-centerDepth),abs(textureSampleLevel(normalTex,normalSamp,uv-vec2f(base.x,0),0).r-centerDepth));let dy=max(abs(textureSampleLevel(normalTex,normalSamp,uv+vec2f(0,base.y),0).r-centerDepth),abs(textureSampleLevel(normalTex,normalSamp,uv-vec2f(0,base.y),0).r-centerDepth));let depthScale=max(.0015,max(dx,dy)*2+.0005);var sum=center*4;var total=4.0;let offsets=array<vec2f,8>(vec2f(1,0),vec2f(-1,0),vec2f(0,1),vec2f(0,-1),vec2f(1,1),vec2f(-1,1),vec2f(1,-1),vec2f(-1,-1));for(var q=0;q<8;q++){let suv=uv+offsets[q]*t;let value=temporal_decode_input(textureSampleLevel(mainTex,samp,suv,0));let sampleDepth=textureSampleLevel(normalTex,normalSamp,suv,0).r;let depthWeight=exp(-abs(sampleDepth-centerDepth)/depthScale);let radiance=value.rgb/max(value.a,.05);let sampleLog=log2(1+dot(max(radiance,vec3f(0)),vec3f(.2126,.7152,.0722)));let radianceWeight=exp(-abs(sampleLog-centerLog)*1.5);let confidenceWeight=mix(.35,1,clamp(value.a*6,0,1));let kernelWeight=select(1.0,2.0,q<4);let weight=kernelWeight*depthWeight*radianceWeight*confidenceWeight*clamp(p(22),0,1);sum+=value*weight;total+=weight;}return sum/max(total,.0001);}
fn temporal_rgb_to_ycocg(c:vec3f)->vec3f{return vec3f(c.r*.25+c.g*.5+c.b*.25,c.r*.5-c.b*.5,-c.r*.25+c.g*.5-c.b*.25);}
fn temporal_ycocg_to_rgb(c:vec3f)->vec3f{return vec3f(c.x+c.y-c.z,c.x+c.z,c.x-c.y-c.z);}
fn temporal_hdr_encode(c:vec3f)->vec3f{let q=temporal_rgb_to_ycocg(max(c,vec3f(0)));let r=1+max(q.x,0);return vec3f(log2(r),q.yz/r);}
fn temporal_hdr_decode(c:vec3f)->vec3f{let y=max(exp2(c.x)-1,0);let r=1+y;return max(temporal_ycocg_to_rgb(vec3f(y,c.yz*r)),vec3f(0));}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{
var current=temporal_spatial(i.uv);if p(18)<.5{return temporal_encode_output(current)*i.color;}
let texel=vec2f(p(16),p(17));let currentEncoded=temporal_hdr_encode(current.rgb);var lo=currentEncoded;var hi=currentEncoded;var sum=vec3f(0);var sumSq=vec3f(0);
for(var y=-1;y<=1;y++){for(var x=-1;x<=1;x++){let s=temporal_hdr_encode(temporal_decode_input(textureSampleLevel(mainTex,samp,i.uv+vec2f(f32(x)*texel.x,f32(y)*texel.y),0)).rgb);lo=min(lo,s);hi=max(hi,s);sum+=s;sumSq+=s*s;}}
let mean=sum/9;let sigma=sqrt(max(sumSq/9-mean*mean,vec3f(0)));lo=max(lo,mean-sigma*1.5);hi=min(hi,mean+sigma*1.5);hi.x=min(hi.x,mean.x+3);current=vec4f(temporal_hdr_decode(clamp(currentEncoded,lo,hi)),current.a);
let md=textureSampleLevel(normalTex,normalSamp,i.uv,0);let n=max(p(19),.0001);let f=max(p(20),n+.001);let vd=mix(n,f,md.r);let z=(f-n*f/max(vd,n))/(f-n);let pc=ssr_reprojection()*vec4f(i.uv*2-1,z,1);var huv=pc.xy/max(abs(pc.w),.000001)*.5+.5;huv+=(md.gb-vec2f(.5))*2;
let valid=all(huv>=vec2f(0))&&all(huv<=vec2f(1))&&pc.w>0;var history=temporal_decode_input(history_cubic(clamp(huv,vec2f(0),vec2f(1))));history=vec4f(temporal_hdr_decode(clamp(temporal_hdr_encode(history.rgb),lo,hi)),clamp(history.a,0,1));let cd=abs(current.a-history.a);let velocity=length((md.gb-vec2f(.5))*2);let historyDepth=textureSampleLevel(normalTex,normalSamp,clamp(huv,vec2f(0),vec2f(1)),0).r;let depthGradient=max(max(abs(textureSampleLevel(normalTex,normalSamp,i.uv+vec2f(texel.x,0),0).r-md.r),abs(textureSampleLevel(normalTex,normalSamp,i.uv-vec2f(texel.x,0),0).r-md.r)),max(abs(textureSampleLevel(normalTex,normalSamp,i.uv+vec2f(0,texel.y),0).r-md.r),abs(textureSampleLevel(normalTex,normalSamp,i.uv-vec2f(0,texel.y),0).r-md.r)));let depthTolerance=max(.0015,depthGradient*2+velocity*.5);let depthReject=smoothstep(depthTolerance,depthTolerance*4,abs(historyDepth-md.r));var reject=max(depthReject,max(smoothstep(.08,.35,cd),smoothstep(.01,.08,velocity)));if !valid||current.a<.01{reject=1;}return temporal_encode_output(mix(history,current,mix(clamp(p(21),.02,1),1,reject)))*i.color;
}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 ScreenEffectsWgsl.h 第 52 行定义.

◆ kTaa

constexpr const char* eve::graphics::shaders::kTaa
inlineconstexpr
初始值:
= R"wgsl(
fn taa_reprojection()->mat4x4f{return mat4x4f(
vec4f(p(7),p(8),p(9),p(10)),vec4f(p(11),p(12),p(13),p(14)),
vec4f(p(15),p(16),p(17),p(18)),vec4f(p(19),p(20),p(21),p(22)));}
@fragment fn fs_main(i:FSIn)->@location(0) vec4f{
let t=vec2f(p(0),p(1));let currentSample=tex(i.uv);let current=currentSample.rgb;let linearDepth=select(currentSample.a,motion_load(i.uv).r,p(26)>.5);if p(4)<.5{return vec4f(current*i.color.rgb,linearDepth);}
let currentY=hdr_ycocg(current);var lo=currentY;var hi=currentY;var sum=vec3f(0);var sumSq=vec3f(0);
for(var y=-1;y<=1;y++){for(var x=-1;x<=1;x++){let c=hdr_ycocg(tex(i.uv+vec2f(f32(x)*t.x,f32(y)*t.y)).rgb);lo=min(lo,c);hi=max(hi,c);sum+=c;sumSq+=c*c;}}
let mean=sum/9;let sigma=sqrt(max(sumSq/9-mean*mean,vec3f(0)));lo=max(lo,mean-sigma*1.25);hi=min(hi,mean+sigma*1.25);
var historyUV=i.uv+vec2f(p(5),p(6));
if p(25)>.5&&linearDepth>.00001&&linearDepth<.9999{let n=max(p(23),.0001);let f=max(p(24),n+.001);let vd=mix(n,f,linearDepth);let z=(f-n*f/max(vd,n))/(f-n);let pc=taa_reprojection()*vec4f(i.uv*2-1,z,1);if abs(pc.w)>.000001{historyUV=pc.xy/pc.w*.5+.5;}}
var objectMotion=vec2f(0);if p(26)>.5&&linearDepth>.00001&&linearDepth<.9999{var nearest=motion_load(i.uv);for(var my=-1;my<=1;my++){for(var mx=-1;mx<=1;mx++){let candidate=motion_load(i.uv+vec2f(f32(mx)*t.x,f32(my)*t.y));if candidate.r<nearest.r{nearest=candidate;}}}objectMotion=(nearest.gb-vec2f(.5))*2;historyUV+=objectMotion;}
let inBounds=all(historyUV>=vec2f(0))&&all(historyUV<=vec2f(1));let hs=aux_cubic(clamp(historyUV,vec2f(0),vec2f(1)));let history=hs.rgb;let historyY=hdr_ycocg(history);let clippedY=mix(historyY,clamp(historyY,lo,hi),clamp(p(3),0,1));let clipped=hdr_rgb(clippedY);
let encodedDelta=abs(currentY-clippedY);let delta=max(encodedDelta.x,max(encodedDelta.y,encodedDelta.z));let colorReject=smoothstep(.03,.15,delta);let dt=.006+linearDepth*.02;let depthReject=smoothstep(dt,dt*4,abs(linearDepth-hs.a));let velocityReactive=smoothstep(.002,.04,length(objectMotion));var surfaceReactive=0.0;if p(26)>.5&&linearDepth>.00001&&linearDepth<.9999{surfaceReactive=smoothstep(.01,.08,abs(linearDepth-motion_load(i.uv).r));}var reject=max(max(colorReject,depthReject),max(velocityReactive*.65,surfaceReactive));if !inBounds{reject=1;}
let currentWeight=mix(clamp(p(2),0,1),1.0,reject);
var resolved=mix(clipped,current,currentWeight);let crossAverage=(hdr_ycocg(tex(i.uv+vec2f(t.x,0)).rgb)+hdr_ycocg(tex(i.uv-vec2f(t.x,0)).rgb)+hdr_ycocg(tex(i.uv+vec2f(0,t.y)).rgb)+hdr_ycocg(tex(i.uv-vec2f(0,t.y)).rgb))*.25;let sharpenStrength=.12*(1-reject)*(1-velocityReactive);let sharpened=hdr_ycocg(resolved)+(currentY-crossAverage)*sharpenStrength;resolved=hdr_rgb(clamp(sharpened,lo,hi));
return vec4f(resolved*i.color.rgb,linearDepth);
}
)wgsl"

@lifetime Shader source has static storage for the process lifetime.

在文件 PostProcessWgsl.h 第 86 行定义.

◆ kTreeWindVertWgsl

constexpr const char* eve::graphics::shaders::kTreeWindVertWgsl
inlineconstexpr

Immutable WGSL source. @ownership Program image. @lifetime Entire process.

在文件 TreeWindWgsl.h 第 4 行定义.

被这些函数引用 eve::graphics::createTreeWindShader().

◆ kVolCloud

constexpr const char* eve::graphics::shaders::kVolCloud
inlineconstexpr
初始值:
=R"wgsl(
fn hash(q:vec2f)->f32{return fract(sin(dot(q,vec2f(12.9898,78.233)))*43758.5453);}
@fragment fn fs_main(i:FSIn)->@location(0)vec4f{let uv=i.uv+vec2f(p(25),p(26))*p(19)*.0002;let n=hash(floor(uv*max(p(24),1)));let cov=clamp(p(22),0,1);let density=max(p(23),0);let a=smoothstep(1-cov,1,n)*density*.7;let light=vec3f(p(29),p(30),p(31));return vec4f(light,a)*i.color;}
)wgsl"

在文件 VolumetricWgsl.h 第 21 行定义.

◆ kVolCommon

constexpr const char* eve::graphics::shaders::kVolCommon
inlineconstexpr
初始值:
=R"wgsl(
struct FSIn{@location(0) color:vec4f,@location(1) uv:vec2f};struct U{data:array<vec4f,8>};
@group(0) @binding(0)var mainTex:texture_2d<f32>;@group(0) @binding(1)var depthTex:texture_2d<f32>;@group(0) @binding(2)var samp:sampler;@group(0) @binding(4)var<uniform>u:U;
fn p(i:u32)->f32{return u.data[i/4u][i%4u];}fn tex(uv:vec2f)->vec4f{return textureSampleLevel(mainTex,samp,clamp(uv,vec2f(0),vec2f(1)),0);}
)wgsl"

在文件 VolumetricWgsl.h 第 4 行定义.

◆ kVolDirectionalCookie

constexpr char eve::graphics::shaders::kVolDirectionalCookie[]
inlineconstexpr
初始值:
=R"wgsl(
fn world(m:mat4x4f,uv:vec2f,z:f32)->vec3f{let h=m*vec4f(uv*2-1,z,1);return h.xyz/max(h.w,.000001);}
@fragment fn fs_main(i:FSIn)->@location(0)vec4f{let z=textureSampleLevel(depthTex,samp,i.uv,0).r;if z<=.00001||z>=.99999{return vec4f(0);}let m=mat4x4f(u.data[0],u.data[1],u.data[2],u.data[3]);let w=world(m,i.uv,z);let l=normalize(vec3f(p(18),p(19),p(20))+vec3f(.000001));let h=select(vec3f(1,0,0),vec3f(0,1,0),abs(l.y)<.99);let a=normalize(cross(h,l));let b=normalize(cross(l,a));let uv=fract(vec2f(dot(w,a),dot(w,b))/max(p(16),.001)+.5);let ra=1-abs(sin((uv.x+.28*sin(uv.y*12))*19));let rb=1-abs(sin((uv.y+.24*sin(uv.x*15))*23));let proc=.12+.88*pow(max(ra,rb),5);let c=max(tex(uv).rgb,vec3f(proc));let alpha=clamp(max(c.r,max(c.g,c.b))*max(p(17),0),0,1);return vec4f(c*i.color.rgb,alpha*i.color.a);}
)wgsl"

在文件 VolumetricWgsl.h 第 28 行定义.

◆ kVolFog

constexpr const char* eve::graphics::shaders::kVolFog
inlineconstexpr
初始值:
=R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0)vec4f{let z=tex(i.uv).r;if z>=.999{return vec4f(0);}let start=max(p(29),0);let end=max(p(30),start+.001);let dist=mix(max(p(24),.001),max(p(25),1),z);let range=smoothstep(start,end,dist);let height=mix(.65,1.0,clamp(i.uv.y,0,1));let a=clamp(range*max(p(19),0)*max(p(23),0)*height,0,.95);return vec4f(vec3f(p(20),p(21),p(22)),a)*i.color;}
)wgsl"

在文件 VolumetricWgsl.h 第 18 行定义.

◆ kVolFroxel

constexpr const char* eve::graphics::shaders::kVolFroxel
inlineconstexpr
初始值:
=R"wgsl(
@fragment fn fs_main(i:FSIn)->@location(0)vec4f{let cols=max(p(0),1);let rows=max(p(1),1);let slices=max(p(2),1);let tile=vec2f(1/cols,1/rows);var acc=vec4f(0);let count=i32(clamp(slices,1,64));for(var q=0;q<64;q++){if q>=count{break;}let f=f32(q);let cell=vec2f(f-floor(f/cols)*cols,floor(f/cols));let s=tex(cell*tile+i.uv*tile);acc.rgb+=s.rgb*(1-acc.a);acc.a+=s.a*(1-acc.a);}return acc*i.color;}
)wgsl"

在文件 VolumetricWgsl.h 第 25 行定义.

◆ kVolRay

constexpr const char* eve::graphics::shaders::kVolRay
inlineconstexpr
初始值:
=R"wgsl(
fn hg(c:f32,g:f32)->f32{let g2=g*g;return (1-g2)/(12.566*pow(max(1e-4,1+g2-2*g*c),1.5));}
@fragment fn fs_main(i:FSIn)->@location(0)vec4f{let z=tex(i.uv).r;if z>=.999{return vec4f(0);}let d=max(p(19),0);let c=vec3f(p(20),p(21),p(22));let light=normalize(vec3f(p(16),p(17),p(18)));let pack=p(29);var g=select(0.6,clamp(fract(pack)*1.98-0.99,-0.99,0.99),fract(pack)>1e-5);let phase=mix(hg(light.y,g*-0.5),hg(light.y,g),0.75);let a=clamp((1-z)*d*max(p(23),0)*(1+max(p(28),0))*phase*.55,0,.9);return vec4f(c*phase,a)*i.color;}
)wgsl"

在文件 VolumetricWgsl.h 第 14 行定义.

◆ kVolScreen

constexpr const char* eve::graphics::shaders::kVolScreen
inlineconstexpr
初始值:
=R"wgsl(
fn spotAtten(uv:vec2f,light:vec2f,beam:vec2f,cosO:f32,cosI:f32)->f32{if cosO<=-1.5{return 1.0;}let fromL=uv-light;let fl=length(fromL);if fl<=1e-4{return 1.0;}let bl=length(beam);if bl<=1e-6{return 0.0;}return smoothstep(cosO,cosI,dot(fromL/fl,beam/bl));}
@fragment fn fs_main(i:FSIn)->@location(0)vec4f{let light=vec2f(p(0),p(1));let count=i32(clamp(p(6),1,96));let delta=(i.uv-light)*p(4)/f32(count);var uv=i.uv;var illum=vec3f(0);var decay=1.0;
for(var q=0;q<96;q++){if q>=count{break;}uv-=delta;illum+=tex(uv).rgb*decay*p(5);decay*=p(3);}let fog=vec3f(p(9),p(10),p(11))*max(p(8),0);let shaft=vec3f(p(12),p(13),p(14));var rgb=(illum*shaft*p(2)+fog)*max(p(17),0);rgb*=spotAtten(i.uv,light,vec2f(p(18),p(19)),p(20),p(21));return vec4f(rgb,clamp(max(rgb.r,max(rgb.g,rgb.b)),0,1))*i.color;}
)wgsl"

在文件 VolumetricWgsl.h 第 9 行定义.

◆ kWaterfallFragWgsl

constexpr const char* eve::graphics::shaders::kWaterfallFragWgsl
inlineconstexpr

Waterfall fragment shader WGSL source. @ownership Borrowed immutable string literal; callers must not free it. @lifetime Static storage duration, valid for the entire process lifetime. @thread Safe for concurrent reads.

在文件 WaterfallWgsl.h 第 10 行定义.

被这些函数引用 eve::graphics::newWaterfallShader().

◆ kWaterFragWgsl

constexpr char eve::graphics::shaders::kWaterFragWgsl[]
inlineconstexpr
初始值:
= R"wgsl(
struct Light3D{posRadius:vec4f,color:vec4f,spot:vec4f};
struct Frame{mvp:mat4x4f,model:mat4x4f,lightDir:vec4f,lightColor:vec4f,tint:vec4f,cameraPos:vec4f,ambient:vec4f,lights:array<Light3D,8>,texBomb:vec4f,parallax:vec4f,surface:vec4f,view:mat4x4f,clipInfo:vec4f,cloud:vec4f,cloudWind:vec4f,envProbeCenter:vec4f,envProbeExtent:vec4f,skinInfo:vec4f,reflectionProbeCenter:array<vec4f,2>,reflectionProbeExtent:array<vec4f,2>};
struct FSIn{@builtin(position)pos:vec4f,@location(0)normal:vec3f,@location(1)uv:vec2f,@location(2)tint:vec4f,@location(3)worldPos:vec3f,@location(4)cameraPos:vec3f,@location(5)viewPos:vec3f};
struct Params{data:array<vec4f,8>};
@group(0)@binding(0)var<uniform>frame:Frame;@group(0)@binding(1)var sceneColorTex:texture_2d<f32>;@group(0)@binding(2)var depthRampTex:texture_2d<f32>;@group(0)@binding(3)var environment:texture_cube<f32>;@group(0)@binding(6)var ssrTex:texture_2d<f32>;@group(0)@binding(7)var samp:sampler;@group(0)@binding(9)var sceneDepthTex:texture_2d<f32>;@group(0)@binding(15)var<uniform>params:Params;@group(0)@binding(16)var reflectionProbe0:texture_cube<f32>;@group(0)@binding(17)var reflectionProbe1:texture_cube<f32>;
fn p(i:u32)->f32{return params.data[i/4u][i%4u];}fn hash(n:f32)->f32{return fract(sin(n)*43758.5453123);}fn hash2(i:i32)->vec2f{return vec2f(hash(f32(i)*7.31),hash(f32(i)*13.17+1.0));}fn waveDirection(value:vec2f)->vec2f{let angle=fract(p(5u))*12.5663706;let c=cos(angle);let s=sin(angle);return vec2f(c*value.x-s*value.y,s*value.x+c*value.y);}
fn shapedWave(phase:f32)->f32{let w=sin(phase);return sign(w)*pow(abs(w),max(p(31u),0.1));}
fn rippleRing(uv:vec2f,i:i32)->f32{let period=max(p(6u),0.05);let age=p(0u)-floor(p(0u)/period)*period-hash(f32(i)*3.7)*period;if(age<0.0||age>period*0.8){return 0.0;}let center=mix(vec2f(0.5),hash2(i),vec2f(0.72));let x=(length(uv-center)-age*0.22)/0.10;return p(4u)*exp(-(x*x)*0.9)*cos(x*6.2831853)*exp(-age*1.6);}
fn waterHeight(inputUv:vec2f)->f32{let uv=waveDirection(inputUv-vec2f(0.5))+vec2f(0.5);let scale=p(3u);let time=p(0u)*p(1u);let q=uv+vec2f(sin(uv.y*scale*0.31+time*0.37),sin(uv.x*scale*0.27-time*0.29))*0.018;let phase0=dot(q,vec2f(1.0,0.23))*scale*6.2831853+time*6.2831853;let phase1=dot(q,vec2f(-0.48,0.88))*scale*0.73*6.2831853-time*1.17*6.2831853;let phase2=dot(q,vec2f(0.37,0.93))*scale*1.31*6.2831853+time*0.61*6.2831853;var h=p(2u)*(shapedWave(phase0)*0.42+shapedWave(phase1)*0.34+shapedWave(phase2)*0.24);for(var i=0;i<8;i++){if(f32(i)>=p(5u)+0.5){break;}h+=rippleRing(q,i);}return h;}
fn caustics(pos:vec2f)->f32{let q=pos*max(p(30u),0.01);let t=p(0u)*p(1u);let a=sin(q.x*1.37+q.y*0.73+t*1.2);let b=sin(q.x*-0.62+q.y*1.51-t*0.93);let c=sin((q.x+q.y)*1.11+t*0.57);let ridge=1.0-abs((a+b+c)/3.0);return pow(clamp(ridge,0.0,1.0),5.0);}
fn foamCells(pos:vec2f)->f32{let cell=floor(pos);let f=fract(pos);var first=10.0;var second=10.0;for(var y=-1;y<=1;y++){for(var x=-1;x<=1;x++){let g=vec2f(f32(x),f32(y));let point=hash2(i32(cell.x+g.x)*131+i32(cell.y+g.y)*197);let distance=length(g+point-f);if(distance<first){second=first;first=distance;}else if(distance<second){second=distance;}}}return 1.0-smoothstep(0.025,0.18,second-first);}
fn flowNoise(pos:vec2f)->f32{let t=p(0u)*p(1u);let a=sin(pos.x*1.31+pos.y*0.73+t*1.17);let b=sin(pos.x*-0.67+pos.y*1.57-t*0.83);return 0.5+0.25*(a+b);}
fn crestLines(pos:vec2f)->f32{let t=p(0u)*p(1u);let scale=max(p(3u),0.01)*0.43;let phaseA=dot(pos,vec2f(0.96,0.28))*scale+sin(pos.y*0.72-t*0.31)*1.35+t*1.35;let phaseB=dot(pos,vec2f(-0.38,0.92))*scale*0.67+sin(pos.x*0.58+t*0.27)*1.15-t*0.82;let a=smoothstep(0.91,0.985,sin(phaseA));let b=smoothstep(0.935,0.992,sin(phaseB));let broken=smoothstep(0.52,0.70,flowNoise(pos*0.66+vec2f(4.7)));return max(a*0.58,b*0.38)*broken;}
fn probeWeight(i:u32,pos:vec3f)->f32{let edge=frame.reflectionProbeExtent[i].xyz-abs(pos-frame.reflectionProbeCenter[i].xyz);let inside=min(edge.x,min(edge.y,edge.z));return select(0.0,clamp(inside/max(frame.reflectionProbeExtent[i].w,0.0001),0.0,1.0),inside>0.0&&frame.reflectionProbeCenter[i].w>0.0);}
fn probeDirection(i:u32,direction:vec3f,pos:vec3f)->vec3f{let center=frame.reflectionProbeCenter[i].xyz;let extent=frame.reflectionProbeExtent[i].xyz;let safe=select(vec3f(0.00001),direction,abs(direction)>vec3f(0.00001));let exitT=max((center-extent-pos)/safe,(center+extent-pos)/safe);let distance=min(exitT.x,min(exitT.y,exitT.z));return select(normalize(direction),normalize(pos+direction*distance-center),distance>0.0);}
@fragment fn fs_main(in:FSIn)->@location(0)vec4f{
let eps=0.001;let grad=vec2f(waterHeight(in.uv+vec2f(eps,0))-waterHeight(in.uv-vec2f(eps,0)),waterHeight(in.uv+vec2f(0,eps))-waterHeight(in.uv-vec2f(0,eps)))/(2.0*eps);let flowTime=p(0u)*p(1u);let normalLayerA=vec2f(sin(in.worldPos.x*1.7+in.worldPos.z*0.8+flowTime),cos(in.worldPos.z*1.5-in.worldPos.x*0.6-flowTime*0.83));let normalLayerB=vec2f(cos(in.worldPos.x*3.1-in.worldPos.z*1.2-flowTime*1.31),sin(in.worldPos.z*2.7+in.worldPos.x*0.9+flowTime*0.57));let layeredNormal=grad*0.11+normalLayerA*0.055+normalLayerB*0.025;let normal=normalize(in.normal+vec3f(-layeredNormal.x,0,-layeredNormal.y));let view=normalize(frame.cameraPos.xyz-in.worldPos);let reflected=reflect(-view,normal);let ndv=max(dot(view,normal),0.0);
let size=vec2f(textureDimensions(sceneColorTex));let suv=in.pos.xy/max(size,vec2f(1));let nearZ=max(frame.clipInfo.x,0.0001);let farZ=max(frame.clipInfo.y,nearZ+0.001);let surface=clamp((-in.viewPos.z-nearZ)/(farZ-nearZ),0.0,1.0);let hasDepth=p(29u)>=0.0;let opacity=select(-p(29u)-1.0,p(29u),hasDepth);let sceneSample=textureSample(sceneColorTex,samp,suv);var scene=surface+1.0;if(hasDepth){scene=textureSample(sceneDepthTex,samp,suv).r;}if(sceneSample.a>surface+0.00001&&sceneSample.a<0.9999){scene=sceneSample.a;}let depth=max((scene-surface)*(farZ-nearZ),0.0);let depthDistance=max(abs(p(16u)),0.0001);let shallow=1.0-smoothstep(0.0,depthDistance,depth);let shallowColor=vec3f(p(13u),p(14u),p(15u));let water=select(mix(vec3f(p(10u),p(11u),p(12u)),shallowColor,vec3f(shallow)),textureSample(depthRampTex,samp,vec2f(clamp(depth/depthDistance,0.0,1.0),0.5)).rgb,p(16u)<0.0);
let flow=vec2f(flowNoise(in.worldPos.xz*1.8),flowNoise(in.worldPos.zx*2.3+vec2f(17.0)))-vec2f(0.5);let ruv=clamp(suv+(layeredNormal*0.75+flow*0.35)*p(28u)*(0.25+shallow*0.75),vec2f(0.001),vec2f(0.999));let behind=textureSample(sceneColorTex,samp,ruv).rgb;let absorption=select(1.0,1.0-exp(-depth/max(abs(p(16u)),0.001)*3.2),hasDepth);var waterAlpha=clamp(opacity*mix(0.35,1.0,absorption),0.0,1.0);var color=water;let causticMask=select(0.0,smoothstep(0.02,max(abs(p(16u)),0.03),depth)*shallow,hasDepth);color+=shallowColor*caustics(in.worldPos.xz)*causticMask*p(26u);
let rough=clamp(0.08+length(layeredNormal)*0.35,0.05,0.34);let envLod=rough*f32(max(i32(textureNumLevels(environment))-2,0));var w0=probeWeight(0u,in.worldPos);var w1=probeWeight(1u,in.worldPos);var sum=w0+w1;if(sum>1.0){w0/=sum;w1/=sum;sum=1.0;}var reflection=textureSampleLevel(environment,samp,reflected,envLod).rgb*frame.lightColor.w*(1.0-sum);if(w0>0.0){reflection+=textureSampleLevel(reflectionProbe0,samp,probeDirection(0u,reflected,in.worldPos),rough*4.0).rgb*frame.reflectionProbeCenter[0].w*w0;}if(w1>0.0){reflection+=textureSampleLevel(reflectionProbe1,samp,probeDirection(1u,reflected,in.worldPos),rough*4.0).rgb*frame.reflectionProbeCenter[1].w*w1;}reflection*=vec3f(p(21u),p(22u),p(23u));let fresnel=pow(1.0-ndv,max(p(25u),0.01));waterAlpha=max(waterAlpha,opacity*mix(0.35,1.0,fresnel));let reflectionWeight=clamp((0.08+0.92*fresnel)*p(20u),0.0,0.78);color=mix(color,reflection,vec3f(reflectionWeight));
let light=normalize(frame.lightDir.xyz);let glint=pow(max(dot(normal,normalize(view+light)),0.0),mix(24.0,160.0,1.0-rough));color+=frame.lightColor.rgb*glint*max(dot(normal,light),0.0)*p(24u);
let foamUv=in.worldPos.xz*0.80;let cells=foamCells(foamUv+vec2f(p(0u)*0.08,-p(0u)*0.05));let cells2=foamCells(foamUv*0.61+vec2f(-p(0u)*0.04,p(0u)*0.06));let curvedLines=smoothstep(0.72,0.96,max(cells,cells2*0.72));let crest=smoothstep(p(2u)*0.34,p(2u)*0.80,waterHeight(in.uv));let surfaceTint=mix(shallowColor,vec3f(p(17u),p(18u),p(19u)),vec3f(0.28));let surfacePattern=curvedLines*(0.07+crest*0.11)*p(9u);color=mix(color,surfaceTint,vec3f(surfacePattern));waterAlpha=max(waterAlpha,surfacePattern*0.42);
let normalizedDepth=clamp(depth/max(p(7u),0.0001),0.0,1.0);let edge=1.0-smoothstep(max(p(7u)-p(8u),0.0),p(7u)+p(8u),depth);let bandCoord=normalizedDepth*3.4+flowNoise(foamUv*2.1)*0.34;let shoreBands=(1.0-smoothstep(0.035,0.12,abs(fract(bandCoord)-0.5)))*(1.0-normalizedDepth);let shoreFoam=max(edge*(0.52+0.48*cells),shoreBands*0.82)*p(9u);color=mix(color,vec3f(p(17u),p(18u),p(19u)),vec3f(clamp(shoreFoam,0.0,1.0)));waterAlpha=max(waterAlpha,clamp(shoreFoam,0.0,1.0));
if(p(27u)>0.0){let externalReflection=textureSample(ssrTex,samp,suv);let externalWeight=clamp(externalReflection.a*p(27u),0.0,1.0);color=mix(color,externalReflection.rgb,vec3f(externalWeight));waterAlpha=max(waterAlpha,externalWeight);}
waterAlpha=max(waterAlpha,reflectionWeight*0.72);let transmission=(1.0-waterAlpha)*0.38;color=mix(color,behind,vec3f(transmission));return vec4f(color*in.tint.rgb,waterAlpha);
}
)wgsl"

Backend-parity stylized-water WGSL source with depth foam and scene-color refraction.

在文件 WaterWgsl.h 第 36 行定义.

被这些函数引用 eve::graphics::newWaterShader().

◆ kWaterVertWgsl

constexpr char eve::graphics::shaders::kWaterVertWgsl[]
inlineconstexpr
初始值:
= R"wgsl(
struct Light3D{posRadius:vec4f,color:vec4f,spot:vec4f};
struct Frame{mvp:mat4x4f,model:mat4x4f,lightDir:vec4f,lightColor:vec4f,tint:vec4f,cameraPos:vec4f,ambient:vec4f,lights:array<Light3D,8>,texBomb:vec4f,parallax:vec4f,surface:vec4f,view:mat4x4f,clipInfo:vec4f,cloud:vec4f,cloudWind:vec4f,envProbeCenter:vec4f,envProbeExtent:vec4f,skinInfo:vec4f,reflectionProbeCenter:array<vec4f,2>,reflectionProbeExtent:array<vec4f,2>};
struct Params{data:array<vec4f,8>};
struct VSIn{@location(0)pos:vec3f,@location(1)normal:vec3f,@location(2)uv:vec2f};
struct VSOut{@builtin(position)pos:vec4f,@location(0)normal:vec3f,@location(1)uv:vec2f,@location(2)tint:vec4f,@location(3)worldPos:vec3f,@location(4)cameraPos:vec3f,@location(5)viewPos:vec3f};
@group(0)@binding(0)var<uniform>frame:Frame;
@group(0)@binding(15)var<uniform>params:Params;
fn p(i:u32)->f32{return params.data[i/4u][i%4u];}
fn waveDirection(value:vec2f)->vec2f{let angle=fract(p(5u))*12.5663706;let c=cos(angle);let s=sin(angle);return vec2f(c*value.x-s*value.y,s*value.x+c*value.y);}
fn waveHeight(inputXZ:vec2f)->f32{
let worldXZ=waveDirection(inputXZ);
let scale=max(p(3u),0.01)*0.72;let time=p(0u)*p(1u);
let primary=sin(dot(worldXZ,vec2f(0.91,0.31))*scale+time*1.45);
let crossWave=sin(dot(worldXZ,vec2f(-0.36,0.93))*scale*0.58-time*0.92);
let swell=sin(dot(worldXZ,vec2f(0.22,0.98))*scale*0.24+time*0.37);
return p(2u)*(primary*0.48+crossWave*0.34+swell*0.18);
}
@vertex fn vs_main(in:VSIn)->VSOut{
let baseWorld=frame.model*vec4f(in.pos,1.0);let eps=0.025;let height=waveHeight(baseWorld.xz);
let dx=(waveHeight(baseWorld.xz+vec2f(eps,0))-waveHeight(baseWorld.xz-vec2f(eps,0)))/(2.0*eps);
let dz=(waveHeight(baseWorld.xz+vec2f(0,eps))-waveHeight(baseWorld.xz-vec2f(0,eps)))/(2.0*eps);
let localPos=in.pos+vec3f(0,height,0);let world=frame.model*vec4f(localPos,1.0);
var out:VSOut;out.pos=frame.mvp*vec4f(localPos,1.0);out.pos.y=-out.pos.y;
out.normal=normalize(mat3x3f(frame.model[0].xyz,frame.model[1].xyz,frame.model[2].xyz)*normalize(vec3f(-dx,1,-dz)));
out.uv=in.uv;out.tint=frame.tint;out.worldPos=world.xyz;out.cameraPos=frame.cameraPos.xyz;out.viewPos=(frame.view*world).xyz;return out;
}
)wgsl"

Vertex-displaced low-frequency water layers for the WebGPU backend.

在文件 WaterWgsl.h 第 6 行定义.

被这些函数引用 eve::graphics::newWaterShader().