Skip to content

Commit

Permalink
refactor: move to TextureUtils class and use that in GLTFExporter, re…
Browse files Browse the repository at this point in the history
…spect sRGB vs. Linear, cache some generated objects
  • Loading branch information
hybridherbst committed Nov 24, 2022
1 parent 22a8e81 commit dc59c08
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 63 deletions.
72 changes: 9 additions & 63 deletions examples/jsm/exporters/GLTFExporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,10 @@ import {
Scene,
Source,
sRGBEncoding,
Texture,
CompressedTexture,
PlaneGeometry,
ShaderMaterial,
Mesh,
PerspectiveCamera,
WebGLRenderer,
Uniform,
Vector3
} from 'three';
import { decompress } from './../utils/TextureUtils.js';

class GLTFExporter {

Expand Down Expand Up @@ -545,13 +539,6 @@ class GLTFWriter {

}

// Clean up in case we had to create a temporary renderer for blitting compressed textures.
if (this.temporaryRenderer) {

this.temporaryRenderer.dispose();

}

}

/**
Expand Down Expand Up @@ -730,49 +717,6 @@ class GLTFWriter {

}

buildReadableTexture( map, maxTextureSize ) {

const fullscreenQuadGeometry = new PlaneGeometry( 2, 2, 1, 1 );
const fullscreenQuadMaterial = new ShaderMaterial( {
uniforms: { blitTexture: new Uniform( map ) },
vertexShader: `
varying vec2 vUv;
void main(){
vUv = uv;
gl_Position = vec4(position.xy * 1.0,0.,.999999);
}`,
fragmentShader: `
uniform sampler2D blitTexture;
varying vec2 vUv;
void main(){
gl_FragColor = vec4(vUv.xy, 0, 1);
gl_FragColor = texture2D( blitTexture, vUv);
}`
} );

const fullscreenQuad = new Mesh( fullscreenQuadGeometry, fullscreenQuadMaterial );
fullscreenQuad.frustrumCulled = false;

const temporaryCam = new PerspectiveCamera();
const temporaryScene = new Scene();
temporaryScene.add( fullscreenQuad );

if (!this.temporaryRenderer) {

this.temporaryRenderer = new WebGLRenderer( { antialias: false } );

}

this.temporaryRenderer.setSize( Math.min(map.image.width, maxTextureSize), Math.min(map.image.height, maxTextureSize) );
this.temporaryRenderer.clear();
this.temporaryRenderer.render( temporaryScene, temporaryCam );

const readableTexture = new Texture( this.temporaryRenderer.domElement );
readableTexture.userData.mimeType = 'image/png';
return readableTexture;

}

buildMetalRoughTexture( metalnessMap, roughnessMap ) {

if ( metalnessMap === roughnessMap ) return metalnessMap;
Expand Down Expand Up @@ -801,17 +745,17 @@ class GLTFWriter {

console.warn( 'THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.' );

if ( typeof CompressedTexture !== 'undefined') {
if ( typeof CompressedTexture !== 'undefined' ) {

if ( metalnessMap instanceof CompressedTexture ) {

metalnessMap = this.buildReadableTexture( metalnessMap );
metalnessMap = decompress( metalnessMap );

}

if ( roughnessMap instanceof CompressedTexture ) {

roughnessMap = this.buildReadableTexture( roughnessMap );
roughnessMap = decompress( roughnessMap );

}

Expand Down Expand Up @@ -1209,6 +1153,7 @@ class GLTFWriter {
console.error( 'GLTFExporter: Only RGBAFormat is supported.', image );

}

if ( image.width > options.maxTextureSize || image.height > options.maxTextureSize ) {

console.warn( 'GLTFExporter: Image size is bigger than maxTextureSize', image );
Expand Down Expand Up @@ -1335,13 +1280,14 @@ class GLTFWriter {
let modifiedMap = map;

// make non-readable textures (e.g. CompressedTexture) readable by blitting them into a new texture
// TODO: how to detect that a texture isn't readable?
if ( typeof CompressedTexture !== 'undefined' && map instanceof CompressedTexture ) {

modifiedMap = this.buildReadableTexture( map, options.maxTextureSize );
modifiedMap = decompress( map, options.maxTextureSize );
// remove from cache, as the underlaying canvas is always the same between decompressed textures
cache.images.delete( modifiedMap.image );

}

let mimeType = modifiedMap.userData.mimeType;

if ( mimeType === 'image/webp' ) mimeType = 'image/png';
Expand Down
85 changes: 85 additions & 0 deletions examples/jsm/utils/TextureUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {
PlaneGeometry,
ShaderMaterial,
Uniform,
Mesh,
PerspectiveCamera,
Scene,
WebGLRenderer,
Texture,
sRGBEncoding
} from 'three';

let temporaryRenderer;
let fullscreenQuadGeometry;
let fullscreenQuadMaterial;
let fullscreenQuad;

function decompress( texture, maxTextureSize, renderer ) {

if ( !fullscreenQuadGeometry ) fullscreenQuadGeometry = new PlaneGeometry( 2, 2, 1, 1 );
if ( !fullscreenQuadMaterial ) fullscreenQuadMaterial = new ShaderMaterial( {
uniforms: { blitTexture: new Uniform( texture ) },
vertexShader: `
varying vec2 vUv;
void main(){
vUv = uv;
gl_Position = vec4(position.xy * 1.0,0.,.999999);
}`,
fragmentShader: `
uniform sampler2D blitTexture;
varying vec2 vUv;
// took from threejs 05fc79cd52b79e8c3e8dec1e7dca72c5c39983a4
vec4 conv_LinearTosRGB( in vec4 value ) {
return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
}
void main(){
gl_FragColor = vec4(vUv.xy, 0, 1);
#ifdef IS_SRGB
gl_FragColor = conv_LinearTosRGB( texture2D( blitTexture, vUv) );
#else
gl_FragColor = texture2D( blitTexture, vUv);
#endif
}`
} );

fullscreenQuadMaterial.uniforms.blitTexture.value = texture;
fullscreenQuadMaterial.defines.IS_SRGB = texture.encoding == sRGBEncoding;

if ( !fullscreenQuad ) {

fullscreenQuad = new Mesh( fullscreenQuadGeometry, fullscreenQuadMaterial );
fullscreenQuad.frustrumCulled = false;

}

const temporaryCam = new PerspectiveCamera();
const temporaryScene = new Scene();
temporaryScene.add( fullscreenQuad );

if ( !renderer ) {

if ( !temporaryRenderer )
temporaryRenderer = new WebGLRenderer( { antialias: false } );

renderer = temporaryRenderer;

}

renderer.setSize( Math.min(texture.image.width, maxTextureSize), Math.min(texture.image.height, maxTextureSize) );
renderer.clear();
renderer.render( temporaryScene, temporaryCam );

const readableTexture = new Texture( renderer.domElement );
readableTexture.userData.mimeType = 'image/png';
console.log(readableTexture, readableTexture.image)

return readableTexture;

}

export {
decompress
}

0 comments on commit dc59c08

Please sign in to comment.