Reputation: 2281
I am trying to pass "volume._data" to my fragment shader in threeJS. It is a Float32Array and it can contain up to: 512x512x512x4 elements.
var mat = new THREE.ShaderMaterial({
uniforms: {
color: {type: 'f', value: 1.0},
ijk: {type: '??', value: volume._data},
dimensions: {type: 'vec3', value: volume._dimensions},
ijktoras: {type: 'mat4', value: volume._RASToIJK}
},
vertexShader: document.
getElementById('vertShader').text,
fragmentShader: document.
getElementById('fragShader').text
});
The problem is that I do not know which type to give it. Or is the best option to pass a 2D texture?
My concern with the texture is that it will be too big to be passed to the shader.
Is there any workaround to pass this amount of information to the shader?
My overall goal is, in the fragment shader, to map the screen pixel position to the object world's coordinate. And then map this world coordinate to my volume._data (ijk space) to display on the screen a specific color.
Thank you, Nicolas
Upvotes: 2
Views: 6461
Reputation: 404
The answer Flux provided is correct. For those of you here trying to put together a volumetric shader the following may be useful.
You can use a one dimensional array to represent 3d space and retrieve the correct array item via it's x,y,z coords using the following method.
x,y,z coords should be in local space (rather than world) with the origin at 0,0,0
. You'll need to know the width and height of each 2d section.
Assuming a voxel volume of 3x3x3
uniform float[] Voxels;
uniform int Width = 3;
uniform int Height = 3;
float getValueAtVoxel(x,y,z) {
int voxel = (Width * Height * z) + (y * Width) + x;
if (voxel < 0 || voxel >= Voxels.length) {
return 0.0;
}
return Voxels[voxel];
}
Upvotes: 1
Reputation: 666
Check out https://github.com/mrdoob/three.js/wiki/Uniforms-types for arrays, such as:
"uFloatArray3" : { type: "fv", value: [ 0.1, 0.2, 0.3, 0.4, 0.5, 0.6 ] }, // float array (vec3)
or
"uVec4Array" : { type: "v4v", value: [ new THREE.Vector4( 0.1, 0.2, 0.3, 0.4 ),
new THREE.Vector4( 0.4, 0.5, 0.6, 0.7 ) ] }, // Vector4 array
You can always just pack that data into a straight array and use a delimiter.
As far as what you are doing, it's best to pass in 3 textures, each 512x512 and access RGBA for your 4 values. It will not be too slow, don't worry too much about optimization until you try it.
This ofcourse depends on how you fill the data in your buffer. The faster way to do it is through a canvas using the pixels array as described here: https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipulation-with-typed-arrays/
Upvotes: 2