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

Custom vertex format support for ParticleFX components #7866

Merged
merged 36 commits into from Sep 8, 2023

Conversation

Jhonnyg
Copy link
Contributor

@Jhonnyg Jhonnyg commented Aug 7, 2023

Particle FX nodes can now utilise the custom vertex formats previously added to sprites. This enables you to pass custom data from the editor into shader attributes when rendering particles.

Fixes #7818

PR checklist

  • Code
    • Add engine and/or editor unit tests.
    • New and changed code follows the overall code style of existing code
    • Add comments where needed
  • Documentation
    • Make sure that API documentation is updated in code comments
    • Make sure that manuals are updated (in github.com/defold/doc)
  • Prepare pull request and affected issue for automatic release notes generator
    • Pull request - Write a message that explains what this pull request does. What was the problem? How was it solved? What are the changes to APIs or the new APIs introduced? This message will be used in the generated release notes. Make sure it is well written and understandable for a user of Defold.
    • Pull request - Write a pull request title that in a sentence summarises what the pull request does. Do not include "Issue-1234 ..." in the title. This text will be used in the generated release notes.
    • Pull request - Link the pull request to the issue(s) it is closing. Use on of the approved closing keywords.
    • Affected issue - Assign the issue to a project. Do not assign the pull request to a project if there is an issue which the pull request closes.
    • Affected issue - Assign the "breaking change" label to the issue if introducing a breaking change.
    • Affected issue - Assign the "skip release notes" is the issue should not be included in the generated release notes.

Comment on lines -330 to -344
(defn vertex-overlay
"Use a vertex layout together with an existing ByteBuffer. Returns a vertex buffer suitable
for the `use-with` function.

This will assume the ByteBuffer is an integer multiple of the vertex size."
[layout ^ByteBuffer buffer]
(assert layout)
(assert (= 0 (mod (.limit buffer) (:vertex-size layout))))
(let [^ByteBuffer buffer (.duplicate buffer)
limit (.limit buffer)
count (mod limit (:vertex-size layout))
buffer-starts (buffer-starts limit layout)
slices (b/slice buffer (map min (repeat limit) buffer-starts))]
(->PersistentVertexBuffer layout count buffer slices (AtomicLong. count) not-allowed not-allowed)))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No used anywhere now

Comment on lines 108 to 113
uint32_t buffer_size = dmParticle::GetVertexBufferSize(ctx->m_MaxParticleCount, dmParticle::PARTICLE_GO);
// position : 3
// color : 4
// texcoord0 : 2
// page_index : 1
const uint32_t default_vx_size = sizeof(float) * (3 + 4 + 2 + 1);
const uint32_t buffer_size = ctx->m_MaxParticleCount * 6 * default_vx_size;
world->m_VertexBufferData.SetCapacity(ctx->m_MaxParticleCount * 6 * default_vx_size);
Copy link
Contributor Author

@Jhonnyg Jhonnyg Aug 16, 2023

Choose a reason for hiding this comment

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

We don't have any particle "formats" now, the size of the vx buffer is only dependent on the vertex size.

Comment on lines +32 to +37
obj = bld.stlib(features = obj.features + ['skip_asan'],
includes = obj.includes,
source = bld.path.ant_glob(['graphics_proto.cpp']) + bld.path.parent.ant_glob('proto/graphics/*'),
protoc_includes = obj.protoc_includes,
use = obj.use,
target = 'graphics_proto_noasan')
Copy link
Contributor Author

@Jhonnyg Jhonnyg Aug 28, 2023

Choose a reason for hiding this comment

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

Particle now depends on graphics being built first, since we use data structures from that library when producing particles.

Comment on lines 1070 to 1080
case dmGraphics::VertexAttribute::SEMANTIC_TYPE_COLOR:
{
if (info.m_NameHash == VERTEX_STREAM_COLOR)
{
memcpy(write_ptr, &color, info.m_ValueByteSize);
}
else
{
memcpy(write_ptr, info.m_ValuePtr, info.m_ValueByteSize);
}
} break;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As previously mentioned, we need to know if the stream has the name "color" or not, if that is the case we output out the particle color and otherwise we put the binary value from the actual attribute.

Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this true for the other cases?
If the user set a POSITION or TEXCOORD attribute with name "extra", it will get the predefined position/uv values.
Or isn't is allowed, and should that a build error?

Also, do we want to look at the type?
E.g. if the user really wants to use a single uint32_t instead of float4 for color for bandwidth.

Later, I also feel this "write logic" should be standardized/centralized somehow.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah that's true I suppose. The problem I ran into was that the "color" semantic is the only one that has any value in the editor since we decorate the property with a color widget. So the way we had originally setup the semantic types means that I can't decorate an attribute with a color widget, but maybe that's fine and should be a separate "edit type" value or something.. But yes, if we are to conform these vertex writing functions into a shared location I think we should produce the built-in data based on the semantic types.

Also, do we want to look at the type?
E.g. if the user really wants to use a single uint32_t instead of float4 for color for bandwidth.

Do you mean with the built-in semantic types? Because the data produced from the content pipeline is narrowed or expanded to the correct type, but the built-in types are not. For the built-in types we need to do data conversion between the floats (it's all float streams I think?) into whatever format. I think we should do it, but I'd rather try to get this PR in first and then take a stab at merging the vertex writing function in a separate PR.

Comment on lines +1281 to +1292
Vector3 p0_local;
Vector3 p1_local;
Vector3 p2_local;
Vector3 p3_local;

if (use_local_position)
{
p0_local = -x - y;
p1_local = -x + y;
p2_local = x - y;
p3_local = x + y;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These will only be used if there is a stream with position_local semantic being used.

Comment on lines -1283 to +1333
const char* config_key = MAX_PARTICLE_COUNT_KEY;

if (format == PARTICLE_GUI)
config_key = "gui.max_particle_count";

dmLogWarning("Maximum number of particles (%d) exceeded, particles will not be rendered. Change \"%s\" in the config file.", context->m_MaxParticleCount, config_key);
res = GENERATE_VERTEX_DATA_MAX_PARTICLES_EXCEEDED;
Copy link
Contributor Author

@Jhonnyg Jhonnyg Aug 29, 2023

Choose a reason for hiding this comment

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

Each component has to deal with the error by themselves, since we don't know the source of what's being generated.

@Jhonnyg Jhonnyg added the feature request A suggestion for a new feature label Aug 29, 2023
@Jhonnyg Jhonnyg changed the title Issue 7818 custom vertex formats particlefx Custom vertex format support for ParticleFX components Aug 29, 2023
Comment on lines +2154 to +2160
if (ix >= context->m_AttributeDataPtrs.Capacity())
{
void* new_ptr = malloc(ATTRIBUTE_WRAPPER_SIZE);
context->m_AttributeDataPtrs.OffsetCapacity(1);
context->m_AttributeDataPtrs.Push(new_ptr);
return new_ptr;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to retain the same pointers between every simulation step, which other expanding array solutions will not guarantee, and I don't think we want to preallocate a large array for this since the scratch buffer approach is ONLY for the editor.

@Jhonnyg Jhonnyg requested review from JCash and matgis August 29, 2023 21:28
@Jhonnyg Jhonnyg marked this pull request as ready for review August 29, 2023 21:28
Copy link
Contributor

@matgis matgis left a comment

Choose a reason for hiding this comment

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

Found some minor niggles on the editor side, but they shouldn't be a lot of effort to fix!

editor/src/clj/editor/particle_lib.clj Outdated Show resolved Hide resolved
editor/src/clj/editor/particlefx.clj Outdated Show resolved Hide resolved
editor/src/clj/editor/graphics.clj Outdated Show resolved Hide resolved
editor/src/clj/editor/graphics.clj Outdated Show resolved Hide resolved
editor/src/clj/editor/graphics.clj Outdated Show resolved Hide resolved
editor/src/clj/editor/particle_lib.clj Outdated Show resolved Hide resolved
context (:context pfx-sim)
vbuf (vtx/wrap-vertex-buffer vertex-description :static raw-vbuf)
all-raw-vbufs (vset (:raw-vbufs pfx-sim) emitter-index raw-vbuf)]
(swap! pfx-sim-atom assoc :raw-vbufs all-raw-vbufs)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm a bit annoyed that we have to do it like this because the vertex-description is not available until we have a GL context to compile the shaders with.

Perhaps in the future we could get the information from the output of the SPIR-V compiler and prepare the buffers before rendering?

Oh well. Some day...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, it makes things more complicated for sure... But hm, I'll add a note about this for now and it will have to be a headache for the future I guess 🤷

editor/src/clj/editor/sprite.clj Outdated Show resolved Hide resolved
Copy link
Contributor

@JCash JCash left a comment

Choose a reason for hiding this comment

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

Mainly the assert in the editor only C++ code needs attention.

Also some questions that may warrant some clarifications.

engine/gamesys/src/gamesys/components/comp_gui.cpp Outdated Show resolved Hide resolved
@@ -1060,7 +1081,7 @@ namespace dmGameSystem
dmGui::NodeType node_type = dmGui::GetNodeType(scene, first_node);
assert(node_type == dmGui::NODE_TYPE_PARTICLEFX);

uint32_t vb_max_size = dmParticle::GetMaxVertexBufferSize(gui_world->m_ParticleContext, dmParticle::PARTICLE_GUI) - gui_world->m_RenderedParticlesSize;
uint32_t vb_max_size = dmParticle::GetMaxVertexBufferSize(gui_world->m_ParticleContext, sizeof(ParticleGuiVertex)) - gui_world->m_RenderedParticlesSize;
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what the best way is to define the particle budget now.
Previously it was bytes, but now that we can support multiple materials with different vertex formats, it might be relevant to think of #particles.
🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

The usage of the sizeof(ParticleGuiVertex) seems a little strange now. Perhaps add a comment or two to show that the size is an estimate, and that the code is works ok?

E.g. the vertex count relies on that size

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure what the best way is to define the particle budget now.
Previously it was bytes, but now that we can support multiple materials with different vertex formats, it might be relevant to think of #particles.
🤔

What budget are you referring to here? Both the GUI and the particle settings specify particle count (and components)

image

The usage of the sizeof(ParticleGuiVertex) seems a little strange now. Perhaps add a comment or two to show that the size is an estimate, and that the code is works ok?

E.g. the vertex count relies on that size

But for GUI the size isn't an estimate, it is what is allocated regardless of what material is used 🤔 this is because we don't support any custom vertex formats in GUI right now, so we don't use the configuration from the material.

engine/gamesys/src/gamesys/components/comp_particlefx.cpp Outdated Show resolved Hide resolved

uint32_t ro_vertex_count = vb_end - vb_begin;
vertex_buffer.SetSize(vb_end - vertex_buffer.Begin());
vertex_buffer.SetSize(vb_size);
Copy link
Contributor

Choose a reason for hiding this comment

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

It's not a new pattern in the engine, but I think as communications go, we could make it clearer that between the SetCapacity() and SetSize() the array size is 0 and it's not really ok to write to the memory.

E.g. this could be changed to:

SetCapacity(max_size);
SetSize(max_size);

new_size = ...do work;

SetSize(new_size);

It's not a big deal in this case, but I recall having to change other places where that logic becomes problematic.

Comment on lines 1070 to 1080
case dmGraphics::VertexAttribute::SEMANTIC_TYPE_COLOR:
{
if (info.m_NameHash == VERTEX_STREAM_COLOR)
{
memcpy(write_ptr, &color, info.m_ValueByteSize);
}
else
{
memcpy(write_ptr, info.m_ValuePtr, info.m_ValueByteSize);
}
} break;
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this true for the other cases?
If the user set a POSITION or TEXCOORD attribute with name "extra", it will get the predefined position/uv values.
Or isn't is allowed, and should that a build error?

Also, do we want to look at the type?
E.g. if the user really wants to use a single uint32_t instead of float4 for color for bandwidth.

Later, I also feel this "write logic" should be standardized/centralized somehow.

engine/particle/src/particle.cpp Outdated Show resolved Hide resolved
engine/particle/src/particle.cpp Outdated Show resolved Hide resolved
@Jhonnyg Jhonnyg merged commit ebc50ab into dev Sep 8, 2023
22 checks passed
@Jhonnyg Jhonnyg deleted the issue-7818-custom-vertex-formats-particlefx branch September 8, 2023 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request A suggestion for a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Custom vertex formats (particlefx support)
3 participants