reckfellENGINE

Particle emission from points and normals

Mesh extraction, float data, point colors and DirectedPoints.

On this page

Use Points when a particle should be born at one of a finite set of local positions; use DirectedPoints when each position also supplies an orientation normal. These are data textures, not an albedo image, a normal map for surface lighting or a live link to a mesh.

Generate points from a mesh in the editor

The following labels are from the 1.0.0 source; this pass does not claim a physical UI test.

  1. Configure GPUParticles3D with a ParticleProcessMaterial and a draw mesh first.
  2. Add or locate a MeshInstance3D with actual face geometry. The generator selects one mesh instance per operation, not an arbitrary Entity hierarchy.
  3. Select the particle emitter and use its contextual menu Create Emission Points From Entity.
  4. Select the source MeshInstance3D, then choose the number of samples and mode: Surface Points, Surface Points+Normal (Directed) or Volume.
  5. Generate, save and restart a controlled effect to inspect the distribution and direction. Check the material resource is not unintentionally shared with another effect.

Surface sampling weights usable triangles by area. The volume mode uses an approximate intersection-based generator; inspect open, concave or hollow meshes rather than assuming it samples every interior correctly. Degenerate/empty face geometry cannot supply useful surface points.

The generator transforms the mesh into emitter-local coordinates. Generated points are a snapshot of geometry/relative transforms, not a deforming-mesh attachment. Regenerate after changing the relationship or source geometry when you need a new distribution. Moving the resulting emitter is separate from regenerating data; LocalCoords controls how live particles follow it.

More sample positions improve the available distribution, not automatically the particle count/density. Amount and emission settings remain separate.

Pack data deliberately

PropertyContent
EmissionPointTextureXYZ position per texel; use float data to preserve negative coordinates and range.
EmissionNormalTextureXYZ direction per matching texel for DirectedPoints. Use valid nonzero normals, normally normalized; not an RGB-encoded surface normal map.
EmissionColorTextureOptional color per matching texel; multiplies process color and other color sources.
EmissionPointCountNumber of valid sample entries to select from. Not particle Amount and not a request to generate missing data.

The shader indexes positions in row-major order and reuses the position texture's coordinate for the normal/color textures. Keep their layouts consistent. A generated texture can contain padding; PointCount should describe valid samples, not every padded texel. Do not increase it beyond your valid data. Use a positive count when sampling Points/DirectedPoints.

Do not store XYZ positions or signed normals in a lossy/8-bit color workflow. Do not apply sRGB conversion to their components. The example creates float ImageTextures directly, avoiding an import step.

Create two colored points in C#

C#
using Reckfell;

public static class ParticlePointMaterial
{
    private static ImageTexture Data(Vector3 first, Vector3 second)
    {
        using var image = Image.CreateEmpty(2, 1, false, Image.Format.Rgbaf);
        image.SetPixel(0, 0, new Color(first.X, first.Y, first.Z, 1));
        image.SetPixel(1, 0, new Color(second.X, second.Y, second.Z, 1));
        return ImageTexture.CreateFromImage(image);
    }

    public static ParticleProcessMaterial Create(bool directed = false)
    {
        return new ParticleProcessMaterial
        {
            EmissionShape = directed
                ? ParticleProcessMaterial.EmissionShapeEnum.DirectedPoints
                : ParticleProcessMaterial.EmissionShapeEnum.Points,
            EmissionPointCount = 2,
            EmissionPointTexture = Data(new Vector3(-0.65f, 0, 0), new Vector3(0.65f, 0, 0)),
            EmissionNormalTexture = Data(Vector3.Left, Vector3.Right),
            EmissionColorTexture = Data(new Vector3(1, 0, 0), new Vector3(0, 0, 1)),
            // In the directed frame, local +Z corresponds to the stored normal.
            Direction = Vector3.Back,
            Spread = 0,
            InitialVelocityMin = directed ? 1f : 0f,
            InitialVelocityMax = directed ? 1f : 0f,
            Gravity = Vector3.Zero,
        };
    }
}

Assign ParticlePointMaterial.Create() to an existing emitter's ProcessMaterial. Give it enough Amount to sample both positions, a visible draw mesh, fixed seed for a controlled comparison and an AABB covering the points plus motion. On the mesh's standard material, enable VertexColorUseAsAlbedo and use white AlbedoColor; otherwise the per-point colors can be absent or tinted.

The executed test uses Amount 64 with only two sample points. Setting EmissionPointCount to 1 selects only the first valid slot without changing Amount. Two samples do not mean only two particles can be alive: many can overlap at each location.

Create(directed: true) sets a normal for each point, zero Spread and base Direction +Z (Vector3.Back). In this implementation's directed frame, that local axis follows the stored normal, so the test's left/right normals produce outward motion. Normals orient a frame; arbitrary base directions, spread and forces need not all move directly along the normal.

Change layout without confusing scale

EmissionShapeScale scales the local birth positions; EmissionShapeOffset is then added. This differs from ScaleMin/Max, which scale the drawn particle geometry. The native test halves point separation using shape scale, then enlarges particle geometry independently using material scale.

Retest the full VisibilityAabb after layout/velocity changes. A point texture does not automatically update the emitter culling bound. Editing a source mesh does not automatically rewrite your programmatically created ImageTexture either.

Diagnose broken distributions

SymptomCheck
All particles appear at/near the originValid PointCount and float position data; padded/zero texels or clamped negative coordinates.
Colors are missing or all whiteMatching color layout, process Color and surface VertexColorUseAsAlbedo.
One color disappearsMultiplication by process/surface color, not only the texture file.
Directed particles move sidewaysNormal data plus base Direction, Spread and velocity. The normal alone does not create speed.
The sampled mesh changed but emission did notRegenerate the snapshot or explicitly update the data resource.
Effect disappears after moving points outwardVisibilityAabb and camera/layers, not just source textures.

Runtime validation covers the two-point float data path, matching colors, count/capacity separation, directed normals, shape transforms and associated material tests on Windows Forward+/Vulkan. Editor extraction, volume sampling and every import/device/export path are source-reviewed or untested, not claimed end-to-end here. Continue with process material controls.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.