update.BetterPoints - tooll3/t3 GitHub Wiki
Over the last couple of years, Tooll's Point structure has become a fundamental building block among many compute shaders. For performance reasons, we decided early on to limit its content to the following attributes:
Vec3 Position
Quaternion Rotation
float W
Through the combination of Position and a Quaternion, it represents a valid reference coordinate system in space and can be used for mesh or point instantiation. The magic "W" attribute can stand for Width, Size, Age, Selection, etc.
However, many users eventually desired additional attributes like Color and to separate Selection from Size. Due to nVidia's 16-byte alignment, we're very hesitant to adjust the original structure. Doubling the memory footprint and bandwidth, and complicating all Point-shaders by copying and handling attributes they probably don't need.
While implementing the new particle system, I encountered a challenge. In initial experiments, I attempted to encode particle velocity within the normalized quaternion. Though theoretically viable, it proved awkward, limiting, and too much of a hack. In the final implementation, we introduced a new Particle-structure with additional attributes for Velocity and particle age. Surprisingly, this didn't significantly impact performance. Early measurements on Nvidia GTX2070 Max-Q and GTX2080 Super showed that the particle system (including the copy) accounted for only about 10% of the overall performance. 90% was dedicated to drawing the points as billboards or lines. Altering the render target resolution or MSAA samples from 2, 4, or 8 had a greater impact than changing the data structure size.
Simulating 10 million points was much easier than actually drawing them.
After lengthy consideration, I finally embarked on changing the point structure and updating all Point shaders. In this effort, I also ensured consistency in attribute titles and grouping, as well as naming of helper functions. Let's delve into the changes in detail.
The new Point and Particle structures look like this:
struct Point
{
float3 Position;
float W;
float4 Rotation;
float4 Color;
float3 Extend;
float Selected;
};
struct Particle
{
float3 Position;
float Radius;
float4 Rotation;
float4 Color;
float3 Velocity;
float BirthTime;
}
Both structures share the same memory layout. However, in particle simulation, the meaning of Extend
and Selected
changes. In upcoming versions, Extend
could define bounding box regions for scaled Mesh instancing or other effects.
Initially, we're focusing on updating all Shaders and effects with emphasis on backward compatibility. Fortunately, we have many old demo projects like "There" and "Works for Everybody" that heavily rely on points. Ensuring these projects functioned as before allowed us to test each shader thoroughly.
The most significant change for all compute shaders is adjusting the stride of structure buffers to 64 bytes:
The next major change is ensuring correct assignment and copying of new attributes when creating new buffers. This could be achieved through methods like:
ResultPoints[i.x].Position = newW;
ResultPoints[i.x].Position = p.xyz;
ResultPoints[i.x].Rotation = newRotation;
ResultPoints[i.x].Color = SourcePoints[i.x].Color;
ResultPoints[i.x].Selected = SourcePoints[i.x].Selected;
ResultPoints[i.x].Extend = SourcePoints[i.x].Extend;
or
TrailPoints[targetIndex] = SourcePoints[sourceIndex];
or
Point p = SourcePoints[i.x];
// do something with p...
ResultPoints[i.x] = p;
At first glance, this appears to introduce a lot of overhead. Therefore, I was genuinely concerned about the performance impact of this change. Initial measurements indicated a performance impact of 5-10%, but of course, this varies depending on the use case. As far as I can discern, there is no noticeable change in complex projects like "Works for Everybody" or "There", which is a significant relief.
So, how do we get colored points? We started with a few obvious methods:
- [APoint] now has a Color parameter.
- [LinePoints] now has two color parameters: A and B.
- [LoadObjAsPoints] now uses the color attribute (instead of an awkward rotation hack).
- [SetPointAttributes] can override the color. Note that we renamed the previous version of that operation to [SpreadPointAttribute] to clarify its purpose.
- [SpreadPointAttribute] got a new Gradient parameter that can be used to colorize points depending on their position within the buffer.
In later updates, many more operators will receive color attributes. If you have any suggestions, don't hesitate to leave a comment on Discord or create a feature request issue on GitHub.
We began with the obvious choices:
- [DrawPoints], [DrawPointsShaded], [DrawLines], [DrawBillboards], and [DrawMeshAtPoints] will all apply the point color by default:
Since the default color is white, this should not break existing projects!
- Stabilize: This change affected several hundred files, so I expect minor glitches to pop up here and there.
- Consolidate Selection: We have many operators that use the W parameter to define a selection state. We want to adjust this to use the dedicated Selected property instead of overriding the W attribute, which normally holds information like the Size or Width of an object.
- More Colors: Many operators like [RandomizePoints] or [SamplePointAttributes] should support adding point colors.
-
More Features: We have ideas for special operators like colorized text and better [Sketch]ing. Especially, the
Extends
will open a lot of potential for advanced inter-point effects and modifiers.
Considering it, it's quite impressive that we can modify such an intrinsic feature without breaking existing projects or adding a completely parallel set of operators. So, let's infuse some colors! As always, we're eager to hear your feedback on Discord.