Skip to content

Commit

Permalink
Merge branch 'master' into sd/try-relocatability
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonDanisch authored Feb 18, 2025
2 parents ca1a3e2 + ee880c8 commit a2c9219
Show file tree
Hide file tree
Showing 67 changed files with 1,533 additions and 1,099 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@

## [Unreleased]

- Moved Axis3 clip planes slightly outside to avoid clipping objects on the border with 0 margin [#4742](https://github.com/MakieOrg/Makie.jl/pull/4742)
- Fixed an issue with transformations not propagating to child plots when their spaces only match indirectly. [#4723](https://github.com/MakieOrg/Makie.jl/pull/4723)
- Added a tutorial on creating an inset plot [#4697](https://github.com/MakieOrg/Makie.jl/pull/4697)
- Enhanced Pattern support: Added general CairoMakie implementation, improved quality, added anchoring, added support in band, density, added tests & fixed various bugs and inconsistencies. [#4715](https://github.com/MakieOrg/Makie.jl/pull/4715)
- Fixed issue with `voronoiplot` for Voronoi tessellations with empty polygons [#4740](https://github.com/MakieOrg/Makie.jl/pull/4740)
- Fixed shader compilation error due to undefined unused variable in volume [#4755](https://github.com/MakieOrg/Makie.jl/pull/4755)
- Added option `update_while_dragging=true` to Slider [#4745](https://github.com/MakieOrg/Makie.jl/pull/4745).
- Added option `lowres_background=true` to Resampler, and renamed `resolution` to `max_resolution` [#4745](https://github.com/MakieOrg/Makie.jl/pull/4745).
- Added option `throttle=0.0` to `async_latest`, to allow throttling while skipping latest updates [#4745](https://github.com/MakieOrg/Makie.jl/pull/4745).
- Fixed issue with `WGLMakie.voxels` not rendering on linux with firefox [#4756](https://github.com/MakieOrg/Makie.jl/pull/4756)
- Cleaned up surface handling in GLMakie: Surface cells are now discarded when there is a nan in x, y or z. Fixed incorrect normal if x or y is nan [#4735](https://github.com/MakieOrg/Makie.jl/pull/4735)
- Cleaned up `volume` plots: Added `:indexedabsorption` and `:additive` to WGLMakie, generalized `:mip` to include negative values, fixed missing conversions for rgba algorithms (`:additive`, `:absorptionrgba`), fixed missing conversion for `absorption` attribute & extended it to `:indexedabsorption` and `absorptionrgba`, added tests and improved docs. [#4726](https://github.com/MakieOrg/Makie.jl/pull/4726)
- Fixed integer underflow in GLMakie line indices which may have caused segmentation faults on mac [#4782](https://github.com/MakieOrg/Makie.jl/pull/4782)
- Added `Axis3.clip` attribute to allow turning off clipping [#4791](https://github.com/MakieOrg/Makie.jl/pull/4791)
- Fixed `Plane(Vec{N, T}(0), dist)` producing a `NaN` normal, which caused WGLMakie to break. (E.g. when rotating Axis3) [#4772](https://github.com/MakieOrg/Makie.jl/pull/4772)

## [0.22.1] - 2025-01-17

- Allow volume textures for mesh color, to e.g. implement a performant volume slice display [#2274](https://github.com/MakieOrg/Makie.jl/pull/2274).
- Fix `alpha` use in legends and some CairoMakie cases [#4721](https://github.com/MakieOrg/Makie.jl/pull/4721).
- Fixed `alpha` use in legends and some CairoMakie cases [#4721](https://github.com/MakieOrg/Makie.jl/pull/4721).

## [0.22.0] - 2024-12-12

Expand Down
2 changes: 1 addition & 1 deletion CairoMakie/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,13 @@ excludes = Set([
"fast pixel marker",
"scatter with glow", # some are missing
"scatter with stroke", # stroke acts inward in CairoMakie, outwards in W/GLMakie
"heatmaps & surface", # different nan_colors in surface
"Textured meshscatter", # not yet implemented
"Voxel - texture mapping", # not yet implemented
"Miter Joints for line rendering", # CairoMakie does not show overlap here
"picking", # Not implemented
"MetaMesh (Sponza)", # makes little sense without per pixel depth order
"Mesh with 3d volume texture", # Not implemented yet
"Volume absorption",
])

functions = [:volume, :volume!, :uv_mesh]
Expand Down
101 changes: 77 additions & 24 deletions GLMakie/assets/shader/surface.vert
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ vec4 color_lookup(float intensity, sampler1D color, vec2 norm);

uniform vec3 scale;
uniform mat4 view, model, projection;
uniform bool invert_normals;

uniform uint objectid;
flat out uvec2 o_id;
flat out int o_InstanceID; // dummy for compat with meshscatter in mesh.frag
out vec4 o_color;
out vec3 o_uv;

// See util.vert for implementations
void render(vec4 position_world, vec3 normal, mat4 view, mat4 projection);
Expand Down Expand Up @@ -85,18 +92,18 @@ vec3 normal_from_points(
// isnan checks should avoid darkening around NaN positions but may not
// work with all systems
if (!isnan(s0.z)) {
bool check1 = isinbounds(off1, size) && !isnan(s1.z);
bool check2 = isinbounds(off2, size) && !isnan(s2.z);
bool check3 = isinbounds(off3, size) && !isnan(s3.z);
bool check4 = isinbounds(off4, size) && !isnan(s4.z);
bool check1 = isinbounds(off1, size) && !isnan(s1.x) && !isnan(s1.y) && !isnan(s1.z);
bool check2 = isinbounds(off2, size) && !isnan(s2.x) && !isnan(s2.y) && !isnan(s2.z);
bool check3 = isinbounds(off3, size) && !isnan(s3.x) && !isnan(s3.y) && !isnan(s3.z);
bool check4 = isinbounds(off4, size) && !isnan(s4.x) && !isnan(s4.y) && !isnan(s4.z);
if (check1 && check2) result += cross(s2-s0, s1-s0);
if (check2 && check3) result += cross(s3-s0, s2-s0);
if (check3 && check4) result += cross(s4-s0, s3-s0);
if (check4 && check1) result += cross(s1-s0, s4-s0);
}
// normal should be zero, but needs to be here, because the dead-code
// elimanation of GLSL is overly enthusiastic
return normalize(result);
// elimination of GLSL is overly enthusiastic
return (invert_normals ? -1.0 : 1.0) * normalize(result);
}

// Overload for surface(Matrix, Matrix, Matrix)
Expand Down Expand Up @@ -157,31 +164,77 @@ vec3 getnormal(Nothing pos, sampler1D xs, sampler1D ys, sampler2D zs, ivec2 uv){
return normal_from_points(s0, s1, s2, s3, s4, off1, off2, off3, off4, textureSize(zs, 0));
}

uniform uint objectid;
flat out uvec2 o_id;
flat out int o_InstanceID; // dummy for compat with meshscatter in mesh.frag
out vec4 o_color;
out vec3 o_uv;
// See main() for more information
vec3 getposition(Nothing grid, sampler2D x, sampler2D y, sampler2D z, ivec2 idx, vec2 uv) {
vec3 center = vec3(texture(x, uv).x, texture(y, uv).x, texture(z, uv).x);
if (isnan(center.x) || isnan(center.y) || isnan(center.z)) {
return vec3(0);
} else {
return vec3(texelFetch(x, idx, 0).x, texelFetch(y, idx, 0).x, texelFetch(z, idx, 0).x);
}
}
vec3 getposition(Nothing grid, sampler1D x, sampler1D y, sampler2D z, ivec2 idx, vec2 uv) {
vec3 center = vec3(texture(x, uv.x).x, texture(y, uv.y).x, texture(z, uv).x);
if (isnan(center.x) || isnan(center.y) || isnan(center.z)) {
return vec3(0);
} else {
return vec3(texelFetch(x, idx.x, 0).x, texelFetch(y, idx.y, 0).x, texelFetch(z, idx, 0).x);
}
}
vec3 getposition(Grid2D grid, Nothing x, Nothing y, sampler2D z, ivec2 idx, vec2 uv) {
float center = texture(z, uv).x;
if (isnan(center)) {
return vec3(0);
} else {
ivec2 size = textureSize(z, 0);
return vec3(grid_pos(grid, idx, size), texelFetch(z, idx, 0).x);
}
}



void main()
{
// We have (N, M) = dims positions with (N-1, M-1) rects between them. Each
// instance refers to one rect. Each rect has vertices (0..1, 0..1) so we
// can do `base_idx + vertex` to index positions if base_idx refers to a
// (N-1, M-1) matrix.
int index = gl_InstanceID;
vec2 offset = vertices;
ivec2 offseti = ivec2(offset);
ivec2 dims = textureSize(position_z, 0);
vec3 pos;
{{position_calc}}
ivec2 base_idx = ind2sub(dims - 1, index);
ivec2 vertex_index = base_idx + ivec2(vertices);

/*
When using uv coordinates to access textures here, we need to be careful with
how we calculate the uvs. 0, 1 refer to the far edges of the texture:
0 1/N 2/N 3/N ... N/N
|_____|_____|_____|_ _|
| | | | |
|_____|_____|_____|_ _|
| | | | |
Our textures contain one pixel per vertex though, so that the pixel centers
correspond to vertices. I.e. we want to access (0.5/N, 0.5/M) for the first
vertex, corresponding to index (0, 0).
*/

// Discard rects containing a nan value by making their size zero. For this
// we get the value at the center of the rect, which mixes all 4 vertex
// values via texture interpolation. (If nan is part of the interpolation
// the result will also be nan.)
vec2 center_uv = (base_idx + vec2(1)) / dims;
vec3 pos = getposition(position, position_x, position_y, position_z, vertex_index, center_uv);
vec3 normalvec = getnormal(position, position_x, position_y, position_z, vertex_index);

// Colors should correspond to vertices, so they need the 0.5 shift discussed
// above
vec2 vertex_uv = vec2(vertex_index + 0.5) / vec2(dims);
o_uv = apply_uv_transform(uv_transform, vec2(vertex_uv.x, 1 - vertex_uv.y));

o_color = vec4(0.0);
o_id = uvec2(objectid, 0); // calculated from uv in mesh.frag
o_InstanceID = 0;
// match up with mesh
o_uv = apply_uv_transform(uv_transform, vec2(index01.x, 1 - index01.y));
vec3 normalvec = {{normal_calc}};
o_InstanceID = 0; // for meshscatter uv_transforms, irrelevant here

o_color = vec4(0.0);
// we still want to render NaN values... TODO: make value customizable?
if (isnan(pos.z)) {
pos.z = 0.0;
}
render(model * vec4(pos, 1), normalvec, view, projection);
}
51 changes: 18 additions & 33 deletions GLMakie/assets/shader/volume.frag
Original file line number Diff line number Diff line change
Expand Up @@ -35,45 +35,30 @@ const float max_distance = 1.3;
const int num_samples = 200;
const float step_size = max_distance / float(num_samples);

float _normalize(float val, float from, float to)
{
return (val-from) / (to - from);
}
float _normalize(float val, float from, float to) { return (val-from) / (to - from);}

vec4 color_lookup(float intensity, Nothing color_map, Nothing norm, vec4 color)
{
vec4 color_lookup(float intensity, Nothing color_map, Nothing norm, vec4 color) {
return color;
}

vec4 color_lookup(float intensity, samplerBuffer color_ramp, vec2 norm, Nothing color)
{
vec4 color_lookup(float intensity, samplerBuffer color_ramp, vec2 norm, Nothing color) {
return texelFetch(color_ramp, int(_normalize(intensity, norm.x, norm.y)*textureSize(color_ramp)));
}

vec4 color_lookup(float intensity, samplerBuffer color_ramp, Nothing norm, Nothing color)
{
vec4 color_lookup(float intensity, samplerBuffer color_ramp, Nothing norm, Nothing color) {
return vec4(0); // stub method
}

vec4 color_lookup(float intensity, sampler1D color_ramp, vec2 norm, Nothing color)
{
vec4 color_lookup(float intensity, sampler1D color_ramp, vec2 norm, Nothing color) {
return texture(color_ramp, _normalize(intensity, norm.x, norm.y));
}

vec4 color_lookup(samplerBuffer colormap, int index)
{
return texelFetch(colormap, index);
vec4 color_lookup(vec4 data_color, Nothing color_ramp, Nothing norm, Nothing color) {
return data_color; // stub method
}

vec4 color_lookup(sampler1D colormap, int index)
{
return texelFetch(colormap, index, 0);
vec4 color_lookup(float intensity, Nothing color_ramp, Nothing norm, Nothing color) {
return vec4(0); // stub method
}

vec4 color_lookup(Nothing colormap, int index)
{
return vec4(0);
}
vec4 color_lookup(samplerBuffer colormap, int index) { return texelFetch(colormap, index); }
vec4 color_lookup(sampler1D colormap, int index) { return texelFetch(colormap, index, 0); }
vec4 color_lookup(Nothing colormap, int index) { return vec4(0); }

vec3 gennormal(vec3 uvw, float d, vec3 o)
{
Expand Down Expand Up @@ -184,7 +169,7 @@ vec4 absorptionrgba(vec3 front, vec3 dir)
int i = 0;
for (i; i < num_samples ; ++i) {
vec4 density = texture(volumedata, pos);
float opacity = step_size * density.a;
float opacity = step_size * density.a * absorption;
T *= 1.0-opacity;
if (T <= 0.01)
break;
Expand All @@ -204,7 +189,7 @@ vec4 volumeindexedrgba(vec3 front, vec3 dir)
for (i; i < num_samples; ++i) {
int index = int(texture(volumedata, pos).x) - 1;
vec4 density = color_lookup(color_map, index);
float opacity = step_size*density.a;
float opacity = step_size*density.a * absorption;
Lo += (T*opacity)*density.rgb;
T *= 1.0 - opacity;
if (T <= 0.01)
Expand Down Expand Up @@ -284,9 +269,9 @@ vec4 isosurface(vec3 front, vec3 dir)

vec4 mip(vec3 front, vec3 dir)
{
vec3 pos = front;
int i = 0;
float maximum = 0.0;
vec3 pos = front + dir;
int i = 1;
float maximum = texture(volumedata, front).x;
for (i; i < num_samples; ++i, pos += dir){
float density = texture(volumedata, pos).x;
if(maximum < density)
Expand Down Expand Up @@ -315,7 +300,7 @@ bool process_clip_planes(inout vec3 p1, inout vec3 p2)
p2 = p1;
return true;
}

// one outside - shorten segment
else if (d1 < 0.0)
// solve 0 = m * t + b = (d2 - d1) * t + d1 with t in (0, 1)
Expand Down
11 changes: 8 additions & 3 deletions GLMakie/assets/shader/volume.vert
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@ uniform float depth_shift;
out vec3 o_view_pos;
out vec3 o_view_normal;

// Lighting (unused and don't need to be available?)
// out vec3 o_world_pos;
// out vec3 o_world_normal;
// Lighting (unused but sometimes necessary)
out vec3 o_world_pos;
out vec3 o_camdir;

void main()
{
// TODO set these in volume.frag
o_view_pos = vec3(0);
o_view_normal = vec3(0);

o_world_pos = vec3(0);
o_camdir = vec3(0);

vec4 world_vert = model * vec4(vertices, 1);
frag_vert = world_vert.xyz;

gl_Position = projectionview * world_vert;
gl_Position.z += gl_Position.w * depth_shift;
}
17 changes: 13 additions & 4 deletions GLMakie/src/GLAbstraction/GLBuffer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ mutable struct GLBuffer{T} <: GPUArray{T, 1}
switch_context!(context)
id = glGenBuffers()
glBindBuffer(buffertype, id)
# size of 0 can segfault it seems
buff_length = buff_length == 0 ? 1 : buff_length
glBufferData(buffertype, buff_length * sizeof(T), ptr, usage)
# size of 0 can segfault it seems, but so can a draw call to an index buffer that has garbage data.
# Therefore we let the buffer pull some garbage data in to have a GPU size > 0,
# but keep the CPU size unchanged. Draw calls are then discarded if the CPU size is 0.
glBufferData(buffertype, max(1, buff_length) * sizeof(T), ptr, usage)
glBindBuffer(buffertype, 0)

obj = new(
Expand Down Expand Up @@ -105,7 +106,15 @@ function gpu_data(b::GLBuffer{T}) where T
bind(b)
glGetBufferSubData(b.buffertype, 0, sizeof(data), data)
bind(b, 0)
data
return data
end

# for render() debug checks
function gpu_data_no_unbind(b::GLBuffer{T}) where T
data = Vector{T}(undef, length(b))
bind(b)
glGetBufferSubData(b.buffertype, 0, sizeof(data), data)
return data
end


Expand Down
Loading

0 comments on commit a2c9219

Please sign in to comment.