AlloSphere-Research-Group / allolib

Library for interactive multimedia application development
BSD 3-Clause "New" or "Revised" License
36 stars 14 forks source link

Texture Point Sprite Example #17

Open kybr opened 5 years ago

kybr commented 5 years ago

I want to know how to do a cloud of points that obey perspective where each point is rendered as a texture. I've written this many times is the old system. It is a very common request from students.

However, I'm struggling to do this given the new system. In particular...

  1. I don't know whether the default shader system supports this use case. If it does, I don't know how to use it. I would assume, a) create a simple 16x16 pixel texture, b) create a point mesh, c) bind the texture, d) call g.texture() to use the default shader for textures, and e) win. But, this does not work for me.
  2. When I write my own shader, I have to use version 330 GLSL, so I adapted my shader which uses the old GLSL and fixed-pipeline "magic" variables. Again, I cannot get it to work for me, even though I think it should. I have something that compiles, but i don't see anything. Does one still need to call glEnable(GL_POINT_SPRITE) and glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE)??
  3. There is no example to follow that shows how to do this very, very common case.
  4. The "way" of doing graphics (i.e., default shaders concatenated as strings to cover common use cases) is still totally undocumented, so I (and others) are left to read the source and infer and deduce what might be the "right way" to use the default shader system.

Perhaps the "right way" to do a point sprite cloud is totally different than it used to be; Perhaps the "right way" is so radically different that I'm going about it all wrong. Perhaps I should be using instancing?

In any case, I need an example. Here's a non-texture-sprite cloud I wrote:

https://github.com/kybr/mat201b/blob/master/example/shader_point_cloud.cpp

Here's the current shader sprite example in AlloSystem

https://github.com/AlloSphere-Research-Group/AlloSystem/blob/devel/allocore/examples/graphics/shaderSprites.cpp

(Does it really have to use a geometry shader?)

kybr commented 5 years ago

Done. I added an example. I didn't end up adapting the AlloSystem example.

Please review examples/graphics/point-cloud-geometry-shader-texture-sprite.cpp for coding style, readability, efficacy, grammar, etc. Anything you see that might make this not a good example, please call it out.

I'm interested if there's a better way to do this, generally. Also, I'm not sure that depth and blending are configured correctly or in the best way.

LancePutnam commented 5 years ago

Hi Karl,

I think best practices these days say to avoid geometry shaders as they prevent certain optimizations. You can send four duplicate vertices per "point" and then offset them in the vertex shader using gl_VertexID. Make sure to include the following in your vertex shader:

version 120 // or greater

extension GL_EXT_gpu_shader4 : enable

This used to be so much easier with the fixed pipeline. I appreciate our modern programmable pipelines, but it seems like we've taken several steps backwards in terms of immediacy. Meanwhile, with general-purpose programming it's cool to be as high-level as possible.

Lance

On Thu, Nov 22, 2018 at 6:26 PM karl yerkes notifications@github.com wrote:

I want to know how to do a cloud of points that obey perspective where each point is rendered as a texture. I've written this many times is the old system. It is a very common request from students.

However, I'm struggling to do this given the new system. In particular...

  1. I don't know whether the default shader system supports this use case. If it does, I don't know how to use it. I would assume, a) create a simple 16x16 pixel texture, b) create a point mesh, c) bind the texture, d) call g.texture() to use the default shader for textures, and e) win. But, this does not work for me.
  2. When I write my own shader, I have to use version 330 GLSL, so I adapted my shader which uses the old GLSL and fixed-pipeline "magic" variables. Again, I cannot get it to work for me, even though I think it should. I have something that compiles, but i don't see anything. Does one still need to call glEnable(GL_POINT_SPRITE) and glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE)??
  3. There is no example to follow that shows how to do this very, very common case.
  4. The "way" of doing graphics (i.e., default shaders concatenated as strings to cover common use cases) is still totally undocumented, so I (and others) are left to read the source and infer and deduce what might be the "right way" to use the default shader system.

Perhaps the "right way" to do a point sprite cloud is totally different than it used to be; Perhaps the "right way" is so radically different that I'm going about it all wrong. Perhaps I should be using instancing?

In any case, I need an example. Here's a non-texture-sprite cloud I wrote:

https://github.com/kybr/mat201b/blob/master/example/shader_point_cloud.cpp

Here's the current shader sprite example in AlloSystem

https://github.com/AlloSphere-Research-Group/AlloSystem/blob/devel/allocore/examples/graphics/shaderSprites.cpp

(Does it really have to use a geometry shader?)

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/AlloSphere-Research-Group/allolib/issues/17, or mute the thread https://github.com/notifications/unsubscribe-auth/ABiB37d-8mlLHJaCN0Nf2X160z_HvBL5ks5uxuxlgaJpZM4YvxrC .

kybr commented 5 years ago

they prevent certain optimizations.

what optimizations? link?


so, the scheme for a point cloud might be to duplicate each point 3 times so there are 4 total per logical point, the use gl_VertexID % 4 to decide offsets?

thanks, Lance.

kybr commented 5 years ago

after a few minutes of trying... it seems like using gl_VertexID with a scheme to avoid a geometry shader (in this case) is a bit of work. i think i have to change the draw primitive to triangles or triangle strip and use an element/index array. and i notice that your example uses a geometry shader.

unless it truly ruins performance, i think that it's better to have a clear example that does use a GS rather than a more performant example that is considerably more complicated. still, it's even better to have both :)

grrrwaaa commented 5 years ago

Why can’t point sprites be used? Seems easier than geom shaders or instancing. Just draw with GL_POINTS, with the sprite texture bound. Set the size with gl_PointSize in the vert shader and you can use the gl_PointCoord in the frag shader to texture lookup if desired. At least, that’s what is supposed to work.

https://www.khronos.org/opengl/wiki/Primitive#Point_primitives

Graham

On Nov 23, 2018, at 4:33 PM, karl yerkes notifications@github.com wrote:

after a few minutes of trying... it seems like using gl_VertexID with a scheme to avoid a geometry shader (in this case) is a bit of work. i think i have to change the draw primitive to triangles or triangle strip and use an element/index array. and i notice that your example uses a geometry shader.

unless it truly ruins performance, i think that it's better to have a clear example that does use a GS rather than a more performant example that is considerably more complicated. still, it's even better to have both :)

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

LancePutnam commented 5 years ago

If you cannot use GL_QUADS, then you should be able to do the same with indexed triangles. I believe gl_VertexID will give you the actual index rather than the vertex number.

Googling geometry shader performance produces many results, e.g.

https://stackoverflow.com/questions/13189594/performance-difference-between-geometry-shader-and-vertex-shader http://www.joshbarczak.com/blog/?p=667

Basically, a GS affects the post transform cache ( https://www.khronos.org/opengl/wiki/Post_Transform_Cache). But as with most things, YMMV.

You can use regular GL_POINTS, but there are some cons to be aware of: https://stackoverflow.com/questions/17397724/point-sprites-for-particle-system

There is no point size attenuation and sprites get culled by their center point. I found the latter to be rather irritating once the sprites get larger.

Lance

On Sat, Nov 24, 2018 at 1:21 AM Graham Wakefield notifications@github.com wrote:

Why can’t point sprites be used? Seems easier than geom shaders or instancing. Just draw with GL_POINTS, with the sprite texture bound. Set the size with gl_PointSize in the vert shader and you can use the gl_PointCoord in the frag shader to texture lookup if desired. At least, that’s what is supposed to work.

https://www.khronos.org/opengl/wiki/Primitive#Point_primitives

Graham

On Nov 23, 2018, at 4:33 PM, karl yerkes notifications@github.com wrote:

after a few minutes of trying... it seems like using gl_VertexID with a scheme to avoid a geometry shader (in this case) is a bit of work. i think i have to change the draw primitive to triangles or triangle strip and use an element/index array. and i notice that your example uses a geometry shader.

unless it truly ruins performance, i think that it's better to have a clear example that does use a GS rather than a more performant example that is considerably more complicated. still, it's even better to have both :)

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/AlloSphere-Research-Group/allolib/issues/17#issuecomment-441335422, or mute the thread https://github.com/notifications/unsubscribe-auth/ABiB34YLQY4QLwhMxCLyLIIMjDWNacDMks5uyJ79gaJpZM4YvxrC .

grrrwaaa commented 5 years ago

Yes with GL_POINTS you have to do the size calculation yourself to set gl_PointSize in the vertex shader. The culling by center can also be fixed by assigning to glFragDepth in the fragment shader (this is what we did for Endless Current), but again, that requires doing some math based on the projection, and it adds some cost.

If that seems too much then I’d recommend instancing a square. In the long run learning instancing probably has more transferable benefit anyway.

Graham

On Nov 24, 2018, at 6:08 AM, Lance Putnam notifications@github.com wrote:

If you cannot use GL_QUADS, then you should be able to do the same with indexed triangles. I believe gl_VertexID will give you the actual index rather than the vertex number.

Googling geometry shader performance produces many results, e.g.

https://stackoverflow.com/questions/13189594/performance-difference-between-geometry-shader-and-vertex-shader http://www.joshbarczak.com/blog/?p=667

Basically, a GS affects the post transform cache ( https://www.khronos.org/opengl/wiki/Post_Transform_Cache). But as with most things, YMMV.

You can use regular GL_POINTS, but there are some cons to be aware of: https://stackoverflow.com/questions/17397724/point-sprites-for-particle-system

There is no point size attenuation and sprites get culled by their center point. I found the latter to be rather irritating once the sprites get larger.

Lance

On Sat, Nov 24, 2018 at 1:21 AM Graham Wakefield notifications@github.com wrote:

Why can’t point sprites be used? Seems easier than geom shaders or instancing. Just draw with GL_POINTS, with the sprite texture bound. Set the size with gl_PointSize in the vert shader and you can use the gl_PointCoord in the frag shader to texture lookup if desired. At least, that’s what is supposed to work.

https://www.khronos.org/opengl/wiki/Primitive#Point_primitives

Graham

On Nov 23, 2018, at 4:33 PM, karl yerkes notifications@github.com wrote:

after a few minutes of trying... it seems like using gl_VertexID with a scheme to avoid a geometry shader (in this case) is a bit of work. i think i have to change the draw primitive to triangles or triangle strip and use an element/index array. and i notice that your example uses a geometry shader.

unless it truly ruins performance, i think that it's better to have a clear example that does use a GS rather than a more performant example that is considerably more complicated. still, it's even better to have both :)

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/AlloSphere-Research-Group/allolib/issues/17#issuecomment-441335422, or mute the thread https://github.com/notifications/unsubscribe-auth/ABiB34YLQY4QLwhMxCLyLIIMjDWNacDMks5uyJ79gaJpZM4YvxrC .

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.