diff --git a/WGLMakie/assets/mesh.frag b/WGLMakie/assets/mesh.frag index efe137428e3..7c70d3ec146 100644 --- a/WGLMakie/assets/mesh.frag +++ b/WGLMakie/assets/mesh.frag @@ -4,6 +4,7 @@ flat in int sample_frag_color; in vec3 o_normal; in vec3 o_camdir; +in float o_clip_distance[8]; // Smoothes out edge around 0 light intensity, see GLMakie float smooth_zero_max(float x) { @@ -107,7 +108,12 @@ vec4 pack_int(uint id, uint index) { return unpack; } -void main() { +void main() +{ + for (int i = 0; i < 8; i++) + if (o_clip_distance[i] < 0.0) + discard; + vec4 real_color = get_color(uniform_color, frag_uv, get_colorrange(), colormap); vec3 shaded_color = real_color.rgb; diff --git a/WGLMakie/assets/mesh.vert b/WGLMakie/assets/mesh.vert index 14341fbe452..37b36257bfd 100644 --- a/WGLMakie/assets/mesh.vert +++ b/WGLMakie/assets/mesh.vert @@ -3,10 +3,12 @@ out vec3 o_normal; out vec3 o_camdir; out vec4 frag_color; +out float o_clip_distance[8]; uniform mat4 projection; uniform mat4 view; uniform vec3 eyeposition; +uniform vec4 clip_planes[8]; vec3 tovec3(vec2 v){return vec3(v, 0.0);} vec3 tovec3(vec3 v){return v;} @@ -61,11 +63,17 @@ vec4 vertex_color(float value, vec2 colorrange, sampler2D colormap){ } } +void process_clip_planes(vec3 world_pos) { + for (int i = 0; i < 8; i++) + o_clip_distance[i] = dot(world_pos, clip_planes[i].xyz) - clip_planes[i].w; +} + void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection) { // normal in world space o_normal = get_normalmatrix() * normal; // position in clip space (w/ depth) + process_clip_planes(position_world.xyz); gl_Position = projection * view * position_world; // TODO consider using projectionview directly gl_Position.z += gl_Position.w * get_depth_shift(); // direction to camera diff --git a/WGLMakie/assets/particles.frag b/WGLMakie/assets/particles.frag index 262a1fd9538..062de977cf3 100644 --- a/WGLMakie/assets/particles.frag +++ b/WGLMakie/assets/particles.frag @@ -2,6 +2,7 @@ in vec4 frag_color; in vec3 frag_normal; in vec3 frag_position; in vec3 o_camdir; +in float o_clip_distance[8]; // Smoothes out edge around 0 light intensity, see GLMakie float smooth_zero_max(float x) { @@ -43,6 +44,10 @@ vec4 pack_int(uint id, uint index) { } void main() { + for (int i = 0; i < 8; i++) + if (o_clip_distance[i] < 0.0) + discard; + vec3 L, N, light, color; if (get_shading()) { L = get_light_direction(); diff --git a/WGLMakie/assets/particles.vert b/WGLMakie/assets/particles.vert index 495c475579d..99c3bf9e395 100644 --- a/WGLMakie/assets/particles.vert +++ b/WGLMakie/assets/particles.vert @@ -3,11 +3,13 @@ precision mediump float; uniform mat4 projection; uniform mat4 view; uniform vec3 eyeposition; +uniform vec4 clip_planes[8]; out vec3 frag_normal; out vec3 frag_position; out vec4 frag_color; out vec3 o_camdir; +out float o_clip_distance[8]; vec3 qmul(vec4 q, vec3 v){ return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); @@ -24,6 +26,11 @@ vec4 to_vec4(vec4 v4){return v4;} vec3 to_vec3(vec2 v3){return vec3(v3, 0.0);} vec3 to_vec3(vec3 v4){return v4;} +void process_clip_planes(vec3 world_pos) { + for (int i = 0; i < 8; i++) + o_clip_distance[i] = dot(world_pos, clip_planes[i].xyz) - clip_planes[i].w; +} + flat out uint frag_instance_id; void main(){ @@ -34,6 +41,7 @@ void main(){ rotate(get_rotation(), vertex_position, N); vertex_position = to_vec3(get_offset()) + vertex_position; vec4 position_world = model * vec4(vertex_position, 1); + process_clip_planes(position_world.xyz); frag_normal = N; frag_color = to_vec4(get_color()); // direction to camera diff --git a/WGLMakie/assets/sprites.frag b/WGLMakie/assets/sprites.frag index 468b75366ff..37358af6cb2 100644 --- a/WGLMakie/assets/sprites.frag +++ b/WGLMakie/assets/sprites.frag @@ -17,6 +17,7 @@ in float frag_uvscale; in float frag_distancefield_scale; in vec4 frag_uv_offset_width; flat in uint frag_instance_id; +in float o_clip_distance[8]; // These versions of aastep assume that `dist` is a signed distance function // which has been scaled to be in units of pixels. @@ -103,6 +104,10 @@ vec4 pack_int(uint id, uint index) { } void main() { + for (int i = 0; i < 8; i++) + if (o_clip_distance[i] < 0.0) + discard; + float signed_distance = 0.0; vec4 uv_off = frag_uv_offset_width; diff --git a/WGLMakie/assets/sprites.vert b/WGLMakie/assets/sprites.vert index 6b2e162eb72..c9971439404 100644 --- a/WGLMakie/assets/sprites.vert +++ b/WGLMakie/assets/sprites.vert @@ -1,5 +1,6 @@ uniform mat4 projection; uniform mat4 view; +uniform vec4 clip_planes[8]; uniform float atlas_tex_dim; @@ -8,6 +9,7 @@ out vec2 frag_uv; out float frag_uvscale; out float frag_distancefield_scale; out vec4 frag_uv_offset_width; +out float o_clip_distance[8]; flat out uint frag_instance_id; @@ -58,6 +60,11 @@ float _determinant(mat2 m) { return m[0][0] * m[1][1] - m[0][1] * m[1][0]; } +void process_clip_planes(vec3 world_pos) { + for (int i = 0; i < 8; i++) + o_clip_distance[i] = dot(world_pos, clip_planes[i].xyz) - clip_planes[i].w; +} + void main(){ // get_pos() returns the position of the scatter marker // get_position() returns the (relative) position of the current quad vertex @@ -68,9 +75,12 @@ void main(){ mat4 pview = projection * view; mat4 trans = get_transform_marker() ? model : mat4(1.0); + vec4 position_world = model * vec4(tovec3(get_pos()), 1); + process_clip_planes(position_world.xyz); + // Compute centre of billboard in clipping coordinates // Always transform text/scatter position argument - vec4 data_point = get_preprojection() * model * vec4(tovec3(get_pos()), 1); + vec4 data_point = get_preprojection() * position_world; // maybe transform marker_offset + glyph offsets data_point = vec4(data_point.xyz / data_point.w + mat3(trans) * tovec3(get_marker_offset()), 1); data_point = pview * data_point; diff --git a/WGLMakie/assets/volume.frag b/WGLMakie/assets/volume.frag index d3048f8afee..c16adc24465 100644 --- a/WGLMakie/assets/volume.frag +++ b/WGLMakie/assets/volume.frag @@ -2,6 +2,7 @@ struct Nothing{ //Nothing type, to encode if some variable doesn't contain any d bool _; //empty structs are not allowed }; in vec3 frag_vert; +in float o_clip_distance[8]; const float max_distance = 1.3; @@ -227,6 +228,10 @@ vec4 pack_int(uint id, uint index) { void main() { + for (int i = 0; i < 8; i++) + if (o_clip_distance[i] < 0.0) + discard; + vec4 color; vec3 eye_unit = vec3(modelinv * vec4(eyeposition, 1)); vec3 back_position = frag_vert; diff --git a/WGLMakie/assets/volume.vert b/WGLMakie/assets/volume.vert index c9d00be85b8..4a334c3c843 100644 --- a/WGLMakie/assets/volume.vert +++ b/WGLMakie/assets/volume.vert @@ -1,11 +1,19 @@ out vec3 frag_vert; +out float o_clip_distance[8]; uniform mat4 projection, view; +uniform vec4 clip_planes[8]; + +void process_clip_planes(vec3 world_pos) { + for (int i = 0; i < 8; i++) + o_clip_distance[i] = dot(world_pos, clip_planes[i].xyz) - clip_planes[i].w; +} void main() { frag_vert = position; vec4 world_vert = model * vec4(position, 1); + process_clip_planes(world_vert.xyz); gl_Position = projection * view * world_vert; gl_Position.z += gl_Position.w * get_depth_shift(); } diff --git a/WGLMakie/assets/voxel.frag b/WGLMakie/assets/voxel.frag index 3b2c4fead11..38ecf4c3dec 100644 --- a/WGLMakie/assets/voxel.frag +++ b/WGLMakie/assets/voxel.frag @@ -5,6 +5,7 @@ flat in vec3 o_normal; in vec3 o_uvw; flat in int o_side; in vec2 o_tex_uv; +in float o_clip_distance[8]; in vec3 o_camdir; @@ -90,6 +91,10 @@ vec4 pack_int(uint id, uint index) { } void main() { + for (int i = 0; i < 8; i++) + if (o_clip_distance[i] < 0.0) + discard; + vec2 voxel_uv = mod(o_tex_uv, 1.0); if (voxel_uv.x < 0.5 * gap || voxel_uv.x > 1.0 - 0.5 * gap || voxel_uv.y < 0.5 * gap || voxel_uv.y > 1.0 - 0.5 * gap) diff --git a/WGLMakie/assets/voxel.vert b/WGLMakie/assets/voxel.vert index 68ae1fd6318..6e89943f596 100644 --- a/WGLMakie/assets/voxel.vert +++ b/WGLMakie/assets/voxel.vert @@ -5,6 +5,7 @@ flat out vec3 o_normal; out vec3 o_uvw; flat out int o_side; out vec2 o_tex_uv; +out float o_clip_distance[8]; #ifdef DEBUG_RENDER_ORDER flat out float plane_render_idx; @@ -15,6 +16,12 @@ flat out int plane_front; out vec3 o_camdir; uniform mat4 projection, view; +uniform vec4 clip_planes[8]; + +void process_clip_planes(vec3 world_pos) { + for (int i = 0; i < 8; i++) + o_clip_distance[i] = dot(world_pos, clip_planes[i].xyz) - clip_planes[i].w; +} const vec3 unit_vecs[3] = vec3[]( vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1) ); const mat2x3 orientations[3] = mat2x3[]( @@ -136,6 +143,7 @@ void main() { // place plane vertices vec3 plane_vertex = vec3(size) * (orientations[dim] * get_position()) + displacement; vec4 world_pos = get_model() * vec4(plane_vertex, 1.0f); + process_clip_planes(world_pos.xyz); gl_Position = projection * view * world_pos; gl_Position.z += gl_Position.w * get_depth_shift(); diff --git a/WGLMakie/src/Lines.js b/WGLMakie/src/Lines.js index 03850e5701a..522181c2b80 100644 --- a/WGLMakie/src/Lines.js +++ b/WGLMakie/src/Lines.js @@ -44,11 +44,11 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { ${attribute_decl} - out vec3 f_quad_sdf; out vec2 f_truncation; // invalid / not needed out float f_linestart; // constant out float f_linelength; + out float o_clip_distance[8]; flat out vec2 f_extrusion; // invalid / not needed flat out float f_linewidth; @@ -63,6 +63,7 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { flat out vec4 f_miter_vecs; // invalid / not needed ${uniform_decl} + uniform vec4 clip_planes[8]; // Constants const float AA_RADIUS = 0.8; @@ -73,6 +74,9 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Geometry/Position Utils //////////////////////////////////////////////////////////////////////// + vec4 world_space(vec3 point) { return model * vec4(point, 1); } + vec4 world_space(vec2 point) { return world_space(vec3(point, 0)); } + vec4 clip_space(vec3 point) { return projectionview * model * vec4(point, 1); } @@ -93,6 +97,10 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Main //////////////////////////////////////////////////////////////////////// + void process_clip_planes(vec3 world_pos) { + for (int i = 0; i < 8; i++) + o_clip_distance[i] = dot(world_pos, clip_planes[i].xyz) - clip_planes[i].w; + } void main() { bool is_end = position.x == 1.0; @@ -158,6 +166,8 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Varying vertex data //////////////////////////////////////////////////////////////////// + vec4 world_pos = world_space(is_end ? linepoint_end : linepoint_start); + process_clip_planes(world_pos.xyz); // linecaps f_capmode = ivec2(linecap); @@ -207,6 +217,7 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { out vec2 f_truncation; out float f_linestart; out float f_linelength; + out float o_clip_distance[8]; flat out vec2 f_extrusion; flat out float f_linewidth; @@ -221,6 +232,7 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { flat out vec4 f_miter_vecs; ${uniform_decl} + uniform vec4 clip_planes[8]; // Constants const float AA_RADIUS = 0.8; @@ -319,6 +331,9 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Geometry/Position Utils //////////////////////////////////////////////////////////////////////// + vec4 world_space(vec3 point) { return model * vec4(point, 1); } + vec4 world_space(vec2 point) { return world_space(vec3(point, 0)); } + vec4 clip_space(vec3 point) { return projectionview * model * vec4(point, 1); } @@ -340,6 +355,11 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Main //////////////////////////////////////////////////////////////////////// + void process_clip_planes(vec3 world_pos) { + for (int i = 0; i < 8; i++) + o_clip_distance[i] = dot(world_pos, clip_planes[i].xyz) - clip_planes[i].w; + } + void main() { bool is_end = position.x == 1.0; @@ -573,7 +593,9 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { //////////////////////////////////////////////////////////////////// // Varying vertex data //////////////////////////////////////////////////////////////////// - + + vec4 world_pos = world_space(is_end ? linepoint_end : linepoint_start); + process_clip_planes(world_pos.xyz); vec3 offset; int x = int(is_end); @@ -664,6 +686,7 @@ function lines_fragment_shader(uniforms, attributes) { in vec2 f_truncation; in float f_linestart; in float f_linelength; + in float o_clip_distance[8]; flat in float f_linewidth; flat in vec4 f_pattern_overwrite; @@ -787,6 +810,10 @@ function lines_fragment_shader(uniforms, attributes) { void main(){ + for (int i = 0; i < 8; i++) + if (o_clip_distance[i] < 0.0) + discard; + vec4 color; // f_quad_sdf.x is the distance from p1, negative in v1 direction. diff --git a/WGLMakie/src/Serialization.js b/WGLMakie/src/Serialization.js index c8834120ae0..246db53e217 100644 --- a/WGLMakie/src/Serialization.js +++ b/WGLMakie/src/Serialization.js @@ -453,7 +453,7 @@ function create_material(scene, program) { transparent: true, glslVersion: THREE.GLSL3, depthTest: !program.overdraw.value, - depthWrite: !program.transparency.value, + depthWrite: !program.transparency.value }); } diff --git a/WGLMakie/src/Shaders.js b/WGLMakie/src/Shaders.js index 4d6959673e9..764694a1b99 100644 --- a/WGLMakie/src/Shaders.js +++ b/WGLMakie/src/Shaders.js @@ -42,7 +42,7 @@ export function uniform_type(obj) { } else if (obj instanceof THREE.Texture) { return "sampler2D"; } else { - return; + return "invalid"; } } @@ -51,7 +51,8 @@ export function uniforms_to_type_declaration(uniform_dict) { for (const name in uniform_dict) { const uniform = uniform_dict[name]; const type = uniform_type(uniform); - result += `uniform ${type} ${name};\n`; + if (type != "invalid") + result += `uniform ${type} ${name};\n`; } return result; } diff --git a/WGLMakie/src/lines.jl b/WGLMakie/src/lines.jl index f30d88a9a43..f8545bb80cd 100644 --- a/WGLMakie/src/lines.jl +++ b/WGLMakie/src/lines.jl @@ -133,6 +133,23 @@ function serialize_three(scene::Scene, plot::Union{Lines, LineSegments}) end end + # Handle clip planes + uniforms[:clip_planes] = map(plot, plot.clip_planes) do planes + if length(planes) > 8 + @warn("Only up to 8 clip planes are supported. The rest are ignored!", maxlog = 1) + end + + output = Vector{Vec4f}(undef, 8) + for i in 1:min(length(planes), 8) + output[i] = Makie.gl_plane_format(planes[i]) + end + for i in min(length(planes), 8)+1:8 + output[i] = Vec4f(0, 0, 0, -1e10) + end + + return output + end + attr = Dict( :name => string(Makie.plotkey(plot)) * "-" * string(objectid(plot)), :visible => plot.visible, diff --git a/WGLMakie/src/particles.jl b/WGLMakie/src/particles.jl index 535105ee82d..6514287c197 100644 --- a/WGLMakie/src/particles.jl +++ b/WGLMakie/src/particles.jl @@ -40,7 +40,7 @@ const IGNORE_KEYS = Set([ :visible, :transformation, :alpha, :linewidth, :transparency, :marker, :light_direction, :light_color, :cycle, :label, :inspector_clear, :inspector_hover, - :inspector_label, :axis_cyclerr, :dim_conversions, :material + :inspector_label, :axis_cyclerr, :dim_conversions, :material, :clip_planes # TODO add model here since we generally need to apply patch_model? ]) diff --git a/WGLMakie/src/serialization.jl b/WGLMakie/src/serialization.jl index 3769e3b1f53..4f4e92e444d 100644 --- a/WGLMakie/src/serialization.jl +++ b/WGLMakie/src/serialization.jl @@ -330,6 +330,7 @@ function serialize_plots(scene::Scene, @nospecialize(plots::Vector{T}), result=[ return result end +# TODO: lines overwrites this function serialize_three(scene::Scene, @nospecialize(plot::AbstractPlot)) program = create_shader(scene, plot) mesh = serialize_three(plot, program) @@ -368,6 +369,28 @@ function serialize_three(scene::Scene, @nospecialize(plot::AbstractPlot)) key = haskey(plot, :markerspace) ? (:markerspace) : (:space) mesh[:cam_space] = to_value(get(plot, key, :data)) + # Handle clip planes + clip_planes = map(plot, plot.clip_planes) do planes + if length(planes) > 8 + @warn("Only up to 8 clip planes are supported. The rest are ignored!", maxlog = 1) + end + + output = Vector{Vec4f}(undef, 8) + for i in 1:min(length(planes), 8) + output[i] = Makie.gl_plane_format(planes[i]) + end + for i in min(length(planes), 8)+1:8 + output[i] = Vec4f(0, 0, 0, -1e10) + end + + return output + end + uniforms[:clip_planes] = serialize_three(clip_planes[]) + on(plot, clip_planes) do value + updater[] = [:clip_planes, serialize_three(value)] + return + end + return mesh end diff --git a/WGLMakie/src/wglmakie.bundled.js b/WGLMakie/src/wglmakie.bundled.js index ae5a10200b0..16b7ee87f49 100644 --- a/WGLMakie/src/wglmakie.bundled.js +++ b/WGLMakie/src/wglmakie.bundled.js @@ -20237,7 +20237,7 @@ function uniform_type(obj) { } else if (obj instanceof THREE.Texture) { return "sampler2D"; } else { - return; + return "invalid"; } } function uniforms_to_type_declaration(uniform_dict) { @@ -20245,7 +20245,7 @@ function uniforms_to_type_declaration(uniform_dict) { for(const name in uniform_dict){ const uniform = uniform_dict[name]; const type = uniform_type(uniform); - result += `uniform ${type} ${name};\n`; + if (type != "invalid") result += `uniform ${type} ${name};\n`; } return result; } @@ -21326,11 +21326,11 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { ${attribute_decl} - out vec3 f_quad_sdf; out vec2 f_truncation; // invalid / not needed out float f_linestart; // constant out float f_linelength; + out float o_clip_distance[8]; flat out vec2 f_extrusion; // invalid / not needed flat out float f_linewidth; @@ -21345,6 +21345,7 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { flat out vec4 f_miter_vecs; // invalid / not needed ${uniform_decl} + uniform vec4 clip_planes[8]; // Constants const float AA_RADIUS = 0.8; @@ -21355,6 +21356,9 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Geometry/Position Utils //////////////////////////////////////////////////////////////////////// + vec4 world_space(vec3 point) { return model * vec4(point, 1); } + vec4 world_space(vec2 point) { return world_space(vec3(point, 0)); } + vec4 clip_space(vec3 point) { return projectionview * model * vec4(point, 1); } @@ -21375,6 +21379,10 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Main //////////////////////////////////////////////////////////////////////// + void process_clip_planes(vec3 world_pos) { + for (int i = 0; i < 8; i++) + o_clip_distance[i] = dot(world_pos, clip_planes[i].xyz) - clip_planes[i].w; + } void main() { bool is_end = position.x == 1.0; @@ -21440,6 +21448,8 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Varying vertex data //////////////////////////////////////////////////////////////////// + vec4 world_pos = world_space(is_end ? linepoint_end : linepoint_start); + process_clip_planes(world_pos.xyz); // linecaps f_capmode = ivec2(linecap); @@ -21484,6 +21494,7 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { out vec2 f_truncation; out float f_linestart; out float f_linelength; + out float o_clip_distance[8]; flat out vec2 f_extrusion; flat out float f_linewidth; @@ -21498,6 +21509,7 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { flat out vec4 f_miter_vecs; ${uniform_decl} + uniform vec4 clip_planes[8]; // Constants const float AA_RADIUS = 0.8; @@ -21596,6 +21608,9 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Geometry/Position Utils //////////////////////////////////////////////////////////////////////// + vec4 world_space(vec3 point) { return model * vec4(point, 1); } + vec4 world_space(vec2 point) { return world_space(vec3(point, 0)); } + vec4 clip_space(vec3 point) { return projectionview * model * vec4(point, 1); } @@ -21617,6 +21632,11 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { // Main //////////////////////////////////////////////////////////////////////// + void process_clip_planes(vec3 world_pos) { + for (int i = 0; i < 8; i++) + o_clip_distance[i] = dot(world_pos, clip_planes[i].xyz) - clip_planes[i].w; + } + void main() { bool is_end = position.x == 1.0; @@ -21850,7 +21870,9 @@ function lines_vertex_shader(uniforms, attributes, is_linesegments) { //////////////////////////////////////////////////////////////////// // Varying vertex data //////////////////////////////////////////////////////////////////// - + + vec4 world_pos = world_space(is_end ? linepoint_end : linepoint_start); + process_clip_planes(world_pos.xyz); vec3 offset; int x = int(is_end); @@ -21943,6 +21965,7 @@ function lines_fragment_shader(uniforms, attributes) { in vec2 f_truncation; in float f_linestart; in float f_linelength; + in float o_clip_distance[8]; flat in float f_linewidth; flat in vec4 f_pattern_overwrite; @@ -22066,6 +22089,10 @@ function lines_fragment_shader(uniforms, attributes) { void main(){ + for (int i = 0; i < 8; i++) + if (o_clip_distance[i] < 0.0) + discard; + vec4 color; // f_quad_sdf.x is the distance from p1, negative in v1 direction.