-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
enable mrt on array texture and texture3d render targets #30151
Open
wizgrav
wants to merge
3
commits into
mrdoob:dev
Choose a base branch
from
wizgrav:tex3d-mrt
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,302 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>three.js webgl - 3D texture framebuffer attachment with MRT</title> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> | ||
<link type="text/css" rel="stylesheet" href="main.css"> | ||
</head> | ||
|
||
<script id="vertex-postprocess" type="x-shader/x-vertex"> | ||
uniform mat4 projectionMatrix; | ||
uniform mat4 modelViewMatrix; | ||
|
||
in vec3 position; | ||
in vec2 uv; | ||
out vec2 vUv; | ||
|
||
void main() | ||
{ | ||
vUv = uv; | ||
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); | ||
} | ||
|
||
</script> | ||
|
||
<!-- | ||
Fragment shader processing an input 3d texture array and writing the output | ||
into a framebuffer. The framebuffer should have a 3d texture bound | ||
as color attachment. | ||
--> | ||
<script id="fragment-postprocess" type="x-shader/x-fragment"> | ||
|
||
precision highp sampler3D; | ||
precision mediump float; | ||
|
||
in vec2 vUv; | ||
|
||
uniform sampler3D uTexture; | ||
uniform float uDepth; | ||
uniform float uIntensity; | ||
|
||
#pragma unroll_loop_start | ||
for(int i=0; i< 4; i++) { layout(location = UNROLLED_LOOP_INDEX) out float output_UNROLLED_LOOP_INDEX; } | ||
#pragma unroll_loop_end | ||
|
||
void main() | ||
{ | ||
float v = 1.618 * abs(uDepth - 0.5); | ||
|
||
float voxel = texture(uTexture, vec3( vUv, v )).r; | ||
output_0 = voxel * uIntensity; | ||
|
||
voxel = texture(uTexture, vec3( 1. - vUv.x, vUv.y, v + 0.1 )).r; | ||
output_1 = voxel * uIntensity; | ||
|
||
voxel = texture(uTexture, vec3( vUv, v + 0.2 )).r; | ||
output_2 = voxel * uIntensity; | ||
|
||
voxel = texture(uTexture, vec3( 1. - vUv.x, vUv.y, v + 0.3 )).r; | ||
output_3 = voxel * uIntensity; | ||
|
||
} | ||
|
||
</script> | ||
|
||
<script id="vs" type="x-shader/x-vertex"> | ||
uniform vec2 size; | ||
out vec2 vUv; | ||
|
||
void main() { | ||
|
||
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); | ||
|
||
// Convert position.xy to 1.0-0.0 | ||
|
||
vUv.xy = position.xy / size + 0.5; | ||
vUv.y = 1.0 - vUv.y; // original data is upside down | ||
|
||
} | ||
</script> | ||
|
||
<script id="fs" type="x-shader/x-fragment"> | ||
precision highp float; | ||
precision highp int; | ||
precision highp sampler3D; | ||
|
||
uniform sampler3D diffuse; | ||
in vec2 vUv; | ||
uniform int depth; | ||
|
||
void main() { | ||
|
||
int layer = vUv.x > 0.5 ? 1 : 0; | ||
layer += vUv.y > 0.5 ? 2 : 0; | ||
|
||
vec2 uv; | ||
|
||
switch(layer) { | ||
case 0: uv = vec2(vUv.x * 2., vUv.y * 2.); break; | ||
case 1: uv = vec2(vUv.x * 2. - 1., vUv.y * 2.); break; | ||
case 2: uv = vec2(vUv.x * 2., vUv.y * 2. - 1.); break; | ||
case 3: uv = vec2(vUv.x * 2. - 1., vUv.y * 2. - 1.); break; | ||
} | ||
|
||
// For texture arrays, z is indexed with the actual slice index, 0 1 2 etc | ||
// but for 3d textures the z coordinate needs to be normalized instead | ||
|
||
vec4 color = texture( diffuse, vec3( uv, float(layer) / 4. ) ); | ||
|
||
// lighten a bit | ||
gl_FragColor = vec4( color.rrr * 1.5, 1.0 ); | ||
} | ||
</script> | ||
<body> | ||
<div id="info"> | ||
<a href="https://threejs.org" target="_blank" rel="noopener"> | ||
three.js | ||
</a> | ||
- 3D texture framebuffer MRT color attachments | ||
<br /> | ||
|
||
Scanned head data by | ||
<a href="https://www.codeproject.com/Articles/352270/Getting-started-with-Volume-Rendering" target="_blank" rel="noopener">Divine Augustine</a><br /> | ||
licensed under | ||
<a href="https://www.codeproject.com/info/cpol10.aspx" target="_blank" rel="noopener">CPOL</a> | ||
</div> | ||
|
||
<script type="importmap"> | ||
{ | ||
"imports": { | ||
"three": "../build/three.module.js", | ||
"three/addons/": "./jsm/" | ||
} | ||
} | ||
</script> | ||
|
||
<script type="module"> | ||
|
||
import * as THREE from 'three'; | ||
|
||
import Stats from 'three/addons/libs/stats.module.js'; | ||
import { unzipSync } from 'three/addons/libs/fflate.module.js'; | ||
import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; | ||
|
||
const DIMENSIONS = { | ||
width: 256, | ||
height: 256, | ||
depth: 109 | ||
}; | ||
|
||
const params = { | ||
intensity: 1 | ||
}; | ||
|
||
/** Post-processing objects */ | ||
|
||
const postProcessScene = new THREE.Scene(); | ||
const postProcessCamera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); | ||
|
||
const renderTarget = new THREE.WebGL3DRenderTarget( DIMENSIONS.width, DIMENSIONS.height, 4, { count: 4 } ); | ||
renderTarget.texture.format = THREE.RedFormat; | ||
|
||
const postProcessMaterial = new THREE.RawShaderMaterial( { | ||
uniforms: { | ||
uTexture: { value: null }, | ||
uDepth: { value: 0 }, | ||
uIntensity: { value: 1.0 } | ||
}, | ||
vertexShader: document.getElementById( 'vertex-postprocess' ).textContent.trim(), | ||
fragmentShader: document.getElementById( 'fragment-postprocess' ).textContent.trim(), | ||
glslVersion: THREE.GLSL3 | ||
} ); | ||
|
||
const depthStep = 0.003; | ||
|
||
let camera, scene, mesh, renderer, stats; | ||
|
||
const planeWidth = 50; | ||
const planeHeight = 50; | ||
|
||
init(); | ||
|
||
function init() { | ||
|
||
const container = document.createElement( 'div' ); | ||
document.body.appendChild( container ); | ||
|
||
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 2000 ); | ||
camera.position.z = 70; | ||
|
||
scene = new THREE.Scene(); | ||
|
||
/** Post-processing scene */ | ||
|
||
const planeGeometry = new THREE.PlaneGeometry( 2, 2 ); | ||
const screenQuad = new THREE.Mesh( planeGeometry, postProcessMaterial ); | ||
postProcessScene.add( screenQuad ); | ||
|
||
// 3D Texture is available on WebGL 2.0 | ||
|
||
renderer = new THREE.WebGLRenderer(); | ||
renderer.setPixelRatio( window.devicePixelRatio ); | ||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
container.appendChild( renderer.domElement ); | ||
|
||
stats = new Stats(); | ||
container.appendChild( stats.dom ); | ||
|
||
window.addEventListener( 'resize', onWindowResize ); | ||
|
||
const gui = new GUI(); | ||
|
||
gui.add( params, 'intensity', 0, 1 ).step( 0.01 ).onChange( value => postProcessMaterial.uniforms.uIntensity.value = value ); | ||
gui.open(); | ||
|
||
// width 256, height 256, depth 109, 8-bit, zip archived raw data | ||
|
||
new THREE.FileLoader() | ||
.setResponseType( 'arraybuffer' ) | ||
.load( 'textures/3d/head256x256x109.zip', function ( data ) { | ||
|
||
const zip = unzipSync( new Uint8Array( data ) ); | ||
const array = new Uint8Array( zip[ 'head256x256x109' ].buffer ); | ||
|
||
const texture = new THREE.Data3DTexture( array, DIMENSIONS.width, DIMENSIONS.height, DIMENSIONS.depth ); | ||
texture.format = THREE.RedFormat; | ||
texture.minFilter = THREE.NearestFilter; | ||
texture.magFilter = THREE.NearestFilter; | ||
texture.unpackAlignment = 1; | ||
texture.needsUpdate = true; | ||
|
||
const material = new THREE.ShaderMaterial( { | ||
uniforms: { | ||
diffuse: { value: renderTarget.texture }, | ||
size: { value: new THREE.Vector2( planeWidth, planeHeight ) } | ||
}, | ||
vertexShader: document.getElementById( 'vs' ).textContent.trim(), | ||
fragmentShader: document.getElementById( 'fs' ).textContent.trim() | ||
} ); | ||
|
||
const geometry = new THREE.PlaneGeometry( planeWidth, planeHeight ); | ||
|
||
mesh = new THREE.Mesh( geometry, material ); | ||
|
||
scene.add( mesh ); | ||
|
||
postProcessMaterial.uniforms.uTexture.value = texture; | ||
|
||
renderer.setAnimationLoop( animate ); | ||
|
||
} ); | ||
|
||
} | ||
|
||
function onWindowResize() { | ||
|
||
camera.aspect = window.innerWidth / window.innerHeight; | ||
camera.updateProjectionMatrix(); | ||
|
||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
|
||
} | ||
|
||
function animate() { | ||
|
||
let value = postProcessMaterial.uniforms.uDepth.value; | ||
|
||
value += depthStep; | ||
|
||
postProcessMaterial.uniforms.uDepth.value = value % 1; | ||
|
||
render(); | ||
|
||
stats.update(); | ||
|
||
} | ||
|
||
/** | ||
* Renders the 2D array into the render target `renderTarget`. | ||
*/ | ||
function renderTo3DTexture() { | ||
|
||
renderer.setRenderTarget( renderTarget ); | ||
renderer.render( postProcessScene, postProcessCamera ); | ||
renderer.setRenderTarget( null ); | ||
|
||
} | ||
|
||
function render() { | ||
|
||
// Step 1 - Render the input Data3DTexture into the 4 slices of the render target | ||
renderTo3DTexture(); | ||
|
||
// Step 2 - Renders the scene containing the plane with a material | ||
// sampling the 3D render target texture. | ||
renderer.render( scene, camera ); | ||
|
||
} | ||
|
||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't
layer + i
belayer
here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
without the "+ i" it would attach the same layer of the texture to all COLOR_ATTACHMENTs. This way it will attach layer on ATTACHMENT0, layer + 1 on ATTACHMENT1 etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree it's not so intuitive to implicitly offset the bound layer for each MRT-attached 3d texture. I think this should be set to
layer
as Renaud has suggested under the assumption that each MRT texture is different.And if there's a strong use case that requires binding different layers of the same 3d texture with MRT then that should be discussed in a separate issue so each layer is user-configurable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gkjohnson this was the only way that it would work with no changes/additions to the three api. We could have explicit assignment of layers to attachments by also allowing an array of indices as the layer argument. I can do the change but is this something that would be acceptable for the WebGLRenderer @Mugen87 ?