#version 450 layout(local_size_x=16,local_size_y=16) in; layout(binding=0,rgba8) uniform writeonly image2D outputImage; layout(binding=1) uniform sampler2D panorama; layout(push_constant) uniform Params { vec4 rotation; vec4 originRadius; vec4 tans; vec4 rect; vec4 anglesEye; vec4 scaleBias; vec4 colorScale; vec4 colorBias; } p; vec3 rotate(vec4 q,vec3 v) {return v+2.0*cross(q.xyz,cross(q.xyz,v)+q.w*v);} void main() { ivec2 size=imageSize(outputImage),pixel=ivec2(gl_GlobalInvocationID.xy); int eye=int(p.anglesEye.w),width=size.x/2; if(pixel.x>=width || pixel.y>=size.y)return; vec2 uv=(vec2(pixel)+0.5)/vec2(width,size.y); vec3 d=normalize(rotate(p.rotation,vec3(mix(p.tans.x,p.tans.y,uv.x),mix(p.tans.w,p.tans.z,uv.y),-1.0))); if(p.originRadius.w>0.0) { vec3 o=p.originRadius.xyz; float b=dot(o,d),disc=b*b+p.originRadius.w*p.originRadius.w-dot(o,o); if(disc<0.0){imageStore(outputImage,pixel+ivec2(eye*width,0),vec4(0));return;} float distance=-b+sqrt(disc); if(distance<=0.0){imageStore(outputImage,pixel+ivec2(eye*width,0),vec4(0));return;} d=normalize(o+distance*d); } float lon=atan(d.x,-d.z),lat=asin(clamp(d.y,-1.0,1.0)); vec2 eq; if(p.anglesEye.x>0.0) eq=vec2(lon/p.anglesEye.x+0.5,(lat-p.anglesEye.z)/(p.anglesEye.y-p.anglesEye.z)); else eq=vec2(lon/6.28318530718+0.5,lat/3.14159265359+0.5)*p.scaleBias.xy+p.scaleBias.zw; vec4 color=vec4(0); if(all(greaterThanEqual(eq,vec2(0))) && all(lessThanEqual(eq,vec2(1)))) color=clamp(textureLod(panorama,p.rect.xy+vec2(eq.x,1.0-eq.y)*p.rect.zw,0.0)*p.colorScale+p.colorBias,0.0,1.0); imageStore(outputImage,pixel+ivec2(eye*width,0),color); }