Skip to content

Sphere billboard (Impostor)#1037

Merged
maharshi-gor merged 13 commits intofury-gl:v2from
m-agour:sphere-billboard
Feb 25, 2026
Merged

Sphere billboard (Impostor)#1037
maharshi-gor merged 13 commits intofury-gl:v2from
m-agour:sphere-billboard

Conversation

@m-agour
Copy link
Contributor

@m-agour m-agour commented Sep 28, 2025

Adding first billboard-based actor to Fury (based on #1036). It uses the lighing system and have depth almost as normal gemetry-based sphere. I put it under the sphere actor with a flag imposter (name is up to change).

Here is a super cool video of the super cool impostor:

2025-09-28.13-30-23.mp4

Update (fixed light direction; compare with previoue old video):

2025-09-29.15-44-19.mp4

it looks real to me

example:

import numpy as np
from fury import actor
from fury import window

centers = np.array([[0, 0, 0], [2, 0, 2], [-1, 0, 0]])
colors = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
radii = np.array([1.2, 1, 1])

billboard = actor.sphere(
    centers=centers, colors=colors, radii=radii, opacity=1, impostor=True
)
sphere = actor.sphere(
    centers=centers + np.array([[0, -2, 0]]), colors=colors, radii=radii, opacity=1
)

scene = window.Scene()
scene.add(billboard)
scene.add(sphere)

txt_billboard = actor.text(
    "Shader (billboard)", position=[-5, 0, 0], colors=(1, 1, 1), anchor="middle-right"
)
txt_sphere = actor.text(
    "Geometry-based", position=[-5, -4, 0], colors=(1, 1, 1), anchor="middle-right"
)
scene.add(txt_billboard)
scene.add(txt_sphere)

scene.add(actor.box(
    centers=np.array([[0, -2, 0]]), colors=(0.5, 0.5, 0.5), scales=(7, 0.1, 7)
))
scene.add(actor.box(
    centers=np.array([[0, 0, 0]]), colors=(0.5, 0.5, 0.5), scales=(7, 0.1, 7)
))

showm = window.ShowManager(
    scene=scene, size=(600, 600), title="Billboard Sphere Example"
)
showm.start()

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds billboard-based sphere impostor functionality to the Fury rendering library, providing a performance alternative to geometry-based spheres using shader techniques and camera-facing quads.

  • Implements billboard rendering system with WGSL shaders that always face the camera
  • Adds sphere impostor mode that renders 3D-looking spheres using 2D quads with ray-sphere intersection
  • Integrates billboard functionality into existing sphere actor with an impostor flag

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
fury/wgsl/billboard_sphere_render.wgsl WGSL shader for rendering sphere impostors with lighting and depth
fury/wgsl/billboard_render.wgsl Basic WGSL shader for camera-facing billboard quads
fury/tests/test_billboard.py Comprehensive test suite for billboard and sphere impostor functionality
fury/shader.py Billboard shader classes for rendering pipeline integration
fury/material.py Material classes for billboard and sphere impostor rendering
fury/actor/curved.py Modified sphere function to support impostor mode
fury/actor/billboard.py Core billboard implementation with factory functions
fury/actor/init.pyi Type stub updates for billboard exports

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines 87 to +122
scales = radii
directions = (1, 0, 0)

vertices, faces = fp.prim_sphere(phi=phi, theta=theta)
return actor_from_primitive(
obj = actor_from_primitive(
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable scales is set to radii but should be set to radii_arr for consistency with the processed array data used elsewhere in the function.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@maharshi-gor maharshi-gor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the work @m-agour !

Let's fix some simple changes in the sphere method.

@m-agour
Copy link
Contributor Author

m-agour commented Sep 30, 2025

Thank you for the work @m-agour !

Let's fix some simple changes in the sphere method.

Thank you @maharshi-gor, updated are made!

@Garyfallidis
Copy link
Contributor

Great work.
Double check front back coloring. Intersection seems working well.
Also animate and add example.
Figure out maximum number of spheres that can be rendered.

@m-agour m-agour force-pushed the sphere-billboard branch 2 times, most recently from fbc4532 to 882c804 Compare October 14, 2025 13:49
@skoudoro
Copy link
Contributor

What is the update on this @m-agour ? can you fix conflict and address Elef comments

@guaje
Copy link
Contributor

guaje commented Dec 12, 2025

@m-agour thanks for putting this together! Here are some comments/suggestions:

  • Could you rebase this branch?
  • Can you add a test for create_billboard_sphere?
  • Can you add a test for register_billboard_sphere_render_function?
  • Can you add a test for the sphere function in curved.py that tests impostor=True and impostor=False?

In addition to this, is there a way to merge or extend billboard_render.wsgl with Jinja templates or similar, so that we avoid the duplication of code in billboard_sphere_render.wsgl?

@m-agour m-agour force-pushed the sphere-billboard branch 2 times, most recently from e46ee44 to 327387a Compare January 26, 2026 15:34
@m-agour
Copy link
Contributor Author

m-agour commented Jan 26, 2026

Hi @maharshi-gor ready for review

Copy link
Contributor

@maharshi-gor maharshi-gor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this work @m-agour . Please look at the provided comments on the PR.

import numpy as np

from fury.actor import Mesh
from fury.actor.core import Mesh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from fury.actor.core import Mesh
from fury.actor import Mesh

Comment on lines +9 to +10

__all__ = ["billboard", "billboard_sphere", "Billboard"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
__all__ = ["billboard", "billboard_sphere", "Billboard"]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add them to __init__.pyi, Not required here.

stored on ``billboard_sizes`` and reused by shaders for impostor variants.
"""

pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make billbord_count, billboard_centers and billboard_sizes as properties in the Billboard actor so it stays consistent across. If someone tries to use BillBoard actor directly without _create_billboard_actor method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There a few more on the sphere actor, I would leave it to you how to best represent them. If you want the user to use those properties. They should be available in the object definition.

]

from .billboard import billboard
from .billboard import billboard, billboard_sphere # noqa: F401
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for #noqa: F401

Tuple containing the configured
:class:`~fury.shader.BillboardSphereShader`.
"""
from fury.shader import BillboardSphereShader
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not import like this. Move this import on top of the file.

@@ -126,3 +231,23 @@ def register_billboard_render_function(wobject):
from fury.shader import BillboardShader
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update here as well.

// Load color if available - colors are duplicated 6x like positions
let color = load_s_colors(billboard_index * 6);
varyings.color = vec4<f32>(color, 1.0);
varyings.texcoord_vert = vec2<f32>(tex_coord);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do we use it?

@m-agour
Copy link
Contributor Author

m-agour commented Feb 23, 2026

Hi @maharshi-gor, thanks for the review, I have them all addressed! also added impostor sphere to tru by default.

@m-agour
Copy link
Contributor Author

m-agour commented Feb 24, 2026

@m-agour thanks for putting this together! Here are some comments/suggestions:

  • Could you rebase this branch?
  • Can you add a test for create_billboard_sphere?
  • Can you add a test for register_billboard_sphere_render_function?
  • Can you add a test for the sphere function in curved.py that tests impostor=True and impostor=False?

In addition to this, is there a way to merge or extend billboard_render.wsgl with Jinja templates or similar, so that we avoid the duplication of code in billboard_sphere_render.wsgl?

Hi @guaje , sorry for the late response. I completely missed your review and that’s on me.
Thanks for the suggestions they’re helpful. I’m working through the tests you requested

@maharshi-gor
Copy link
Contributor

Thanks @m-agour for the great work. LGTM Merging!

@maharshi-gor maharshi-gor merged commit c6ba464 into fury-gl:v2 Feb 25, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants