New weird behavior of the particleSystem since the last 12h

Good morning,

I quickly wanted to inform you about my latest issue with #particleSystem. I was using the preview version of 'babylon.js’ in my project as of yesterday evening (12h ago). But this morning, I had to roll back to cdn because of this new weird behavior of my particles (see screenshot - to the left the actual preview, to the right the actual cdn).

My particles are now sort of ‘constrained’ in some undetermined manner. At first, I thought there might have been a change in measurements (of the emitter, of lifetime or anything like that) but for whatever input/property I tried to change in the inspector, got just about no result. I don’t really have time to investigate on this (nor would I have the skills probably;) but I’d rather have the actual (cdn) version persist/'hold-‘on’ for the release of my project. I wouldn’t be very happy if I had to redo all my handling of #particleSystem… Thanks for taking a look at it and eventually inform me about the new constraints/evolution for this part.


I have performed some testings in the Playground by creating a particle system with sphere emitter and it does work for me.

Is it possible for you to make a repro with a particle system that would not work?

In the meantime, you can test a couple of things:

  • try to put engine.getCaps().instancedArrays = false; very early in your code and see if it helps. It disables instancing support, so the particle system will use another code path than the standard one
  • put back engine.getCaps().instancedArrays = true; (or better, remove it) and add this code in your project:
BABYLON.ParticleSystem.prototype._createVertexBuffers = function () {
    this._vertexBufferSize = this._useInstancing ? 10 : 12;
    if (this._isAnimationSheetEnabled) {
        this._vertexBufferSize += 1;

    if (!this._isBillboardBased || this.billboardMode === BABYLON.ParticleSystem.BILLBOARDMODE_STRETCHED) {
        this._vertexBufferSize += 3;

    if (this._useRampGradients) {
        this._vertexBufferSize += 4;

    let engine = this._engine;
    this._vertexData = new Float32Array(this._capacity * this._vertexBufferSize * (this._useInstancing ? 1 : 4));
    this._vertexBuffer = new BABYLON.Buffer(engine, this._vertexData, true, this._vertexBufferSize);

    let dataOffset = 0;
    var positions = this._vertexBuffer.createVertexBuffer(BABYLON.VertexBuffer.PositionKind, dataOffset, 3, this._vertexBufferSize, this._useInstancing);
    this._vertexBuffers[BABYLON.VertexBuffer.PositionKind] = positions;
    dataOffset += 3;

    var colors = this._vertexBuffer.createVertexBuffer(BABYLON.VertexBuffer.ColorKind, dataOffset, 4, this._vertexBufferSize, this._useInstancing);
    this._vertexBuffers[BABYLON.VertexBuffer.ColorKind] = colors;
    dataOffset += 4;

    var options = this._vertexBuffer.createVertexBuffer("angle", dataOffset, 1, this._vertexBufferSize, this._useInstancing);
    this._vertexBuffers["angle"] = options;
    dataOffset += 1;

    var size = this._vertexBuffer.createVertexBuffer("size", dataOffset, 2, this._vertexBufferSize, this._useInstancing);
    this._vertexBuffers["size"] = size;
    dataOffset += 2;

    if (this._isAnimationSheetEnabled) {
        var cellIndexBuffer = this._vertexBuffer.createVertexBuffer("cellIndex", dataOffset, 1, this._vertexBufferSize, this._useInstancing);
        this._vertexBuffers["cellIndex"] = cellIndexBuffer;
        dataOffset += 1;

    if (!this._isBillboardBased || this.billboardMode === BABYLON.ParticleSystem.BILLBOARDMODE_STRETCHED) {
        var directionBuffer = this._vertexBuffer.createVertexBuffer("direction", dataOffset, 3, this._vertexBufferSize, this._useInstancing);
        this._vertexBuffers["direction"] = directionBuffer;
        dataOffset += 3;

    if (this._useRampGradients) {
        var rampDataBuffer = this._vertexBuffer.createVertexBuffer("remapData", dataOffset, 4, this._vertexBufferSize, this._useInstancing);
        this._vertexBuffers["remapData"] = rampDataBuffer;
        dataOffset += 4;

    var offsets;
    if (this._useInstancing) {
        //var spriteData = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
        var spriteData = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
        this._spriteBuffer = new BABYLON.Buffer(engine, spriteData, false, 2);
        offsets = this._spriteBuffer.createVertexBuffer("offset", 0, 2);
    } else {
        offsets = this._vertexBuffer.createVertexBuffer("offset", dataOffset, 2, this._vertexBufferSize, this._useInstancing);
        dataOffset += 2;
    this._vertexBuffers["offset"] = offsets;


BABYLON.ParticleSystem.prototype._render = function (blendMode) {
    var effect = this._getEffect(blendMode);

    var engine = this._engine;

    // Render

    var viewMatrix = this.defaultViewMatrix ? this.defaultViewMatrix : this._scene.getViewMatrix();
    effect.setTexture("diffuseSampler", this.particleTexture);
    effect.setMatrix("view", viewMatrix);
    effect.setMatrix("projection", this.defaultProjectionMatrix ? this.defaultProjectionMatrix : this._scene.getProjectionMatrix());

    if (this._isAnimationSheetEnabled && this.particleTexture) {
        var baseSize = this.particleTexture.getBaseSize();
        effect.setFloat3("particlesInfos", this.spriteCellWidth / baseSize.width, this.spriteCellHeight / baseSize.height, this.spriteCellWidth / baseSize.width);

    effect.setVector2("translationPivot", this.translationPivot);
    effect.setFloat4("textureMask", this.textureMask.r, this.textureMask.g, this.textureMask.b, this.textureMask.a);

    if (this._isBillboardBased && this._scene) {
        var camera = this._scene.activeCamera;
        effect.setVector3("eyePosition", camera.globalPosition);

    if (this._rampGradientsTexture) {
        if (!this._rampGradients || !this._rampGradients.length) {
            this._rampGradientsTexture = null;
        effect.setTexture("rampSampler", this._rampGradientsTexture);

    const defines = effect.defines;

    if (this._scene) {
        if (this._scene.clipPlane || this._scene.clipPlane2 || this._scene.clipPlane3 || this._scene.clipPlane4 || this._scene.clipPlane5 || this._scene.clipPlane6) {
            BABYLON.ThinMaterialHelper.BindClipPlane(effect, this._scene);

    if (defines.indexOf("#define BILLBOARDMODE_ALL") >= 0) {
        effect.setMatrix("invView", BABYLON.TmpVectors.Matrix[0]);

    engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);

    // image processing
    if (this._imageProcessingConfiguration && !this._imageProcessingConfiguration.applyByPostProcess) {

    // Draw order
    switch (blendMode) {
        case BABYLON.ParticleSystem.BLENDMODE_ADD:
        case BABYLON.ParticleSystem.BLENDMODE_ONEONE:
        case BABYLON.ParticleSystem.BLENDMODE_STANDARD:
        case BABYLON.ParticleSystem.BLENDMODE_MULTIPLY:

    if (this._onBeforeDrawParticlesObservable) {

    if (this._useInstancing) {
        //engine.drawArraysType(BABYLON.Constants.MATERIAL_TriangleStripDrawMode, 0, 4, this._particles.length);
        engine.drawArraysType(BABYLON.Constants.MATERIAL_TriangleFanDrawMode, 0, 4, this._particles.length);
    } else {
        engine.drawElementsType(BABYLON.Constants.MATERIAL_TriangleFillMode, 0, this._particles.length * 6);

    return this._particles.length;

It will put back the usage of triangle fans instead of triangle strips, which has been a late change to the particle system. I checked on the playground that the new and old way does still work, but…

Thank you for this prompt answer. I shall try this shortly.
The code for this part is an old version (and an early version from my learning) from March/April. I needed to eventually go back to it, since the ’snow effect’ is a main part of the project.
The code is likely to be a bit mess (or overcrowded;), so I shall have a look at it and will also try set up a playground example reproducing this behavior/error. In any case, thanks a late for the info about the late change(s); it sure gives me a clue about the possible source of the problem (or my error).

quickly checked both solution as early as after


var delayCreateScene = function () {
var scene = new BABYLON.Scene(engine);
engine.getCaps().instancedArrays = true;

Either, it’s not early enough, too early or simply not working with my faen code:(
None of these options change anything. They do not throw an error, but they don’t change anything.
I believe I will have to try’n set up a playground reproducing this. And while doing this, there’s still a chance I might find my error or my ‘unhanded’ twist;)
Will be back on it anyway (for now, I’m struggling with another topic for #spritesheet animation and #babylon GUI (2d GUI). I was actually investigating this problem with my handling of an animated 2D GUI spreadsheet for buttons when I bumped into this new issue with #particles. A sad day;)…
Thanks again,

@mawa we did a big merge yesterday and I am afraid we might have introduced a regression.

Is it possible for you to share your code with us (in private messages) ? and if not, could you in the playground only copy your particle system setup ?

I will see what I can do to quickly set up a playground repro. I’m not really willing to share the code at this stage of the project because for now it’s mostly just a ‘pilling-up’ from a large variety of babylon’s features;) I’d like to clean it at least a little bit before sharing. But I will definitely try to set up something. Just had some other things I needed to focus on…
Thanks again,

no rush and thanks a lot, isolating the particle system issue would be way better for us anyway :slight_smile:

Also are you using pointsCloudSystem, GpuParticles or regular particles, which can help narrowing our search until we get your repro ?

no pointsCloud, but I’m using GPU (currently on just one of my particleSystems). The snowball snow effect. I was running some tests also with the warm-up feature… As I said, I need to quickly go back to it and will try to set up something (after dinner;). Thanks,

1 Like

I’m making some tests while trying to set-up the playground repro and it looks like it could have something to do with the ‘update speed’. Does this ring a bell?
It’s the only parameter I can change where I can actually see a real difference. For now, I’ve remove ‘animated cells’(animationSheet) and returned to just the simple ‘flare.png’ image, I’ve also removed lifetime- and velocity-gradients & GPU particles,I did extend the lifetime of particles, removed all of ‘warm-up’ or ‘delay’ and rendering group in case of an issue with the blend/alpha. I’m still getting the same result.
I’ll keep you posted…

1 Like

Ok, so here’s my repro in the playground, based on the ‘emit particles from a box’ from the intro to the particle system (

This is my version (somewhat simplified but still featuring the problem):

Change the ‘preview/*’ with ’’ and you shall clearly see the difference.

Let me know when you get an input on this. I’m eager to understand just where I messed it up again;)
Thanks a lot,

@mawa are you sure you shared the right one ??? you have shared 2 times the same url
and for me locally both versions do the exact same ???

Ok found it is acting differently !!!

thanks alot

sorry wrong link (getting tired;)
here’s the repro:

1 Like

NP. sry for spamming. As I said, getting tired. I’m gonna go for a rest now and will return on it tomorrow morning.
GL with the topic.

Nah all goood have a good rest the bug is definitely on our side we ll fix it ASAP probably in the next nightly.

1 Like

Fix is in and will be available in the next nightly in about 1 hour Fix WebGPU Particles NoiseTexture by sebavan · Pull Request #9491 · BabylonJS/Babylon.js · GitHub

Thank you for this quick reaction,
For whatever you did, your magic worked. :mage:
I hope you manage to also get a rest from time to time :relieved:

1 Like