CodyJasonBennett / four

💎 Minimal three.js alternative.
https://npmjs.com/fourwastaken
MIT License
306 stars 13 forks source link

Creating a texture with Float32Array, gl.FLOAT format #15

Open Nek opened 1 month ago

Nek commented 1 month ago

Hello! Thanks for the great project. I'm moving to it from ogl and have issues implementing the equivalent of GPGPU. I have to create a Texture from Float32Array and it doesn't seem possible. Am I missing something or should I fork and update the library?

The relevant code: https://github.com/CodyJasonBennett/four/blob/cd6c5ba935dd89cd00fe3e1d55e550d16a96b64d/src/WebGLRenderer.ts#L308

CodyJasonBennett commented 1 month ago

Is this a DOM upload, or are you rendering to a float render target? Note that linear filtering for float textures requires OES_texture_float_linear where support has regressed on Apple platforms. You can try either nearest filtering or half floats to rule out support. GPGPU is a little weak in Four since I haven't implemented depth/stencil, but all of this should be quick to rectify.

Nek commented 1 month ago

I quickly hacked in Float32Array support but I can't make my code work. I feel like I miss something basic. I'm still wrapping my mind around all the juggling WebGL requires. Pretty sure it's not the library but me. :)

The hack looks like this:

 if (texture.image) {
        if (texture.image instanceof Float32Array) {
          this.gl.texImage2D(GL_TEXTURE_2D, 0, this.gl.RGBA32F, width, height, 0, this.gl.RGBA, this.gl.FLOAT, texture.image)
        } else {
          this.gl.texImage2D(GL_TEXTURE_2D, 0, format, format, type, texture.image)
        }
} else {
        this.gl.texImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, null)
}

I'm rendering to render target. Thanks for the guidance! I had no idea about the regress. Actually, this part of rendering seems to work.

const coordsTexture = new Texture(
  floatArray,
  new Sampler({ wrapS: 'clamp', wrapT: 'clamp', minFilter: 'nearest', magFilter: 'nearest', generateMipmaps: false }),
  gl.RGBA32F,
  gl.FLOAT,
)

const triangleGeometry = new Geometry({
  position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) },
  uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) },
})

const coordsCompute = new Mesh(
  triangleGeometry,
  new Material({
    vertex: shaders.passPositionVS,
    fragment: shaders.passDataTextureFS,
    uniforms: {
      tMap: coordsTexture,
    },
  }));

const coordsComputeTarget = new RenderTarget(size, size, 2)

renderer.setRenderTarget(coordsComputeTarget)
renderer.render(coordsCompute)
renderer.setRenderTarget(null)

I'm stuck at the next step where I try to use the data rendered into a texture for particles positioning. I'm not posting it, as it is irrelevant to the Float32Array problem.