i am new to webgpu and trying to render some spheres using frgament shader spheres are defined as
struct Material {
category: u32,
attenuation: vec3f,
fuzz: f32,
refraction_index: f32,
}
struct Sphere {
center: vec3f,
radius: f32,
mat: Material
}
function createSpheresStorageBuffer2(spheres: Sphere[]): GPUBuffer {
const bufferElements: (Float32Array | Uint32Array)[] = [];
let size = 0;
let arrayBuffer;
for (const sphere of spheres) {
arrayBuffer = new Float32Array([...sphere.center, sphere.radius]);
size+=arrayBuffer.byteLength;
bufferElements.push(arrayBuffer);
const {type,attenuation,fuzz,refraction_index} = sphere.material;
arrayBuffer = new Uint32Array([type]);
size+=arrayBuffer.byteLength;
bufferElements.push(arrayBuffer);
arrayBuffer = new Float32Array([...attenuation,fuzz,refraction_index]);
size+=arrayBuffer.byteLength;
bufferElements.push(arrayBuffer);
}
const buffer = device.createBuffer({
label: "spheres buffer",
size: size,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
});
let offset = 0;
for(const buff of bufferElements){
device.queue.writeBuffer(buffer, offset, buff);
offset+=buff.byteLength
}
return buffer
}
enum MaterialType {
Labertian = 0,
Metal = 1,
}
const spheres: Sphere[] = [
{
center: [0, -100.5, -1],
radius: 100,
material: {
type: MaterialType.Labertian,
attenuation: [0.5,0.5,0.5],
fuzz: 1.0,
refraction_index: 1.0
}
},
{
center: [1, 0, -1],
radius: 0.5,
material: {
type: MaterialType.Metal,
attenuation: [0.5,0.5,0.5],
fuzz: 0,
refraction_index: 1.0
}
},
]
but the value of center of shpere 2 in shader is 0.5,0.5,1 which are the values from attenuation [2,3] + fuzz (which i can to know by trial and error)
the code works fine when the attenuation is f32 instead of vector
It doesn't appear that the way you are packing your data matches the memory layout from WebGPU
Here's the layout
The diagram generated from here
You might want to consider using a library to set storage and uniform buffers.
On the other hand, you might also want to consider making one arraybuffer and 2 views. It will be more efficient to upload one buffer than 3 per sphere you're uploading now.
Something along the lines of
See this article for more info
Note: The method above has performance issues as it's creating temporary arrays for each call to
set. I don't know if there is an optimal solution. I'd be fine using the solution above until I found it was too slow for my needs. Then I might try something different. One example might beThis code at least is not allocating temporary arrays. You'd have to profile if it's faster.
disclosure: I contribute to the site that generated the diagram and the article and the library linked above and most likely the browser you're using when you asked this question