Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement multiple lights and more Light types #3246

Merged
merged 91 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
1a67a4d
lighting experiments [skip ci]
ffreyer Sep 21, 2023
86a63c5
remove intermediate type, increase number of lights [skip ci]
ffreyer Sep 21, 2023
13a26d3
add directional light, move lightpos transform to cpu
ffreyer Sep 21, 2023
e17b154
add attenuation
ffreyer Sep 21, 2023
f3743c8
hook up interactivity to render_tick [skip ci]
ffreyer Sep 21, 2023
7b5a6c6
squash parameters into one array
ffreyer Sep 22, 2023
c15d90f
add SpotLight [skip ci]
ffreyer Sep 22, 2023
614592b
reimplement shading [skip ci]
ffreyer Sep 22, 2023
c250f30
minor cleanup, avoid allocs [skip ci]
ffreyer Sep 22, 2023
7fb1ec5
update RPRMakie, tweak SpotLight
ffreyer Sep 23, 2023
2a1b8cf
switch to smoothstep for SpotLight
ffreyer Sep 23, 2023
bbea0a7
readd old lighting code
ffreyer Sep 24, 2023
f2fdd48
work around for Observables#110
ffreyer Sep 24, 2023
246ce65
update `shading` attribute
ffreyer Sep 24, 2023
4bab511
more shading attribute updates
ffreyer Sep 24, 2023
f62d07f
update more shading attributes
ffreyer Sep 25, 2023
7c16e45
merge updates into one call, normalize directions
ffreyer Sep 26, 2023
754f243
fix directions
ffreyer Sep 26, 2023
c7c4b38
add refimg tests
ffreyer Sep 26, 2023
2b748ed
fix and test specular reflections
ffreyer Sep 26, 2023
20b45b6
update docs
ffreyer Sep 26, 2023
39604ea
remove specular reflection
ffreyer Sep 26, 2023
f564279
add pollevents in colorbuffer & tweak render_tick priority
ffreyer Sep 26, 2023
4de2a2e
make number of lights adjustable
ffreyer Sep 27, 2023
58df480
cleanup some comments, todos, etc
ffreyer Sep 27, 2023
a0ee747
update NEWS [skip ci]
ffreyer Sep 27, 2023
3c745f6
fixes
ffreyer Sep 27, 2023
7fe5c3d
fix screen size test
ffreyer Sep 27, 2023
dfd26cd
rework backlight to affect normals and apply to verbose shading
ffreyer Sep 27, 2023
2cfc71d
switch to world space lighting
ffreyer Sep 28, 2023
729aea9
integrate lighting with volume
ffreyer Sep 28, 2023
872daa1
minor cleanup
ffreyer Sep 28, 2023
dba22ab
update backlight in other backends
ffreyer Sep 28, 2023
fc5b654
minor cleanup [skip ci]
ffreyer Sep 28, 2023
b94fdb6
reduce allocations
ffreyer Sep 29, 2023
53f92d7
fix typo
ffreyer Sep 29, 2023
538263c
fix #2985
ffreyer Sep 29, 2023
81e20cc
minor cleanup [skip ci]
ffreyer Sep 29, 2023
5db96a1
set default shading based on number of lights
ffreyer Sep 29, 2023
fd1589a
switch shading to enum
ffreyer Sep 29, 2023
22716d4
update some more shading attributes
ffreyer Sep 29, 2023
adf450e
fix WGLMakie errors
ffreyer Sep 29, 2023
a45f34b
fix docs
ffreyer Sep 30, 2023
1d8bb7e
derive default shading at plot insertion
ffreyer Sep 30, 2023
cbe2d0a
update shading conversion tests
ffreyer Sep 30, 2023
aae5221
switch to DirectionalLight by default
ffreyer Oct 3, 2023
1645afd
update test
ffreyer Oct 3, 2023
1df207e
fix specular reflection
ffreyer Oct 4, 2023
08de7b1
smooth out lighting edge
ffreyer Oct 4, 2023
89e27f4
fix exponent
ffreyer Oct 4, 2023
e68846e
minor optimization [skip ci]
ffreyer Oct 4, 2023
964cab9
update defaults
ffreyer Oct 4, 2023
935c0d0
Merge branch 'sd/beta-20' into ff/lighting
ffreyer Oct 6, 2023
14b6601
fix matcap
ffreyer Oct 6, 2023
fbe44f2
update docs
ffreyer Oct 7, 2023
d05dde4
fix WGLMakie
ffreyer Oct 10, 2023
2cb0abd
cleanup print
ffreyer Oct 10, 2023
0d74694
fix meshscatter [skip ci]
ffreyer Oct 10, 2023
4343b62
move camera-relative light dir calc to backends
ffreyer Oct 11, 2023
9935fb4
add light edge smoothing to WGLMakie
ffreyer Oct 11, 2023
c13f330
fix error
ffreyer Oct 11, 2023
1e4d153
move scale_matrix to model, fix dir
ffreyer Oct 12, 2023
5a495ce
do not connect transformations in different spaces
ffreyer Oct 12, 2023
1f35172
allow scene to report multiple spaces
ffreyer Oct 12, 2023
97ef82e
allow empty lights vectors
ffreyer Oct 12, 2023
6dab20b
fix fast lighting with incomplete light setup
ffreyer Oct 12, 2023
028f883
move docs to references
ffreyer Oct 12, 2023
dbe8d66
minor cleanup
ffreyer Oct 12, 2023
4f653d3
fix folder link
ffreyer Oct 13, 2023
7ffd4cd
fix typo, try fix docs
ffreyer Oct 16, 2023
9f44af6
Merge branch 'sd/beta-20' into ff/lighting
ffreyer Oct 16, 2023
32f8971
Merge branch 'sd/beta-20' into ff/lighting
ffreyer Oct 16, 2023
b6c26f4
Merge branch 'sd/beta-20' into ff/lighting
ffreyer Oct 16, 2023
6c37303
improve example
ffreyer Oct 16, 2023
60b778f
fix missing import
ffreyer Oct 16, 2023
ca064c4
Merge branch 'sd/beta-20' into ff/lighting
ffreyer Oct 19, 2023
f11a442
Merge branch 'sd/beta-20' into ff/lighting
SimonDanisch Oct 26, 2023
4f482a7
clean up LScene reset_limit, fix test
SimonDanisch Oct 26, 2023
54b73b9
fix makie tests
SimonDanisch Oct 26, 2023
d6ebc56
update WGLMakie bundle
SimonDanisch Oct 26, 2023
df67ec8
fix nan surface in WGLMakie
ffreyer Oct 27, 2023
c839d03
consider center when updating camera
ffreyer Oct 27, 2023
3123263
Merge branch 'sd/beta-20' into ff/lighting
ffreyer Oct 28, 2023
7e284e4
fix some merge errors
ffreyer Oct 28, 2023
e9c5443
disable centering after explicit camera placement
ffreyer Oct 28, 2023
bff268c
connect transform_marker to marker/char offsets
ffreyer Oct 29, 2023
fdbb86a
fix axsi3 test (CairoMakie meshscatter transformation)
ffreyer Oct 29, 2023
9dc792b
minor performance tweak
ffreyer Oct 29, 2023
4a00db4
Merge branch 'sd/beta-20' into ff/lighting
SimonDanisch Oct 30, 2023
61c596d
Merge branch 'sd/beta-20' into ff/lighting
SimonDanisch Oct 30, 2023
1d255de
Merge branch 'sd/beta-20' into ff/lighting
SimonDanisch Oct 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 65 additions & 45 deletions CairoMakie/src/primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -496,13 +496,14 @@ end
function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Text{<:Tuple{<:Union{AbstractArray{<:Makie.GlyphCollection}, Makie.GlyphCollection}}}))
ctx = screen.context
@get_attribute(primitive, (rotation, model, space, markerspace, offset))
transform_marker = to_value(get(primitive, :transform_marker, true))::Bool
position = primitive.position[]
# use cached glyph info
glyph_collection = to_value(primitive[1])

draw_glyph_collection(
scene, ctx, position, glyph_collection, remove_billboard(rotation),
model, space, markerspace, offset, primitive.transformation
model, space, markerspace, offset, primitive.transformation, transform_marker
)

nothing
Expand All @@ -511,21 +512,23 @@ end

function draw_glyph_collection(
scene, ctx, positions, glyph_collections::AbstractArray, rotation,
model::Mat, space, markerspace, offset, transformation
model::Mat, space, markerspace, offset, transformation, transform_marker
)

# TODO: why is the Ref around model necessary? doesn't broadcast_foreach handle staticarrays matrices?
broadcast_foreach(positions, glyph_collections, rotation, Ref(model), space,
markerspace, offset) do pos, glayout, ro, mo, sp, msp, off

draw_glyph_collection(scene, ctx, pos, glayout, ro, mo, sp, msp, off, transformation)
draw_glyph_collection(scene, ctx, pos, glayout, ro, mo, sp, msp, off, transformation, transform_marker)
end
end

_deref(x) = x
_deref(x::Ref) = x[]

function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation, _model, space, markerspace, offsets, transformation)
function draw_glyph_collection(
scene, ctx, position, glyph_collection, rotation, _model, space,
markerspace, offsets, transformation, transform_marker)

glyphs = glyph_collection.glyphs
glyphoffsets = glyph_collection.origins
Expand All @@ -537,7 +540,7 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation,
strokecolors = glyph_collection.strokecolors

model = _deref(_model)
model33 = model[Vec(1, 2, 3), Vec(1, 2, 3)]
model33 = transform_marker ? model[Vec(1, 2, 3), Vec(1, 2, 3)] : Mat3f(I)
id = Mat4f(I)

glyph_pos = let
Expand Down Expand Up @@ -859,7 +862,7 @@ end
nan2zero(x) = !isnan(x) * x


function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f0)
function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f0, rotation = Mat4f(I))
@get_attribute(attributes, (shading, diffuse, specular, shininess, faceculling))

matcap = to_value(get(attributes, :matcap, nothing))
Expand All @@ -876,44 +879,61 @@ function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f
model = attributes.model[]::Mat4f
space = to_value(get(attributes, :space, :data))::Symbol
func = Makie.transform_func(attributes)

# TODO: assume Symbol here after this has been deprecated for a while
if shading isa Bool
@warn "`shading::Bool` is deprecated. Use `shading = NoShading` instead of false and `shading = FastShading` or `shading = MultiLightShading` instead of true."
shading_bool = shading
else
shading_bool = shading != NoShading
end

draw_mesh3D(
scene, screen, space, func, meshpoints, meshfaces, meshnormals, per_face_col, pos, scale,
model, shading::Bool, diffuse::Vec3f,
scene, screen, space, func, meshpoints, meshfaces, meshnormals, per_face_col,
pos, scale, rotation,
model, shading_bool::Bool, diffuse::Vec3f,
specular::Vec3f, shininess::Float32, faceculling::Int
)
end

function draw_mesh3D(
scene, screen, space, transform_func, meshpoints, meshfaces, meshnormals, per_face_col, pos, scale,
scene, screen, space, transform_func, meshpoints, meshfaces, meshnormals, per_face_col,
pos, scale, rotation,
model, shading, diffuse,
specular, shininess, faceculling
)
ctx = screen.context
view = ifelse(is_data_space(space), scene.camera.view[], Mat4f(I))
projection = Makie.space_to_clip(scene.camera, space, false)
projectionview = Makie.space_to_clip(scene.camera, space, true)
eyeposition = scene.camera.eyeposition[]
i = Vec(1, 2, 3)
normalmatrix = transpose(inv(view[i, i] * model[i, i]))

# Mesh data
# transform to view/camera space
normalmatrix = transpose(inv(model[i, i]))

local_model = rotation * Makie.scalematrix(Vec3f(scale))
# pass transform_func as argument to function, so that we get a function barrier
# and have `transform_func` be fully typed inside closure
vs = broadcast(meshpoints, (transform_func,)) do v, f
# Should v get a nan2zero?
v = Makie.apply_transform(f, v, space)
p4d = to_ndim(Vec4f, scale .* to_ndim(Vec3f, v, 0f0), 1f0)
view * (model * p4d .+ to_ndim(Vec4f, pos, 0f0))
p4d = to_ndim(Vec4f, to_ndim(Vec3f, v, 0f0), 1f0)
model * (local_model * p4d .+ to_ndim(Vec4f, pos, 0f0))
end

ns = map(n -> normalize(normalmatrix * n), meshnormals)

# Light math happens in view/camera space
pointlight = Makie.get_point_light(scene)
lightposition = if !isnothing(pointlight)
pointlight.position[]
dirlight = Makie.get_directional_light(scene)
if !isnothing(dirlight)
lightdirection = if dirlight.camera_relative
T = inv(scene.camera.view[][Vec(1,2,3), Vec(1,2,3)])
normalize(T * dirlight.direction[])
else
normalize(dirlight.direction[])
end
c = dirlight.color[]
light_color = Vec3f(red(c), green(c), blue(c))
else
Vec3f(0)
lightdirection = Vec3f(0,0,-1)
light_color = Vec3f(0)
end

ambientlight = Makie.get_ambient_light(scene)
Expand All @@ -924,11 +944,9 @@ function draw_mesh3D(
Vec3f(0)
end

lightpos = (view * to_ndim(Vec4f, lightposition, 1.0))[Vec(1, 2, 3)]

# Camera to screen space
ts = map(vs) do v
clip = projection * v
clip = projectionview * v
@inbounds begin
p = (clip ./ clip[4])[Vec(1, 2)]
p_yflip = Vec2f(p[1], -p[2])
Expand All @@ -938,38 +956,41 @@ function draw_mesh3D(
return Vec3f(p[1], p[2], clip[3])
end

# vs are used as camdir (camera to vertex) for light calculation (in world space)
vs = map(v -> normalize(v[i] - eyeposition), vs)

# Approximate zorder
average_zs = map(f -> average_z(ts, f), meshfaces)
zorder = sortperm(average_zs)

# Face culling
zorder = filter(i -> any(last.(ns[meshfaces[i]]) .> faceculling), zorder)

draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightpos, shininess, diffuse, ambient, specular)
draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightdirection, light_color, shininess, diffuse, ambient, specular)
return
end

function _calculate_shaded_vertexcolors(N, v, c, lightpos, ambient, diffuse, specular, shininess)
L = normalize(lightpos .- v[Vec(1,2,3)])
diff_coeff = max(dot(L, N), 0f0)
H = normalize(L + normalize(-v[Vec(1, 2, 3)]))
spec_coeff = max(dot(H, N), 0f0)^shininess
function _calculate_shaded_vertexcolors(N, v, c, lightdir, light_color, ambient, diffuse, specular, shininess)
L = lightdir
diff_coeff = max(dot(L, -N), 0f0)
H = normalize(L + v)
spec_coeff = max(dot(H, -N), 0f0)^shininess
c = RGBAf(c)
# if this is one expression it introduces allocations??
new_c_part1 = (ambient .+ diff_coeff .* diffuse) .* Vec3f(c.r, c.g, c.b) #.+
new_c = new_c_part1 .+ specular * spec_coeff
new_c_part1 = (ambient .+ light_color .* diff_coeff .* diffuse) .* Vec3f(c.r, c.g, c.b) #.+
new_c = new_c_part1 .+ light_color .* specular * spec_coeff
RGBAf(new_c..., c.alpha)
end

function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightpos, shininess, diffuse, ambient, specular)
function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs, lightdir, light_color, shininess, diffuse, ambient, specular)
for k in reverse(zorder)

f = meshfaces[k]
# avoid SizedVector through Face indexing
t1 = ts[f[1]]
t2 = ts[f[2]]
t3 = ts[f[3]]

# skip any mesh segments with NaN points.
if isnan(t1) || isnan(t2) || isnan(t3)
continue
Expand All @@ -984,7 +1005,7 @@ function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs,
N = ns[f[i]]
v = vs[f[i]]
c = facecolors[i]
_calculate_shaded_vertexcolors(N, v, c, lightpos, ambient, diffuse, specular, shininess)
_calculate_shaded_vertexcolors(N, v, c, lightdir, light_color, ambient, diffuse, specular, shininess)
end
else
c1, c2, c3 = facecolors
Expand All @@ -995,7 +1016,7 @@ function draw_pattern(ctx, zorder, shading, meshfaces, ts, per_face_col, ns, vs,
# c1 = RGB(n1...)
# c2 = RGB(n2...)
# c3 = RGB(n3...)

pattern = Cairo.CairoPatternMesh()

Cairo.mesh_pattern_begin_patch(pattern)
Expand Down Expand Up @@ -1067,25 +1088,24 @@ function draw_atomic(scene::Scene, screen::Screen, @nospecialize(primitive::Maki

)

if !(rotations isa Vector)
R = Makie.rotationmatrix4(to_rotation(rotations))
submesh[:model] = model * R
end
submesh[:model] = model
scales = primitive[:markersize][]
for i in zorder
p = pos[i]
if color isa AbstractVector
submesh[:calculated_colors] = color[i]
end
if rotations isa Vector
R = Makie.rotationmatrix4(to_rotation(rotations[i]))
submesh[:model] = model * R
end
scale = markersize isa Vector ? markersize[i] : markersize
rotation = if rotations isa Vector
Makie.rotationmatrix4(to_rotation(rotations[i]))
else
Makie.rotationmatrix4(to_rotation(rotations))
end

draw_mesh3D(
scene, screen, submesh, marker, pos = p,
scale = scale isa Real ? Vec3f(scale) : to_ndim(Vec3f, scale, 1f0)
scale = scale isa Real ? Vec3f(scale) : to_ndim(Vec3f, scale, 1f0),
rotation = rotation
)
end

Expand Down
4 changes: 2 additions & 2 deletions GLMakie/assets/shader/fragment_output.frag
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ layout(location=1) out uvec2 fragment_groupid;


in vec3 o_view_pos;
in vec3 o_normal;
in vec3 o_view_normal;

void write2framebuffer(vec4 color, uvec2 id){
if(color.a <= 0.0)
Expand All @@ -34,7 +34,7 @@ void write2framebuffer(vec4 color, uvec2 id){
// // if transparency == false && ssao = true
// fragment_color = color;
// fragment_position = o_view_pos;
// fragment_normal_occlusion.xyz = o_normal;
// fragment_normal_occlusion.xyz = o_view_normal;

// // else
// fragment_color = color;
Expand Down
4 changes: 2 additions & 2 deletions GLMakie/assets/shader/heatmap.vert
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ out vec2 o_uv;
flat out uvec2 o_objectid;

out vec3 o_view_pos;
out vec3 o_normal;
out vec3 o_view_normal;

ivec2 ind2sub(ivec2 dim, int linearindex){
return ivec2(linearindex % dim.x, linearindex / dim.x);
Expand All @@ -22,7 +22,7 @@ ivec2 ind2sub(ivec2 dim, int linearindex){
void main(){
//Outputs for ssao, which we don't use for 2d shaders like heatmap/image
o_view_pos = vec3(0);
o_normal = vec3(0);
o_view_normal = vec3(0);

int index = gl_InstanceID;
vec2 offset = vertices;
Expand Down
Loading
Loading