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

Weird line rendering with a long line where relatively few points have a high alpha value #419

Closed
kushalkolar opened this issue Jan 3, 2023 · 6 comments · Fixed by #421
Labels
bug Something isn't working

Comments

@kushalkolar
Copy link
Contributor

For example in this video the length of each of these lines (left to right) is 8410, and only a few points along the line have high alpha values. The artifact is that arrows appear at the edges of the where the colors fade out (could it be an interpolation thing?).

weird_line-2023-01-03_00.39.34.mp4

The lines are instantiated like this:

pygfx.LineMaterial

pygfx.Line(
  geometry=pygfx.Geometry(positions=<[8410, 3]>, colors=<[8410, 4]),
  material=material(thickness=20, vertex_colors=True)
)

I tried adjusting the camera near and far planes but it doesn't make a difference. GPU is an nvidia RTX 3090, OS is Debian 11, vulkaninfo seems fine.

Anyways the purpose is to use color intensity of a very long line that represents timepoints to indicate the magnitude of a quantitative variable, not sure if it's possible to do this with a simple Mesh instead if that's better than a Line?

image

@panxinmiao
Copy link
Contributor

It looks like an interpolation problem.
Since gfx does not disclose the API for "changing vertex attribute interpolation method" at present, I think you can consider storing colors in the texture and using the nearest mode to sample.

In this case, the code may look like this:

positions = <[8410, 3]>
colors = <[8410, 4]>
texcoords = <[8410]>

tex = gfx.Texture(colors, dim=1)
view = tex.get_view(address_mode="repeat", filter="nearest")

gfx.Line(
    gfx.Geometry(positions=positions, texcoords=texcoords),
    gfx.LineMaterial(thickness=20, map=view),
)

Hopes this can help you.

@panxinmiao
Copy link
Contributor

I did a test.

There is a bug at present. see: #420

And, there is another limitation: the maximum width and height of the texture is 8192, 😅

The whole test code:

import numpy as np
import random
from wgpu.gui.auto import WgpuCanvas, run
import pygfx as gfx


canvas = WgpuCanvas()
renderer = gfx.WgpuRenderer(canvas)

scene = gfx.Scene()
positions = []
colors = []
texcoords = []

for i in range(8192):
    positions.append([i, 0, 0])
    texcoords.append(i)
    r = random.random()
    if r > 0.9:
        colors.append([0.0, 1.0, 0.0, 1.0])
    else:
        colors.append([0.0, 1.0, 0.0, 0.0])


tex = gfx.Texture(np.array(colors, dtype=np.float32).reshape(8192, 4), dim=1)
view = tex.get_view(address_mode="repeat", filter="nearest")

line = gfx.Line(
    gfx.Geometry(positions=positions, texcoords=texcoords),
    gfx.LineMaterial(thickness=20.0, map=view),
)
scene.add(line)

camera = gfx.OrthographicCamera(600, 500)
camera.position.set(300, 0, 0)

controller = gfx.PanZoomController(camera.position.clone())
controller.add_default_event_handlers(renderer, camera)


def animate():
    controller.update_camera(camera)
    renderer.render(scene, camera)


if __name__ == "__main__":
    canvas.request_draw(animate)
    run()

I'm not sure if this result is what you want.

@almarklein
Copy link
Collaborator

I can reproduce a similar effect using this minimal example:

import numpy as np
from wgpu.gui.auto import WgpuCanvas, run
import pygfx as gfx


canvas = WgpuCanvas()
renderer = gfx.WgpuRenderer(canvas)

scene = gfx.Scene()

x = np.linspace(0, 100, 8410)

positions = np.zeros((x.size, 3), np.float32)
positions[:, 0] = x

colors = np.zeros((x.size, 4), np.float32)
colors[:, 0] = 1
colors[::10, 3] = 1

line = gfx.Line(
    gfx.Geometry(positions=positions, colors=colors),
    gfx.LineMaterial(vertex_colors=True),
)
scene.add(line)


camera = gfx.OrthographicCamera(110, 10)
camera.position.set(50, 0, 0)
controller = gfx.PanZoomController(camera.position.clone())
controller.add_default_event_handlers(renderer, camera)



def render_scene():
    controller.update_camera(camera)
    renderer.render(scene, camera)

if __name__ == "__main__":
    canvas.request_draw(render_scene)
    run()

@almarklein
Copy link
Collaborator

I think this is simply an aliasing issue. You have 8410 points, in a window that's about 800 pixels wide. So you have about 10 points on the line at each pixel. The point on the line being sampled is thus subject to a high degree of aliasing.

There is not much we can do from the point of view of Pygfx. You'd get similar aliasing when visualizing a highly detailed mesh model when zoomed out. I'd try and see if you can use a line with (much) less points.

If the effect that you were observing is different from what I think it is, could you provide a minimal example to reproduce it?

@kushalkolar
Copy link
Contributor Author

kushalkolar commented Jan 5, 2023

import numpy as np
from wgpu.gui.auto import WgpuCanvas, run
import pygfx as gfx


canvas = WgpuCanvas()
renderer = gfx.WgpuRenderer(canvas)

scene = gfx.Scene()

x = np.linspace(0, 100, 8410)

positions = np.zeros((x.size, 3), np.float32)
positions[:, 0] = x

colors = np.zeros((x.size, 4), np.float32)
colors[:, 0] = 1
colors[::10, 3] = 1

line = gfx.Line(
    gfx.Geometry(positions=positions, colors=colors),
    gfx.LineMaterial(vertex_colors=True),
)
scene.add(line)


camera = gfx.OrthographicCamera(110, 10)
camera.position.set(50, 0, 0)
controller = gfx.PanZoomController(camera.position.clone())
controller.add_default_event_handlers(renderer, camera)



def render_scene():
    controller.update_camera(camera)
    renderer.render(scene, camera)

if __name__ == "__main__":
    canvas.request_draw(render_scene)
    run()

If I set thickness=20 I can reproduce it with the arrows:

image

Is there a way to alter aliasing at the WGPU level? I'll look into how to set aliasing options for nvidia on debian.

panxinmiao, yup I noticed the texture limit in #360

@almarklein
Copy link
Collaborator

Ah, I can see what you mean when I set a higher thickness. This is not antialiasing but a glitch that seems to occur in straight parts of the line. It also occurs when zoomed in a lot (passed where antialiasing could be the cause). I just made the line a sine wave, and then the triangles only occur at the inflection points (where the line is briefly straight). Looking for a fix ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants