问题
I am working on volumetric rendering raw data in three.js. I have a hard time understanding the relationship between the type and format of the texture (in my case it is texture3d) in three.js.
Available type of texture type are :
and available format are:
I tried to put type as THREE.UnsignedIntType for u8int datatype of raw data but it gives invalid internalformat of texture error but everything works fine with type of THREE.UnsignedByteType.
this is my code of texture,
var texture = new THREE.DataTexture3D(data, dims[0], dims[1], dims[2]);
texture.format = THREE.RedFormat;
texture.type = THREE.UnsignedByteType;
Could anyone please say how both are related. I cannot make static since the raw data type can be of any bit (8/16/32) and type(int/float).
回答1:
The three.js texture format and types are aliases for the WebGL formats and types. Only certain combinations are allowed.
The list of valid combinations for WebGL1 is
| format | type
+-----------------+------
| RGBA | UNSIGNED_BYTE
| RGB | UNSIGNED_BYTE
| RGBA | UNSIGNED_SHORT_4_4_4_4
| RGBA | UNSIGNED_SHORT_5_5_5_1
| RGB | UNSIGNED_SHORT_5_6_5
| LUMINANCE_ALPHA | UNSIGNED_BYTE
| LUMINANCE | UNSIGNED_BYTE
| ALPHA | UNSIGNED_BYTE
So translating that to three.js is
| format | type
+----------------------+------
| RGBAFormat | UnsignedByteType
| RGBFormat | UnsignedByteType
| RGBAFormat | UnsignedShort4444
| RGBAFormat | UnsignedShort5551
| RGBFormat | UnsignedShort565
| LuminanceAlphaFormat | UnsignedByteType
| LuminanceFormat | UnsignedByteType
| AlphaFormat | UnsignedByteType
Note: WebGL1 does not support 3D textures directly although you can implement them yourself via creative shaders
WebGL2 allows a much larger list of combinations
Note that the format/type combination is the format and type of the data you are supplying to three.js, not the format of the texture that data will be stored in.
To specify the internal format you set texture.internalFormat
. To specify format
and type
you can set texture.format
and texture.type
Only certain combinations of format/type can be used as input for a given internal format. See the link above for the list.
If you want 1 channel unsigned int texture you need to set
texture.internalFormat = 'R32UI';
texture.format = THREE.RedIntegerFormat;
texture.type = THREE.UnsignedIntType;
You'll also need to make sure you set texture.minFilter
and texture.magFilter
to THREE.NearestFilter
and you'll need to make sure your shaders use uniform usampler3D someSamplerName;
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const context = canvas.getContext('webgl2');
const renderer = new THREE.WebGLRenderer({canvas, context});
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
const scene = new THREE.Scene();
const data = new Uint32Array([1234]);
const texture = new THREE.DataTexture3D(data, 1, 1, 1);
texture.internalFormat = 'R32UI';
texture.format = THREE.RedIntegerFormat;
texture.type = THREE.UnsignedIntType;
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
const shader = {
uniforms: {
threeD: { value: texture },
},
vertexShader: `#version 300 es
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`,
fragmentShader: `#version 300 es
#include <common>
uniform highp usampler3D threeD;
out vec4 c;
void main() {
uvec4 color = texture(threeD, vec3(0));
// this also works
// uvec4 color = texelFetch(threeD, ivec3(0), 0);
c = vec4(float(color.r) / 2468.0, 0, 0, 1);
}
`,
};
const material = new THREE.ShaderMaterial(shader);
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
renderer.render(scene, camera);
}
main();
</script>
With RGIntegerFormat and UnsignedByteType you need to use internal format RG8UI
and pass your data in as Uint8Array
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const context = canvas.getContext('webgl2');
const renderer = new THREE.WebGLRenderer({canvas, context});
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
const scene = new THREE.Scene();
// THREE.RGIntegerFormat as format and THREE.UnsignedByteType
const data = new Uint8Array([11, 22]);
const texture = new THREE.DataTexture3D(data, 1, 1, 1);
texture.internalFormat = 'RG8UI';
texture.format = THREE.RGIntegerFormat;
texture.type = THREE.UnsignedByteType;
window.t = THREE;
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
const shader = {
uniforms: {
threeD: { value: texture },
},
vertexShader: `#version 300 es
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`,
fragmentShader: `#version 300 es
#include <common>
uniform highp usampler3D threeD;
out vec4 c;
void main() {
uvec4 color = texture(threeD, vec3(0));
// this also works
// uvec4 color = texelFetch(threeD, ivec3(0), 0);
c = vec4(vec2(color.rg) / vec2(22), 0, 1);
}
`,
};
const material = new THREE.ShaderMaterial(shader);
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
renderer.render(scene, camera);
}
main();
</script>
来源:https://stackoverflow.com/questions/62003464/what-is-relation-between-type-and-format-of-texture