P5 point cloud with textures

is there a way to map a texture of a obj on points that i create in p5 with beginShape(POINTS). i would like that the user is able to load a texture alongside a .obj and it will map the colors of the texture accurately on the points.

Quick followup question – can anyone explain why drawing a pointcloud with beginShape(POINTS) + vertex(....) + endShape() is sooooo much faster to render, then looping through the vertices and drawing a point() with individual stroke color per point?? Is there a good alternative to render a point cloud with RGB points? does it require a shader or new p5 geom tricks?

Calling point() renders a piece of geometry. Calling point() a million times in a loop renders a million pieces of geometry.

Calling beginShape()endShape() sets up a buffer, fills it with geometry and then renders it all with a single, efficient, graphics call.

stroke() (and fill()) is a somewhat messy function. Because Processing supports multiple color modes with user-chosen number ranges, each call to stroke() has to check what mode it’s in and do the appropriate math to convert from your number range to the hardware-native color range.

By far, the most efficient way to render a cloud of points with a texture is using a shader, though that requires you to figure out the texture uv-mapping yourself for each point.

2 Likes

I don’t think there’s an easy way to do this for POINTS just yet. For regular fills/strokes, you can change the color between each vertex() call, but that seems to not be working for points (worth filing a bug report for, if you’re interested!)

So to explore some alternative solutions: one could be to switch from points to tiny meshes, and then applying a color to each one. This could be either via calling fill() before drawing the triangles, or by giving it texture coordinates in each vertex() call that maps to your imported texture. Here’s a quick example that does that with triangles, but to make it look better from different orientations, you might want to consider doing a tetrahedron or something more 3D. The tradeoff being, it’ll look better with more triangles, but will run slower.

This has to do with batching: drawing with beginShape/endShape does it all in one go, while separate points have back-and-forth between the CPU and GPU for each one. On many systems, that back-and-forth is a much bigger bottleneck than the actual rendering. Based on that, if your data doesn’t change much, I’d recommend putting it in a p5.Geometry, which stores its data on the GPU so that there’s no back and forth after the first render. This might also allow you to use more vertices per point too, compared to the beginShape/endShape approach, or use a sphere as each point. Take a look at the last example in the buildGeometry reference for how to draw a bunch of spheres at different points, saved to a p5.Geometry for performance.

2 Likes

Thanks @scudly + @davepagurek for the quick replies! Indeed a shader is likely what’s needed for handling most point clouds, but curious what can be done within the p5 friendly domain. Thanks for the clarifications as to why point() is slow and sounds like buildGeometry() could be a nice approach, however a big part of their plan is to offset/warp the position of points, so a ‘fixed’ shape/model maybe doesn’t work. While trying out, found a potential issue with point() within buildGeometry()? Also just filed an issue about beginShape(POINTS) not using the given stroke(), since it does work great with LINES and TRIANGLES = could of course make hacky short lines… = aha, hacky works!

1 Like

That could potentially be done in a shader too if you’re interested! By modifying the positions in a shader using something like the last example here, you could end up with something like this (but, in the process, I noticed that stroke colors seem to be not saving correctly in p5.Geometry, so… maybe this approach is best saved for later :sweat_smile:)

For now, no shaders necessary but neat to see what’s possible and now part of 2.0 (baseStrokeShader is wild). In the end, the hack above of using LINES that appear as dots seems to be a viable solution.

Can you help me set up a shader for this? or where do i have to look?

I also saw I think a post from you on Reddit, here’s the answer I left there for continuity:

Here’s a demo that animates points with a shader: Point shader demo by davepagurek -p5.js Web Editor

We don’t have a point shader yet, so the approach I took was:

  • Make each point out of tiny strokes
  • Cache all the strokes in a p5.Geometry so that each frame updates fast
  • Make a stroke shader that animates each point

The main downside of this is that you can only animate each point based on its position, since there isn’t really any other way to identify points here. That could be all you need though!

@davepagurek - we just had a look at your example (thanks for that!) and attempted to set the color within the shader, but unfortunately they are ‘static’ and the same across all points. Do you have a suggestion of how to treat each one separately? Implemented by just adding the following for a quick test, expecting it to be wild colors:

getWorldInputs((inputs) => {
      inputs.color.r = Math.random();
      inputs.color.g = Math.random();
      inputs.color.b = Math.random();
      inputs.position.x += warpScale * sin(t * 0.001 + inputs.position.y * 0.05)
      
      return inputs
    })

Aha - just figured out a hack – just placing an image/texture over all the points with blendMode(MULTIPLY) to colorize our view of all the points.. perhaps a simplest approach, to then use any source as overlay.

1 Like

I think the main issue with your snippet is that we don’t yet support random() within a shader (follow along here if you’re interested in progress on that! [p5.strands] Bridging p5.strands and p5.js functions · Issue #7849 · processing/p5.js · GitHub)

So if you want something random per vertex, you may need to write your own randomizer based on the x,y,z position of each point. E.g. if you add enough sins and coses together, you’ll get something looking fairly random. Here’s a demo of that (using a one-liner random function from github): Point shader demo copy by davepagurek -p5.js Web Editor The main downside here is that because it’s based on the x, y, and z values of the point and I’ve made the points out of lines, the two halves of the line get colored differently. So you maybe want to do something to round the y values to avoid that.

1 Like

Aha, that explains why attempts of random etc weren’t working… yeah, I’m not at all versed in shaders, so I backed away towards other solutions. The previous hack using beginShape(LINES) seemed good, but struggled once getting up to 10,000+ vertices. Using POINTS doesn’t have the same issue, so for simplicity sake (and using wild textures) – this overlay hack is probably best. Nevertheless, will stay tuned for progress mentioned above. thanks!