UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

170 lines (129 loc) 6.9 kB
import { GLSL3, ShaderMaterial, Vector2 } from "three"; export function makeQueryShader() { return new ShaderMaterial({ vertexShader: ` void main() { gl_Position = vec4( position, 1.0 ); } `, fragmentShader: ` uniform sampler2D utDepth; uniform sampler2D utInput; uniform vec2 uDepthMipLimits; out highp vec4 out_value; vec3 read_input_v3(ivec2 start){ float x = texelFetch(utInput, start, 0).x; float y = texelFetch(utInput, start + ivec2(1,0), 0).x; float z = texelFetch(utInput, start + ivec2(2,0), 0).x; return vec3(x,y,z); } vec4 read_input_v4(ivec2 start){ return vec4( read_input_v3(start), texelFetch(utInput, start + ivec2(3,0) , 0).x ); } mat4 read_input_m4(ivec2 start){ return mat4( read_input_v4(start), read_input_v4(start + ivec2(4,0)), read_input_v4(start + ivec2(8,0)), read_input_v4(start + ivec2(12,0)) ); } vec3 project_vec3(vec3 value, mat4 transform){ vec4 v1 = transform * vec4( value, 1.0 ); v1.xyz /= abs(v1.w); return v1.xyz; } void project_aabb(out vec3 pb_min, out vec3 pb_max, in vec3 bb_min, in vec3 bb_max, in mat4 transform){ vec3 p0 = project_vec3( bb_min, transform ); vec3 p1 = project_vec3( vec3(bb_min.xy, bb_max.z), transform ); pb_min = min( p0, p1 ); pb_max = max( p0, p1 ); vec3 p2 = project_vec3( vec3(bb_min.x, bb_max.y, bb_min.z), transform ); pb_min = min( pb_min, p2 ); pb_max = max( pb_max, p2 ); vec3 p3 = project_vec3( vec3( bb_min.x, bb_max.y, bb_max.z ), transform ); pb_min = min( pb_min, p3 ); pb_max = max( pb_max, p3 ); vec3 p4 = project_vec3( vec3( bb_max.x, bb_min.y, bb_min.z), transform ); pb_min = min( pb_min, p4 ); pb_max = max( pb_max, p4 ); vec3 p5 = project_vec3( vec3( bb_max.x, bb_min.y, bb_max.z ), transform ); pb_min = min( pb_min, p5 ); pb_max = max( pb_max, p5 ); vec3 p6 = project_vec3( vec3( bb_max.x, bb_max.y, bb_min.z ), transform ); pb_min = min( pb_min, p6 ); pb_max = max( pb_max, p6 ); vec3 p7 = project_vec3( vec3( bb_max.x, bb_max.y, bb_max.z ), transform ); pb_min = min( pb_min, p7 ); pb_max = max( pb_max, p7 ); } int compute_mip_level_for_dimension(float mip_limit, float ndc_extents){ return max(0, int( floor( mip_limit - log2( 1.0 / ndc_extents) ) ) ); } float query_depth_from_screen_space_bb(in vec3 pb_min, in vec3 pb_max){ vec3 n_min = clamp( (pb_min+1.0)*0.5, 0.0, 1.0); vec3 n_max = clamp( (pb_max+1.0)*0.5, 0.0, 1.0); float bb_width = ( n_max.x - n_min.x ) * 0.5; float bb_height = ( n_max.y - n_min.y ) * 0.5 ; // pick coarsest z-buffer mip to test 4x4 pixels of the bounding box against int mip_level_x = compute_mip_level_for_dimension( uDepthMipLimits.x, bb_width ); int mip_level_y = compute_mip_level_for_dimension( uDepthMipLimits.y, bb_height ); // figure out which mip level to use int mip_to_use = max(mip_level_x, mip_level_y); // sample 4 pixels that cover AABB float n0 = textureLod(utDepth, n_min.xy, float(mip_to_use)).x; float n1 = textureLod(utDepth, vec2(n_min.x, n_max.y), float(mip_to_use)).x; float n2 = textureLod(utDepth, vec2(n_max.y, n_min.y), float(mip_to_use)).x; float n3 = textureLod(utDepth, n_max.xy, float(mip_to_use)).x; float n = max(n0, max(n1, max(n2,n3))); float depth_delta = n - n_min.z; return depth_delta; // return float( uDepthMipLimits.x ); // return float( depth_delta*255.0 ); } uint query_bounds(vec3 bb_min, vec3 bb_max, mat4 transform){ vec3 pb_min; vec3 pb_max; // project bounds to screen space project_aabb(pb_min, pb_max, bb_min, bb_max, transform); if( pb_max.x < -1.0 || pb_max.y < -1.0 || pb_max.z < -1.0 || pb_min.x > 1.0 || pb_min.y > 1.0 || pb_min.z > 1.0 ){ // outside of view frustum return 0u; } float n = query_depth_from_screen_space_bb( pb_min, pb_max ); if(n < 0.0){ return 0u; }else{ return 255u; } } void main() { ivec2 input_offset = ivec2( int(gl_FragCoord.x) * ITEM_SIZE, int(gl_FragCoord.y) ); vec3 bb_min = read_input_v3(input_offset); vec3 bb_max = read_input_v3(input_offset + ivec2(3,0)); mat4 transform = read_input_m4(input_offset + ivec2(6,0)); out_value = vec4( float( query_bounds(bb_min, bb_max, transform) ) / 255.0, 0.0, 0.0, 1.0 ); } `, depthTest: false, depthWrite: false, uniforms: { utDepth: { value: null }, utInput: { value: null }, uDepthMipLimits: { value: new Vector2(1, 1) } }, glslVersion: GLSL3 }); }