Skip to content

Commit

Permalink
merge master
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonDanisch committed Feb 19, 2025
2 parents d87c701 + ca1ffd7 commit b942faf
Show file tree
Hide file tree
Showing 79 changed files with 1,876 additions and 1,214 deletions.
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,31 @@

## [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)
- Updated `voxels` to use `uv_transform` interface instead of `uvmap` to give more control over texture mapping (i.e. to allow rotations) [#4758](https://github.com/MakieOrg/Makie.jl/pull/4758)
- **Breaking** Changed generated `uv`s in `voxels` to more easily align texture maps. Also changed uvs to scale with `gap` so that voxels remain fully covered. [#4758](https://github.com/MakieOrg/Makie.jl/pull/4758)
- Fixed `uv_transform = :rotr90` and `:rotl90` being swapped [#4758](https://github.com/MakieOrg/Makie.jl/pull/4758)
- 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)
- Changed `inspectable` to be inherited from the parent scenes theme. [#4739](https://github.com/MakieOrg/Makie.jl/pull/4739)
- Reverted change to `poly` which disallowed 3D geometries from being plotted [#4738](https://github.com/MakieOrg/Makie.jl/pull/4738)

## [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
5 changes: 3 additions & 2 deletions CairoMakie/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,14 @@ 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
"Voxel - texture mapping", # textures not implemented
"Voxel uvs", # textures not 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;
}
37 changes: 25 additions & 12 deletions GLMakie/assets/shader/voxel.frag
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

// debug FLAGS
// #define DEBUG_RENDER_ORDER 0 // (0, 1, 2) - dimensions
// #define DEBUG_UV
{{DEBUG_FLAG_DEFINE}}

struct Nothing{ //Nothing type, to encode if some variable doesn't contain any data
bool _; //empty structs are not allowed
Expand All @@ -29,7 +31,7 @@ uniform float gap;
uniform int _num_clip_planes;
uniform vec4 clip_planes[8];

{{uv_map_type}} uv_map;
{{uv_transform_type}} uv_transform;
{{color_map_type}} color_map;
{{color_type}} color;

Expand All @@ -44,26 +46,33 @@ vec4 debug_color(uint id) {
vec4 debug_color(int id) { return debug_color(uint(id)); }

// unused but compilation requires it
vec4 get_lrbt(Nothing uv_map, int id, int side) {
return vec4(0,0,1,1);
mat3x2 get_uv_transform_mat(Nothing uv_transform, int id, int side) {
return mat3x2(1,0,0,1,0,0);
}
vec4 get_lrbt(sampler1D uv_map, int id, int side) {
return texelFetch(uv_map, id-1, 0);
mat3x2 get_uv_transform_mat(sampler2D uv_transform, int id, int side) {
vec2 part1 = texelFetch(uv_transform, ivec2(0, id-1), 0).xy;
vec2 part2 = texelFetch(uv_transform, ivec2(1, id-1), 0).xy;
vec2 part3 = texelFetch(uv_transform, ivec2(2, id-1), 0).xy;
return mat3x2(part1, part2, part3);
}
vec4 get_lrbt(sampler2D uv_map, int id, int side) {
return texelFetch(uv_map, ivec2(id-1, side), 0);
mat3x2 get_uv_transform_mat(sampler3D uv_transform, int id, int side) {
vec2 part1 = texelFetch(uv_transform, ivec3(0, id-1, side), 0).xy;
vec2 part2 = texelFetch(uv_transform, ivec3(1, id-1, side), 0).xy;
vec2 part3 = texelFetch(uv_transform, ivec3(2, id-1, side), 0).xy;
return mat3x2(part1, part2, part3);
}

vec4 get_color_from_texture(sampler2D color, int id) {
vec4 lrbt = get_lrbt(uv_map, id, o_side);
mat3x2 uvt = get_uv_transform_mat(uv_transform, id, o_side);
// compute uv normalized to voxel
// TODO: float precision causes this to wrap sometimes (e.g. 5.999..7.0002)
vec2 voxel_uv = mod(o_tex_uv, 1.0);
voxel_uv = mix(lrbt.xz, lrbt.yw, voxel_uv);
// correct for shrinking due to gap
voxel_uv = (voxel_uv - vec2(0.5 * gap)) / vec2(1.0 - gap);
voxel_uv = uvt * vec3(voxel_uv, 1);
return texture(color, voxel_uv);
}


vec4 get_color(Nothing color, Nothing color_map, int id) {
return debug_color(id);
}
Expand Down Expand Up @@ -93,7 +102,7 @@ bool is_clipped()
// distance between clip plane and center
d = dot(xyz, clip_planes[i].xyz) - clip_planes[i].w;

if (d < 0.0)
if (d < 0.0)
return true;
}

Expand Down Expand Up @@ -127,6 +136,10 @@ void main()
// otherwise we draw. For now just some color...
vec4 voxel_color = get_color(color, color_map, id);

#ifdef DEBUG_UV
voxel_color = vec4(voxel_uv, 0, 1);
#endif

#ifdef DEBUG_RENDER_ORDER
if (plane_dim != DEBUG_RENDER_ORDER)
discard;
Expand All @@ -144,7 +157,7 @@ void main()
voxel_color.rgb = illuminate(o_normal, voxel_color.rgb);
#endif

// TODO: index into 3d array
// index into 3d array
ivec3 size = ivec3(textureSize(voxel_id, 0).xyz);
ivec3 idx = clamp(ivec3(o_uvw * size), ivec3(0), size-1);
int lin = 1 + idx.x + size.x * (idx.y + size.y * idx.z);
Expand Down
Loading

0 comments on commit b942faf

Please sign in to comment.