gpujs / gpujs/gpu.js

Render loop that uses the results of previous render tend to glitch out.

Aperta
#756 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
JavaScript
Stelle
15.5k
Fork
663
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

## *What* is wrong?
I am trying to write a continuous simulation loop on canvas, using gpu.js. The idea is to:

1. Generate an initial `w * h * 4` array (`Uint8ClampedArray` to be more specific)
2. Write a gpu.js kernel, that processes that data and outputs result with `this.color`
3. return the data with `getPixels()` and override the initial data
4. pass the data returned in step 3 to the next simulation
5. repeat steps 3-5 in a render loop

However:

- The kernel does not use the data from the previous iteration (even though when I check the `map` variable from the browser console, it does contain results from the previous iteration). You can see that the pixels are not increasing in lightness over first couple of iterations, but are just replaced.
- After a couple of render calls, the entire thing starts to glitch out entirely, drawing almost full lines of the same pixel data.
- The left-side area is not a result of failed recording - it does look like this in the browser.
- In the example code below, RGB pixels are clamped on increasing the value to avoid any overflow possibilities.

Here is the recorded result:
![gpu js-failed-simulation](https://user-images.githubusercontent.com/2618837/168488205-57a554a8-8941-4bfc-8342-1ab2e5920deb.gif)

## *Where* does it happen?
In the browser. (chrome 101.0.4951.67)

## *How* do we replicate the issue?
Here is a sample I wrote:

```html

...

...
```

```js
// index.js
const canvas = document.getElementById('daCanvas');
const gl = canvas.getContext('webgl2', { premultipliedAlpha: false });

// 1.
let map = new Uint8ClampedArray(canvas.width * canvas.height * 4);

const gpu = new GPU({
canvas,
context: gl,
});

// 2.
const simulate = gpu.createKernel(function(mapData) {
if(Math.random() > 0.95) {
this.color(
Math.min(1, mapData[this.thread.x][this.thread.y][0] / 255 + 0.3),
Math.min(1, mapData[this.thread.x][this.thread.y][1] / 255 + 0.3),
Math.min(1, mapData[this.thread.x][this.thread.y][2] / 255 + 0.3),
1
);
} else {
this.color(
mapData[this.thread.x][this.thread.y][0] / 255,
mapData[this.thread.x][this.thread.y][1] / 255,
mapData[this.thread.x][this.thread.y][2] / 255,
1
);
}
})
.setOutput([canvas.width, canvas.height])
.setGraphical(true);

const render = () => {
// 3.
simulate(GPU.input(map, [canvas.width, canvas.height, 4]));
// 4.
map = simulate.getPixels();
}

// 5.
// Were using a nice slow interval for gentle simulation. Resutls for reqquestAnimationFrame loop are similar, just faster
setInterval(() => {requestAnimationFrame(render);}, 1000)
```
## *How* important is this (1-5)?
It's just an experiment a'la the game of life, so let's say 2 (I take my hobby experiments seriously, but let's be honest - I am just playing with the tech).

## Expected behaviour (i.e. solution)
I expected, that the image would start black, and then with each iteration, some pixels would become lighter and lighter until the image is entirely white.

## Other Comments
I was trying this with several different approaches (separate kernel for processing, separate for rendering, different operations within the kernel etc), but the result was always glitchy. Even If I had just a loop that always draws whatever is in `mapData` and then would execute something like `map[0] - 255` from the browser console, the loop would glitch out after a several loops.

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

Riproduci l’esempio di index.html e index.js in Chrome, iniziando dal ciclo di rendering che chiama simulate() e getPixels(). Confronta i valori successivi di map e l’output del canvas per determinare dove i dati dell’iterazione precedente smettono di essere utilizzati o vengono corrotti. Il lavoro è completato quando le iterazioni ripetute utilizzano i pixel precedenti e producono gradualmente l’illuminazione prevista senza difetti visivi.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
javascript
Ambito
computer-graphics, frontend
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.