Skip to content

Commit 53ee377

Browse files
authored
EXRExporter: implements support for DataTexture export (mrdoob#26810)
* EXRExporter: DataTexture support Signed-off-by: Guilherme Avila <[email protected]> * EXRExporter: update API & docs Signed-off-by: Guilherme Avila <[email protected]> * Examples: add misc_exporter_exr Signed-off-by: Guilherme Avila <[email protected]> * fix MIME-type Signed-off-by: Guilherme Avila <[email protected]> * update DataTexture usage example Signed-off-by: Guilherme Avila <[email protected]> * update screenshot Signed-off-by: Guilherme Avila <[email protected]> --------- Signed-off-by: Guilherme Avila <[email protected]>
1 parent c3a746a commit 53ee377

File tree

5 files changed

+336
-24
lines changed

5 files changed

+336
-24
lines changed

docs/examples/en/exporters/EXRExporter.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,15 @@ <h3>[method:null parse]( [param:WebGLRenderer renderer], [param:WebGLRenderTarge
7878
Generates a .exr output from the input render target.
7979
</p>
8080

81+
<h3>[method:null parse]( [param:DataTexture dataTexture], [param:Object options] )</h3>
82+
<p>
83+
[page:Function dataTexture] — DataTexture containing data used for exporting EXR image.<br />
84+
[page:Options options] — Export options (details above).<br />
85+
</p>
86+
<p>
87+
Generates a .exr output from the input data texture.
88+
</p>
89+
8190
<h2>Source</h2>
8291

8392
<p>

examples/files.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@
409409
"misc_exporter_ply",
410410
"misc_exporter_stl",
411411
"misc_exporter_usdz",
412+
"misc_exporter_exr",
412413
"misc_lookat"
413414
],
414415
"css2d": [

examples/jsm/exporters/EXRExporter.js

Lines changed: 102 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,61 +21,107 @@ const ZIP_COMPRESSION = 3;
2121

2222
class EXRExporter {
2323

24-
parse( renderer, renderTarget, options ) {
24+
parse( arg1, arg2, arg3 ) {
2525

26-
if ( ! supported( renderer, renderTarget ) ) return undefined;
26+
if ( ! arg1 || ! ( arg1.isWebGLRenderer || arg1.isDataTexture ) ) {
2727

28-
const info = buildInfo( renderTarget, options ),
29-
dataBuffer = getPixelData( renderer, renderTarget, info ),
30-
rawContentBuffer = reorganizeDataBuffer( dataBuffer, info ),
31-
chunks = compressData( rawContentBuffer, info );
28+
throw Error( 'EXRExporter.parse: Unsupported first parameter, expected instance of WebGLRenderer or DataTexture.' );
3229

33-
return fillData( chunks, info );
30+
} else if ( arg1.isWebGLRenderer ) {
3431

35-
}
32+
const renderer = arg1, renderTarget = arg2, options = arg3;
3633

37-
}
34+
supportedRTT( renderTarget );
35+
36+
const info = buildInfoRTT( renderTarget, options ),
37+
dataBuffer = getPixelData( renderer, renderTarget, info ),
38+
rawContentBuffer = reorganizeDataBuffer( dataBuffer, info ),
39+
chunks = compressData( rawContentBuffer, info );
40+
41+
return fillData( chunks, info );
3842

39-
function supported( renderer, renderTarget ) {
43+
} else if ( arg1.isDataTexture ) {
4044

41-
if ( ! renderer || ! renderer.isWebGLRenderer ) {
45+
const texture = arg1, options = arg2;
4246

43-
console.error( 'EXRExporter.parse: Unsupported first parameter, expected instance of WebGLRenderer.' );
47+
supportedDT( texture );
4448

45-
return false;
49+
const info = buildInfoDT( texture, options ),
50+
dataBuffer = texture.image.data,
51+
rawContentBuffer = reorganizeDataBuffer( dataBuffer, info ),
52+
chunks = compressData( rawContentBuffer, info );
53+
54+
return fillData( chunks, info );
55+
56+
}
4657

4758
}
4859

60+
}
61+
62+
function supportedRTT( renderTarget ) {
63+
4964
if ( ! renderTarget || ! renderTarget.isWebGLRenderTarget ) {
5065

51-
console.error( 'EXRExporter.parse: Unsupported second parameter, expected instance of WebGLRenderTarget.' );
66+
throw Error( 'EXRExporter.parse: Unsupported second parameter, expected instance of WebGLRenderTarget.' );
67+
68+
}
69+
70+
if ( renderTarget.isWebGLCubeRenderTarget || renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {
5271

53-
return false;
72+
throw Error( 'EXRExporter.parse: Unsupported render target type, expected instance of WebGLRenderTarget.' );
5473

5574
}
5675

5776
if ( renderTarget.texture.type !== FloatType && renderTarget.texture.type !== HalfFloatType ) {
5877

59-
console.error( 'EXRExporter.parse: Unsupported WebGLRenderTarget texture type.' );
60-
61-
return false;
78+
throw Error( 'EXRExporter.parse: Unsupported WebGLRenderTarget texture type.' );
6279

6380
}
6481

6582
if ( renderTarget.texture.format !== RGBAFormat ) {
6683

67-
console.error( 'EXRExporter.parse: Unsupported WebGLRenderTarget texture format, expected RGBAFormat.' );
84+
throw Error( 'EXRExporter.parse: Unsupported WebGLRenderTarget texture format, expected RGBAFormat.' );
85+
86+
}
87+
88+
}
89+
90+
function supportedDT( texture ) {
91+
92+
if ( texture.type !== FloatType && texture.type !== HalfFloatType ) {
93+
94+
throw Error( 'EXRExporter.parse: Unsupported DataTexture texture type.' );
95+
96+
}
97+
98+
if ( texture.format !== RGBAFormat ) {
99+
100+
throw Error( 'EXRExporter.parse: Unsupported DataTexture texture format, expected RGBAFormat.' );
101+
102+
}
103+
104+
if ( ! texture.image.data ) {
105+
106+
throw Error( 'EXRExporter.parse: Invalid DataTexture image data.' );
107+
108+
}
109+
110+
if ( texture.type === FloatType && texture.image.data.constructor.name !== 'Float32Array' ) {
68111

69-
return false;
112+
throw Error( 'EXRExporter.parse: DataTexture image data doesn\'t match type, expected \'Float32Array\'.' );
70113

71114
}
72115

116+
if ( texture.type === HalfFloatType && texture.image.data.constructor.name !== 'Uint16Array' ) {
73117

74-
return true;
118+
throw Error( 'EXRExporter.parse: DataTexture image data doesn\'t match type, expected \'Uint16Array\'.' );
119+
120+
}
75121

76122
}
77123

78-
function buildInfo( renderTarget, options = {} ) {
124+
function buildInfoRTT( renderTarget, options = {} ) {
79125

80126
const compressionSizes = {
81127
0: 1,
@@ -87,7 +133,6 @@ function buildInfo( renderTarget, options = {} ) {
87133
HEIGHT = renderTarget.height,
88134
TYPE = renderTarget.texture.type,
89135
FORMAT = renderTarget.texture.format,
90-
COLOR_SPACE = renderTarget.texture.colorSpace,
91136
COMPRESSION = ( options.compression !== undefined ) ? options.compression : ZIP_COMPRESSION,
92137
EXPORTER_TYPE = ( options.type !== undefined ) ? options.type : HalfFloatType,
93138
OUT_TYPE = ( EXPORTER_TYPE === FloatType ) ? 2 : 1,
@@ -99,7 +144,40 @@ function buildInfo( renderTarget, options = {} ) {
99144
height: HEIGHT,
100145
type: TYPE,
101146
format: FORMAT,
102-
colorSpace: COLOR_SPACE,
147+
compression: COMPRESSION,
148+
blockLines: COMPRESSION_SIZE,
149+
dataType: OUT_TYPE,
150+
dataSize: 2 * OUT_TYPE,
151+
numBlocks: Math.ceil( HEIGHT / COMPRESSION_SIZE ),
152+
numInputChannels: 4,
153+
numOutputChannels: NUM_CHANNELS,
154+
};
155+
156+
}
157+
158+
function buildInfoDT( texture, options = {} ) {
159+
160+
const compressionSizes = {
161+
0: 1,
162+
2: 1,
163+
3: 16
164+
};
165+
166+
const WIDTH = texture.image.width,
167+
HEIGHT = texture.image.height,
168+
TYPE = texture.type,
169+
FORMAT = texture.format,
170+
COMPRESSION = ( options.compression !== undefined ) ? options.compression : ZIP_COMPRESSION,
171+
EXPORTER_TYPE = ( options.type !== undefined ) ? options.type : HalfFloatType,
172+
OUT_TYPE = ( EXPORTER_TYPE === FloatType ) ? 2 : 1,
173+
COMPRESSION_SIZE = compressionSizes[ COMPRESSION ],
174+
NUM_CHANNELS = 4;
175+
176+
return {
177+
width: WIDTH,
178+
height: HEIGHT,
179+
type: TYPE,
180+
format: FORMAT,
103181
compression: COMPRESSION,
104182
blockLines: COMPRESSION_SIZE,
105183
dataType: OUT_TYPE,

0 commit comments

Comments
 (0)