Skip to content

Integer uniforms get uploaded to the GPU as Floats #29952

@holtsetio

Description

@holtsetio

Description

When creating Uniform Nodes for WebGPU, the default uniform type in the shader is float. If you want to use integer values in the shader, fp32 is capable of every integer value up to 2^24=16777216, after which fp32 precision breaks down. For better precision, you can set the nodetype of the uniform nodes to create, for example, uniforms of type uint. However, when setting the value of the integer uniform node, the value still gets uploaded to the GPU as a float, but is interpreted by the shader as an uint, which causes nonsense values. Right now you can only use integer uniforms with a little hack to interpret the value as float before uploading to the GPU (see attached jsfiddle)

Reproduction steps

  1. Create a uniform with type uint: uniform(value, "uint")
  2. Use a compute shader to write the value to an output buffer of type uint
  3. Read the output and compare

Code

import * as THREE from 'three';
import { Fn, uniform, storage } from 'three/tsl';

const renderer = new THREE.WebGPURenderer();
const outputNode = document.createElement("div");
document.body.appendChild(outputNode);

const int2float_hack = (x) => {
    return new Float32Array(new Uint32Array([x]).buffer)[0];
};

const run = async () => {
  const buffer = new THREE.StorageBufferAttribute(new Uint32Array(3), 1, Uint32Array);
  const outputStorage = storage(buffer, "uint", 3);
  
  const value = 16777217;
  const u0 = uniform(value);
  const u1 = uniform(value, "uint");
  const u2 = uniform(int2float_hack(value), "uint");

  const kernel = Fn(()=>{
    outputStorage.element(0).assign(u0);
    outputStorage.element(1).assign(u1);
    outputStorage.element(2).assign(u2);
  })().compute(3);

  await renderer.computeAsync(kernel);

  const result = new Uint32Array(await renderer.getArrayBufferAsync(buffer));
  
  outputNode.innerText += "input value: " + value + "\n\n";
  outputNode.innerText += "Element 0 (float uniform): " + result[0] + "\n";
  outputNode.innerText += "Element 1 (uint uniform): " + result[1] + "\n";
  outputNode.innerText += "Element 2 (uint uniform with hack): " + result[2] + "\n";
}
run();

Live example

jsfiddle

Screenshots

threejsbug

Version

r171-dev

Device

No response

Browser

No response

OS

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions