Skip to content

Commit 4a67281

Browse files
authored
fix 0 division of meshscatter normals (#5478)
* fix 0 scale normals * update changelog * tweak refimg * fix format
1 parent 1684918 commit 4a67281

File tree

5 files changed

+61
-10
lines changed

5 files changed

+61
-10
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
- Added loading spinner in WGLMakie that displays while the plot is being loaded [#5469](https://github.com/MakieOrg/Makie.jl/pull/5469)
66
- Moved decoration plots in `Axis3` to `ax.blockscene` so they no longer show up as user plots in the Axis3 [#5463](https://github.com/MakieOrg/Makie.jl/pull/5463)
77
- Fixed issue with `transformation` being applied multiple times when set by a user in a recipe that passes applicable attributes to child plots [#5464](https://github.com/MakieOrg/Makie.jl/pull/5464)
8-
- Fix `arrows2d[!]` plot elements causing CairoMakie SVGs to be rasterized. [#5459](https://github.com/MakieOrg/Makie.jl/pull/#5459)
9-
- Fix plotting order of multi-arrow `arrows2d[!]` to respect z-coordinates. [#5459](https://github.com/MakieOrg/Makie.jl/pull/#5459)
8+
- Fixed `arrows2d[!]` plot elements causing CairoMakie SVGs to be rasterized. [#5459](https://github.com/MakieOrg/Makie.jl/pull/#5459)
9+
- Fixed plotting order of multi-arrow `arrows2d[!]` to respect z-coordinates. [#5459](https://github.com/MakieOrg/Makie.jl/pull/#5459)
10+
- Fixed `meshscatter` objects rendering with incorrect color when scaled to 0 [#5478](https://github.com/MakieOrg/Makie.jl/pull/5478)
1011

1112
## [0.24.8] - 2025-12-04
1213

CairoMakie/src/mesh.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,10 @@ function draw_scattered_mesh(
404404
element_uv_transform = Makie.sv_getindex(uv_transform, i)
405405
element_translation = to_ndim(Point4d, positions[i], 0)
406406
element_rotation = Makie.rotationmatrix4(Makie.sv_getindex(rotations, i))
407-
element_scale = Makie.scalematrix(Makie.sv_getindex(scales, i))
408-
element_transform = element_rotation * element_scale # different order from transformationmatrix()
407+
element_scale = Makie.sv_getindex(scales, i)
408+
element_scale_matrix = Makie.scalematrix(element_scale)
409+
# different order from transformationmatrix()
410+
element_transform = f32c_model * element_rotation * element_scale_matrix
409411

410412
# Note: These are not part of the compute graph because the number of
411413
# vertices of the mesh * number of positions in meshscatter could become
@@ -418,16 +420,20 @@ function draw_scattered_mesh(
418420
# = f32c_model * element_transform * vertices + element_translation
419421
element_world_pos = map(meshpoints) do p
420422
p4d = to_ndim(Point4d, to_ndim(Point3d, p, 0), 1)
421-
p4d = f32c_model * element_transform * p4d + element_translation
423+
p4d = element_transform * p4d + element_translation
422424
return Point3f(p4d) / p4d[4]
423425
end
424426

425427
element_screen_pos = project_position(Point3f, proj_mat, element_world_pos, eachindex(element_world_pos))
426428

429+
# only used for normals
430+
finite_element_scale = @. ifelse(element_scale >= 0, +1, -1) * max(abs(element_scale), 1.0e-6)
431+
model = f32c_model * element_rotation * Makie.scalematrix(finite_element_scale)
432+
427433
draw_mesh3D(
428434
scene, screen, plot,
429435
element_world_pos, element_screen_pos, meshfaces, meshnormals, meshuvs,
430-
element_uv_transform, element_color, clip_planes, f32c_model * element_transform
436+
element_uv_transform, element_color, clip_planes, model
431437
)
432438
end
433439

GLMakie/assets/shader/particles.vert

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,30 @@ vec3 get_uv(int index, vec3 uv) {
116116
return uv;
117117
}
118118

119+
vec3 finite_sign(vec3 v)
120+
{
121+
return vec3(
122+
2 * float(v[0] >= 0) - 1,
123+
2 * float(v[1] >= 0) - 1,
124+
2 * float(v[2] >= 0) - 1
125+
);
126+
}
127+
128+
vec3 finite_div(vec3 v, vec3 d)
129+
{
130+
// sign(0) = 0
131+
vec3 df = finite_sign(d) * max(abs(d), 0.0000001);
132+
return v / df;
133+
}
119134

120135
void main(){
121136
int index = gl_InstanceID;
122137
o_id = uvec2(objectid, index+1);
123138
vec3 s = _scale(scale, index);
124139
vec3 V = s * vertices;
125-
vec3 N = normals / s; // see issue #3702
140+
// needed if scale distorts the shape, see issue #3702
141+
// can't allow zero division, see #5477
142+
vec3 N = finite_div(normals, s);
126143
vec3 pos;
127144
{{position_calc}}
128145
o_color = get_particle_color(color, intensity, color_map, color_norm, index, len);

ReferenceTests/src/tests/examples3d.jl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,16 +201,25 @@ end
201201
end
202202

203203
@reference_test "Basic Shading" begin
204-
f = Figure(size = (500, 300))
204+
f = Figure(size = (500, 500))
205205

206206
# see PR #3722
207207
pts = Point3f[[0, 0, 0], [1, 0, 0]]
208208
markersize = Vec3f[[0.5, 0.2, 0.5], [0.5, 0.2, 0.5]]
209209
rotation = [qrotation(Vec3f(1, 0, 0), 0), qrotation(Vec3f(1, 1, 0), π / 4)]
210-
meshscatter(f[1, 1], pts; markersize, rotation, color = :white, diffuse = Vec3f(-2, 0, 4), specular = Vec3f(4, 0, -2))
210+
meshscatter(
211+
f[1, 1], pts; markersize, rotation, color = :white,
212+
diffuse = Vec3f(-2, 0, 4), specular = Vec3f(4, 0, -2)
213+
)
211214

212215
mesh(f[1, 2], Sphere(Point3f(0), 1.0f0), color = :orange, shading = NoShading)
213216

217+
markersize = Vec3f[[0.5, 0.0, 0.5], [0.5, 0.2, 0.0]]
218+
meshscatter(
219+
f[2, 1], pts; markersize, rotation, color = :white,
220+
diffuse = Vec3f(-2, 0, 4), specular = Vec3f(4, 0, -2), backlight = 1
221+
)
222+
214223
f
215224
end
216225

WGLMakie/assets/particles.vert

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,29 @@ vec4 to_color(vec4 c) {
7575
return c;
7676
}
7777

78+
vec3 finite_sign(vec3 v)
79+
{
80+
return vec3(
81+
2.0 * float(v[0] >= 0.0) - 1.0,
82+
2.0 * float(v[1] >= 0.0) - 1.0,
83+
2.0 * float(v[2] >= 0.0) - 1.0
84+
);
85+
}
86+
87+
vec3 finite_div(vec3 v, vec3 d)
88+
{
89+
// sign(0) = 0
90+
vec3 df = finite_sign(d) * max(abs(d), 0.0000001);
91+
return v / df;
92+
}
93+
7894
void main(){
7995
// get_* gets the global inputs (uniform, sampler, position array)
8096
// those functions will get inserted by the shader creation pipeline
8197
vec3 vertex_position = get_markersize() * to_vec3(get_vertex_position());
82-
vec3 N = get_normal() / get_markersize(); // see issue #3702
98+
// needed for uneven scales, see issue #3702
99+
// can't divide by zero though
100+
vec3 N = finite_div(get_normal(), get_markersize());
83101
rotate(get_converted_rotation(), vertex_position, N);
84102
vertex_position = get_f32c_scale() * vertex_position;
85103
N = N / get_f32c_scale();

0 commit comments

Comments
 (0)