Weird pixelized coloring near camera

So I have an open world map that I’m adding a bunch of grass to, and all seems well except one issue-
When the grass is close to the camera it looks really weird. You can see this in the screen shot below:

However, in this playground the issue does not seem to happen:

Lastly, I had question about baking wind-blowing animations into the grass - I was thinking I would have a physics sim play out in blender and just record it, but does anyone have any tips or resources for turning that into an animation?

Did you change the UV scale for the grass texture in the open world map? You can find the texture in BJS inspector and check.

BTW, this open world map looks very cool now! Is the high mountains accessible for the character?

BTW, this open world map looks very cool now! Is the high mountains accessible for the character?

Sure is! Part of my journey has been figuring out ways to make this work in the browser within reasonable parameters (not using too much ram, etc.) such that it works on most peoples laptops. I’ll be posting it in the demos topic later. I’ll probably use it for the GUI competition :smiley:

Did you change the UV scale for the grass texture in the open world map? You can find the texture in BJS inspector and check.

No, everything I did was pretty standard - the editing that I did do was split this grass model out from a larger gltf file that had other grass models from a pack I found on sketchfab. I then re-centered the model on itself, but I can’t imagine any of that being the issue.

You could make a snapshot of a frame with Spector and see if you can find something strange in it. We could also have a look if you are able to provide a link to a live repro.

2 Likes

Woah, nice tool, I’ll try that out. I’ll also try to get this up live, I was only just starting to play with adding grass to my map; I’ll move quickly to just have it added to the areas around the base of each tree using that same algo I used in the playground. The live demo itself is here:
https://g7r7sz.colyseus.dev/client/index.html
(frame rate is awful for some reason compared to my localhost version)

I’ll post back here once the grass is up.

@Evgeni_Popov Unfortunately I won’t be able to work on this till Tuesday probably. I realized I need to use some precomputed results regarding the placement of each grass instance, and doing that right will take a little more time.

1 Like

@Evgeni_Popov btw, I had another tangential question regarding thin instances I was hoping to ask you-
if I have 140k grass model thin instances but I want to reduce the burden on the gpu, if I were to set the scaling to zero for all thin instances not located in the players current grid region on the map (I have it divided up in to 20x20 grid regions) would this stop the gpu from computing for those instances? And if not, would it at least reduce by some noticeable amount?

Yes, it would reduce the burden a bit because the triangles with vertex scaling = 0 would have no area so the fragment shader will never be executed for them. You could reduce the burden even further by making sure those triangles have 0 area at the geometry level: you can do this by copying the 2nd index into the 3rd of the index array for each triangle that should be excluded from rasterization.

For eg, to remove the first triangle of the ground plane:

[…] Ah, by re-reading your question you want to do this for thin instances… So, this latter technic won’t work because you have a single instance of the mesh. If you remove a triangle this way it will be removed for all instances.

1 Like

So I tried out turning off the grass thin instances via setting scaling to zero, and turning those thin instances back on again via the reverse operation of setting their scaling back to it’s original value. Unfortunately it takes a really long time to do so.

To solve this issue of wanting to have 1400 - 1600 instances be shown only when the player is the corresponding grid region, I was thinking maybe I could make a copy from the grass source mesh for each grid on the map. I would then create thin instances that pertain to a given region and have the visibility of that grid’s source mesh toggled on and off. Would I still be getting the performance savings by doing it this way?

The alternative, that I’m trying right now, would be the same ^ but use regular instanced meshes instead of thin instances.

Do either of these sound like they would work? Are there any better ways to go about this?

This strategy looks good to me as long as your grid cell is big enough (if the source mesh has only 5 thin instances it’s probably not interesting), as your grid is already your visibility unit.

I think it’s a perf saving if you track which grid cells become visible/disappear when you move the camera instead of scanning all the grid cells to update their visibility status. In the former strategy, you will update the status of only a fraction of the grid cells, whereas in the latter you will update all the grid cells. Though it probably warrants some testing as just looping over all the cells is easier than tracking which cells become visible/invisible…

Using regular instanced meshes is probably not the right strategy here as you would need to create tens (or more) thousands of them and the system won’t be able to handle so many meshes.

2 Likes

Each grid’s source mesh for the grass would be responsible for ~ 1400 - 1600 thin instances. So if this strategy works, it would definitely show.

I have a system that checks whether the users position has crossed any grid boundaries, and if so freezes the previous grid and unfreezes the new current grid; so I’m only ever iterating over two grids worth of objects / instances (~ (1400 - 1600) x 2). I was considering adding some logic that also operates on the surrounding grids as well, but I’ll save that for later.

Okay, so this approach seems to be performing a bit better, but I’m still hitting an issue:

Map.ts:651 ** setCurrGridZone - calling _loadGrid 10 6
setCurrGridZone @ Map.ts:651
onPlayerMoveCallback @ Game.ts:971
_updateFromKeyboardControls @ Player.ts:793
_beforeRenderUpdate @ Player.ts:984
notifyObservers @ observable.ts:325
render @ scene.ts:3844
renderLoop @ gameUtils.ts:912
_renderFrame @ engine.ts:1303
_renderLoop @ engine.ts:1321
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
requestAnimationFrame (async)
QueueNewFrame @ thinEngine.ts:5961
_queueNewFrame @ thinEngine.ts:1634
_renderLoop @ engine.ts:1340
localhost/:1 [.WebGL-0000725C086CA200] GL_INVALID_OPERATION: Error: 0x00000502, in ..\..\third_party\angle\src\libANGLE\renderer\d3d\VertexDataManager.cpp, reserveSpaceForAttrib:520. Internal error: 0x00000502: Vertex buffer is not big enough for the draw call.
localhost/:1 [.WebGL-0000725C086CA200] GL_INVALID_OPERATION: Error: 0x00000502, in ..\..\third_party\angle\src\libANGLE\renderer\d3d\VertexDataManager.cpp, reserveSpaceForAttrib:520. Internal error: 0x00000502: Vertex buffer is not big enough for the draw call.
localhost/:1 [.WebGL-0000725C086CA200] GL_INVALID_OPERATION: Error: 0x00000502, in ..\..\third_party\angle\src\libANGLE\renderer\d3d\VertexDataManager.cpp, reserveSpaceForAttrib:520. Internal error: 0x00000502: Vertex buffer is not big enough for the draw call.
localhost/:1 [.WebGL-0000725C086CA200] GL_INVALID_OPERATION: Error: 0x00000502, in ..\..\third_party\angle\src\libANGLE\renderer\d3d\VertexDataManager.cpp, reserveSpaceForAttrib:520. Internal error: 0x00000502: Vertex buffer is not big enough for the draw call.

I don’t really understand this error message, as I’ve already tested out loading all grass across the entire map at once, so why would loading 1/(20 x 20) of that become a space allocation issue? This is the the method that I use to clone the grass mesh per grid:

const getGridResourceTemplate = (sourceMesh: Mesh, row: number, col: number) => {
  const sourceMeshCopy = sourceMesh.clone(
    `${sourceMesh.name}_EEGridSourceMesh[${row}][${col}]`,
    sourceMesh.parent,
  )

  return {
    matrices: [],
    sourceMesh: sourceMeshCopy,
    thinInstanceBuffer: new Float32Array(),
    ees: [],
  }
}

Am I missing something here?

Are you sure you have enough data in the thin instance buffers to account for mesh.thinInstanceCount instances?

I think so… here’s how I load a given grid:

  _loadGrid(row: row, col: col) {
    /* grid[row][col] = return value of getGridResourceTemplate */
    const grid = this._eeResourcesGrid[row][col]
    console.log('loadGrid: ', grid)
    for (const [_eeName, eeResource] of Object.entries(grid)) {
      const matrices = eeResource['matrices']
      const sourceMesh = eeResource['sourceMesh']
      const thinInstanceBuffer = createThinInstances(
        sourceMesh,
        matrices,
      )
      eeResource['thinInstanceBuffer'] = thinInstanceBuffer
  
      this._setGridLoaded(row, col, true)
    }

  }


export const createThinInstances = (
  sourceMesh: Mesh | AbstractMesh,
  matricies: Matrix[],
) => {
  const matricesData = new Float32Array(matricies.length * 16)

  let mat: Matrix
  for (let i = 0; i < matricies.length; i++) {
    mat = matricies[i]
    mat.copyToArray(matricesData, i * 16)
  }

  sourceMesh.parent = null
  sourceMesh.position.setAll(0)
  sourceMesh.scaling.setAll(1)
  sourceMesh.rotation.setAll(0)
  sourceMesh.rotationQuaternion = new Quaternion()

  //@ts-ignore
  sourceMesh.thinInstanceSetBuffer(
    "matrix", matricesData, 16
  )

  return matricesData
}

I’m wondering if when I create these per grid region clones of the grass mesh, I’m doing it in such a way that babylon.js thinks each one shares all the same thin instances (across all grids)?

@Evgeni_Popov I think it has to do with this

Okay yeah that was it. I’m launching this on the live demo link now so that you can see how the grass behaves.

Just know that you’ll need to give the game like 15 seconds after the you see the character load in, for some reason loading the audio first kills the frame rate.

I can’t see the grass?

Shoot so sorry, I’ve not yet created a checklist behind each deployment where changes to the environment are being made. There’s a plain json file that holds the blueprints for the world map’s trees, rocks, grass etc. My installer simply checks if the file exists atm, but not if you have the newest version downloaded; working on a fix for that.

@Evgeni_Popov It should work now. Please let me know if not, thank you!

It seems the problem comes from the bump texture: if we remove it there’s no more flickering.

You should create a minimal repro in the Playground with only a single grass mesh so that it’s easier for us to look for the problem.

1 Like