Skip to content
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

Allow textures to be encoded/decoded in Linear,sRGB,RGBE,RGBM, etc #8117

Merged
merged 34 commits into from
Feb 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
52a0262
add ability to have texel encodings (RGBE,RGBM,etc.) on envMap and em…
Feb 12, 2016
edf8e03
bug fixes.
Feb 12, 2016
1b5eeee
add links to helpful websites.
Feb 12, 2016
47aa1be
use standard GAMMA_FACTOR define.
Feb 12, 2016
94eca51
adopt new naming scheme per @mrdoob's recommendation.
Feb 20, 2016
15e08c1
add support for Texture.encoding to Material.map
Feb 20, 2016
7c2ffd1
set backwards compatible default.
Feb 20, 2016
3ca76ec
make encodings.glsl more reusable.
Feb 20, 2016
b057fed
begin on swithcing texture encodings from uniforms to macros.
Feb 20, 2016
e2c86da
adopt macro-defined encodings, remove uniform defined encodings.
Feb 20, 2016
17d1b90
add preprocessor that by default uses the ShaderChunk library.
Feb 20, 2016
e384007
remove THREE.DefaultEncoding and also old uniforms for encoding.
Feb 20, 2016
57432f0
get macros for encodings working.
Feb 20, 2016
84b70fd
cleanup PR.
Feb 20, 2016
a4c5926
remove unused encoding functions.
Feb 20, 2016
0951f96
simplify preprocessor, no need for reserve if I use pop.
Feb 20, 2016
79bcfdc
Merge branch 'dev' of git@github.com:mrdoob/three.js into texture_enc…
Feb 20, 2016
7ea1c67
fix bug with regards to emissiveMapTexelToLinear...
Feb 21, 2016
af4929e
fill in the LogLuv, RGBM, and RGBD decoders/encoders.
Feb 21, 2016
52bf6c6
ensure that particles also use map encodings.
Feb 21, 2016
15311e6
add true sRGB support for texture.encodings.
Feb 22, 2016
bdcb83a
try hand at using bvec3 with mix for optimizing sRGB linearization.
Feb 22, 2016
b34070b
fix order bug with mix-bvec3
Feb 22, 2016
e204686
cast bvec3 to vec3 so that mix works.
Feb 22, 2016
a1c225a
Merge branch 'dev' of git@github.com:mrdoob/three.js into texture_enc…
Feb 22, 2016
bc0d714
add better documentation that MAterial.needsUpdate needs to be set if…
Feb 23, 2016
f52454c
add comment in docs.
Feb 23, 2016
4cc3052
start addressing @mrdoob's feedback here: https://github.com/mrdoob/t…
Feb 24, 2016
c1aa769
Merge branch 'texture_encoding' of git@github.com:bhouston/three.js.g…
Feb 24, 2016
653a278
remove encoding_template and WebGLShaderPrePRocessor as mrdoob has re…
Feb 24, 2016
91d9af8
Merge branch 'dev' of git@github.com:mrdoob/three.js.git into texture…
Feb 24, 2016
c134418
add encodings to includes for primary frag shaders.
Feb 24, 2016
7fb2830
remove envMap encoding macro.
Feb 24, 2016
0d45254
remove remnants of WebGLShaderPreProcessor, re-add mistakenly removed…
Feb 24, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/api/textures/Texture.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ <h3>[property:boolean premultiplyAlpha]</h3>
False by default, which is the norm for PNG images. Set to true if the RGB values have been stored premultiplied by alpha.
</div>

<h3>[property:number encoding]</h3>
<div>
Set to THREE.LinearEncoding by default, but supports sRGB, RGBE, RGBM, RGBD, LogLuv and Gamma corrected encodings. IMPORTANT: If this value is changed on a texture after the material has been used, it is necessary to trigger a Material.needsUpdate for this value to be realized in the shader.
</div>

<h3>[property:object onUpdate]</h3>
<div>
A callback function, called when the texture is updated (e.g., when needsUpdate has been set to true and then the texture is used).
Expand Down
11 changes: 11 additions & 0 deletions src/Three.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,14 @@ THREE.WrapAroundEnding = 2402;
THREE.TrianglesDrawMode = 0;
THREE.TriangleStripDrawMode = 1;
THREE.TriangleFanDrawMode = 2;

// Texture Encodings

THREE.LinearEncoding = 3000; // No encoding at all.
THREE.sRGBEncoding = 3001;
THREE.RGBEEncoding = 3002; // AKA Radiance
THREE.LogLuvEncoding = 3003;
THREE.RGBM7Encoding = 3004;
THREE.RGBM16Encoding = 3005;
THREE.RGBDEncoding = 3006; // MaxRange is 256
THREE.GammaEncoding = 3007; // uses GAMMA_FACTOR
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

vec4 emissiveColor = texture2D( emissiveMap, vUv );

emissiveColor.rgb = inputToLinear( emissiveColor.rgb );
emissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;

totalEmissiveLight *= emissiveColor.rgb;

Expand Down
93 changes: 93 additions & 0 deletions src/renderers/shaders/ShaderChunk/encodings.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// For a discussion of what this is, please read this: http://lousodrome.net/blog/light/2013/05/26/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer/

// These encodings should have the same integer values as THREE.LinearEncoding, THREE.sRGBEncoding, etc...
#define ENCODING_Linear 3000
#define ENCODING_sRGB 3001
#define ENCODING_RGBE 3002
#define ENCODING_LogLuv 3003
#define ENCODING_RGBM7 3004
#define ENCODING_RGBM16 3005
#define ENCODING_RGBD 3006
#define ENCODING_Gamma 3007

vec4 LinearToLinear( in vec4 value ) {
return value;
}

vec4 GammaToLinear( in vec4 value, in float gammaFactor ) {
return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );
}
vec4 LinearTosGamma( in vec4 value, in float gammaFactor ) {
return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );
}

vec4 sRGBToLinear( in vec4 value ) {
return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );
}
vec4 LinearTosRGB( in vec4 value ) {
return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );
}

vec4 RGBEToLinear( in vec4 value ) {
return vec4( value.xyz * exp2( value.w*256.0 - 128.0 ), 1.0 );
}
vec4 LinearToRGBE( in vec4 value ) {
float maxComponent = max(max(value.r, value.g), value.b );
float fExp = ceil( log2(maxComponent) );
return vec4( value.rgb / exp2(fExp), (fExp + 128.0) / 255.0 );
}

// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html
vec4 RGBMToLinear( in vec4 value, in float maxRange ) {
return vec4( value.xyz * value.w * maxRange, 1.0 );
}
vec4 LinearToRGBM( in vec4 value, in float maxRange ) {
float maxRGB = max( value.x, max( value.g, value.b ) );
float M = maxRGB / maxRange;
M = ceil( M * 255.0 ) / 255.0;
return vec4( value.rgb / ( M * maxRange ), M );
}

// reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html
vec4 RGBDToLinear( in vec4 value, in float maxRange ) {
return vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );
}
vec4 LinearToRGBD( in vec4 value, in float maxRange ) {
float maxRGB = max( value.x, max( value.g, value.b ) );
float D = max( maxRange / maxRGB, 1.0 );
D = saturate( floor( D ) / 255.0 );
return vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );
}

// LogLuv reference: http://graphicrants.blogspot.ca/2009/04/rgbm-color-encoding.html

// M matrix, for encoding
const mat3 cLogLuvM = mat3(
0.2209, 0.3390, 0.4184,
0.1138, 0.6780, 0.7319,
0.0102, 0.1130, 0.2969);
vec4 LinearToLogLuv( in vec4 value ) {
vec3 Xp_Y_XYZp = value.rgb * cLogLuvM;
Xp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));
vec4 vResult;
vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;
float Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;
vResult.w = fract(Le);
vResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;
return vResult;
}

// Inverse M matrix, for decoding
const mat3 cLogLuvInverseM = mat3(
6.0014, -2.7008, -1.7996,
-1.3320, 3.1029, -5.7721,
0.3008, -1.0882, 5.6268);
vec4 LogLuvToLinear( in vec4 value ) {
float Le = value.z * 255.0 + value.w;
vec3 Xp_Y_XYZp;
Xp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);
Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;
Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;
vec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;
return vec4( max(vRGB, 0.0), 1.0 );
}
2 changes: 1 addition & 1 deletion src/renderers/shaders/ShaderChunk/envmap_fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );
#endif

envColor.xyz = inputToLinear( envColor.xyz );
envColor = envMapTexelToLinear( envColor );

#ifdef ENVMAP_BLENDING_MULTIPLY

Expand Down
4 changes: 2 additions & 2 deletions src/renderers/shaders/ShaderChunk/lights_pars.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@

#endif

envMapColor.rgb = inputToLinear( envMapColor.rgb );
envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;

return PI * envMapColor.rgb * envMapIntensity;

Expand Down Expand Up @@ -277,7 +277,7 @@

#endif

envMapColor.rgb = inputToLinear( envMapColor.rgb );
envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;

return envMapColor.rgb * envMapIntensity;

Expand Down
3 changes: 1 addition & 2 deletions src/renderers/shaders/ShaderChunk/map_fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

vec4 texelColor = texture2D( map, vUv );

texelColor.xyz = inputToLinear( texelColor.xyz );

texelColor = mapTexelToLinear( texelColor );
diffuseColor *= texelColor;

#endif
2 changes: 1 addition & 1 deletion src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

uniform sampler2D map;

#endif
#endif
5 changes: 3 additions & 2 deletions src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#ifdef USE_MAP

diffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );

vec4 mapTexel= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );
diffuseColor *= mapTexelToLinear( mapTexel );

#endif
5 changes: 5 additions & 0 deletions src/renderers/shaders/ShaderLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ THREE.ShaderLib = {
"#endif",

'#include <common>',
'#include <encodings>',
'#include <color_pars_fragment>',
'#include <uv_pars_fragment>',
'#include <uv2_pars_fragment>',
Expand Down Expand Up @@ -199,6 +200,7 @@ THREE.ShaderLib = {
"#endif",

'#include <common>',
'#include <encodings>',
'#include <color_pars_fragment>',
'#include <uv_pars_fragment>',
'#include <uv2_pars_fragment>',
Expand Down Expand Up @@ -363,6 +365,7 @@ THREE.ShaderLib = {
"uniform float opacity;",

'#include <common>',
'#include <encodings>',
'#include <color_pars_fragment>',
'#include <uv_pars_fragment>',
'#include <uv2_pars_fragment>',
Expand Down Expand Up @@ -526,6 +529,7 @@ THREE.ShaderLib = {
"#endif",

'#include <common>',
'#include <encodings>',
'#include <color_pars_fragment>',
'#include <uv_pars_fragment>',
'#include <uv2_pars_fragment>',
Expand Down Expand Up @@ -630,6 +634,7 @@ THREE.ShaderLib = {
"uniform float opacity;",

'#include <common>',
'#include <encodings>',
'#include <color_pars_fragment>',
'#include <map_particle_pars_fragment>',
'#include <fog_pars_fragment>',
Expand Down
2 changes: 1 addition & 1 deletion src/renderers/shaders/UniformsLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ THREE.UniformsLib = {

emissivemap: {

"emissiveMap": { type: "t", value: null }
"emissiveMap": { type: "t", value: null },

},

Expand Down
34 changes: 34 additions & 0 deletions src/renderers/webgl/WebGLProgram.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,37 @@ THREE.WebGLProgram = ( function () {
var arrayStructRe = /^([\w\d_]+)\[(\d+)\]\.([\w\d_]+)$/;
var arrayRe = /^([\w\d_]+)\[0\]$/;

function getTexelDecodingFunction( functionName, encoding ) {
var code = "vec4 " + functionName + "( vec4 value ) { return ";
switch( encoding ) {
case THREE.LinearEncoding:
code += "value";
break;
case THREE.sRGBEncoding:
code += "sRGBToLinear( value )";
break;
case THREE.RGBEEncoding:
code += "RGBEToLinear( value )";
break;
case THREE.RGBM7Encoding:
code += "RGBMToLinear( value, 7.0 )";
break;
case THREE.RGBM16Encoding:
code += "RGBMToLinear( value, 16.0 )";
break;
case THREE.RGBDEncoding:
code += "RGBDToLinear( value, 256.0 )";
break;
case THREE.GammaEncoding:
code += "GammaToLinear( value, float( GAMMA_FACTOR ) )";
break;
default:
throw new Error( "unsupported encoding: " + encoding );
}
code += "; }";
return code;
}

function generateExtensions( extensions, parameters, rendererExtensions ) {

extensions = extensions || {};
Expand Down Expand Up @@ -420,13 +451,16 @@ THREE.WebGLProgram = ( function () {
( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',

parameters.map ? '#define USE_MAP' : '',
parameters.mapEncoding ? getTexelDecodingFunction( "mapTexelToLinear", material.map.encoding ) : '',
parameters.envMap ? '#define USE_ENVMAP' : '',
parameters.envMap ? '#define ' + envMapTypeDefine : '',
parameters.envMap ? '#define ' + envMapModeDefine : '',
parameters.envMap ? '#define ' + envMapBlendingDefine : '',
parameters.lightMap ? '#define USE_LIGHTMAP' : '',
parameters.envMapEncoding ? getTexelDecodingFunction( "envMapTexelToLinear", material.envMap.encoding ) : '',
parameters.aoMap ? '#define USE_AOMAP' : '',
parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
parameters.emissiveMapEncoding ? getTexelDecodingFunction( "emissiveMapTexelToLinear", material.emissiveMap.encoding ) : '',
parameters.bumpMap ? '#define USE_BUMPMAP' : '',
parameters.normalMap ? '#define USE_NORMALMAP' : '',
parameters.specularMap ? '#define USE_SPECULARMAP' : '',
Expand Down
7 changes: 5 additions & 2 deletions src/renderers/webgl/WebGLPrograms.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ THREE.WebGLPrograms = function ( renderer, capabilities ) {
};

var parameterNames = [
"precision", "supportsVertexTextures", "map", "envMap", "envMapMode",
"lightMap", "aoMap", "emissiveMap", "bumpMap", "normalMap", "displacementMap", "specularMap",
"precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap",
"roughnessMap", "metalnessMap",
"alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
Expand Down Expand Up @@ -96,11 +96,14 @@ THREE.WebGLPrograms = function ( renderer, capabilities ) {
supportsVertexTextures: capabilities.vertexTextures,

map: !! material.map,
mapEncoding: ( !! material.map ) ? material.map.encoding : false,
envMap: !! material.envMap,
envMapMode: material.envMap && material.envMap.mapping,
envMapEncoding: ( !! material.envMap ) ? material.envMap.encoding : false,
lightMap: !! material.lightMap,
aoMap: !! material.aoMap,
emissiveMap: !! material.emissiveMap,
emissiveMapEncoding: ( !! material.emissiveMap ) ? material.emissiveMap.encoding : false,
bumpMap: !! material.bumpMap,
normalMap: !! material.normalMap,
displacementMap: !! material.displacementMap,
Expand Down
10 changes: 9 additions & 1 deletion src/textures/Texture.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,14 @@ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, f
this.generateMipmaps = true;
this.premultiplyAlpha = false;
this.flipY = true;
this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)


// Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
//
// Also changing the encoding after already used by a Material will not automatically make the Material
// update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
this.encoding = THREE.LinearEncoding;

this.version = 0;
this.onUpdate = null;
Expand Down Expand Up @@ -86,6 +93,7 @@ THREE.Texture.prototype = {
this.premultiplyAlpha = source.premultiplyAlpha;
this.flipY = source.flipY;
this.unpackAlignment = source.unpackAlignment;
this.encoding = source.encoding;

return this;

Expand Down
1 change: 1 addition & 0 deletions utils/build/includes/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
"src/renderers/shaders/ShaderChunk/displacementmap_pars_vertex.glsl",
"src/renderers/shaders/ShaderChunk/emissivemap_fragment.glsl",
"src/renderers/shaders/ShaderChunk/emissivemap_pars_fragment.glsl",
"src/renderers/shaders/ShaderChunk/encodings.glsl",
"src/renderers/shaders/ShaderChunk/envmap_fragment.glsl",
"src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl",
"src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl",
Expand Down