-
Notifications
You must be signed in to change notification settings - Fork 6
/
GainMapDecoderMaterial.ts
161 lines (144 loc) · 5.35 KB
/
GainMapDecoderMaterial.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import { NoBlending, ShaderMaterial, Texture, Vector3 } from 'three'
import { GainMapMetadata } from '../../core/types'
import { GainmapDecodingParameters } from '../types'
const vertexShader = /* glsl */`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
const fragmentShader = /* glsl */`
// min half float value
#define HALF_FLOAT_MIN vec3( -65504, -65504, -65504 )
// max half float value
#define HALF_FLOAT_MAX vec3( 65504, 65504, 65504 )
uniform sampler2D sdr;
uniform sampler2D gainMap;
uniform vec3 gamma;
uniform vec3 offsetHdr;
uniform vec3 offsetSdr;
uniform vec3 gainMapMin;
uniform vec3 gainMapMax;
uniform float weightFactor;
varying vec2 vUv;
void main() {
vec3 rgb = texture2D( sdr, vUv ).rgb;
vec3 recovery = texture2D( gainMap, vUv ).rgb;
vec3 logRecovery = pow( recovery, gamma );
vec3 logBoost = gainMapMin * ( 1.0 - logRecovery ) + gainMapMax * logRecovery;
vec3 hdrColor = (rgb + offsetSdr) * exp2( logBoost * weightFactor ) - offsetHdr;
vec3 clampedHdrColor = max( HALF_FLOAT_MIN, min( HALF_FLOAT_MAX, hdrColor ));
gl_FragColor = vec4( clampedHdrColor , 1.0 );
}
`
/**
* A Material which is able to decode the Gainmap into a full HDR Representation
*
* @category Materials
* @group Materials
*/
export class GainMapDecoderMaterial extends ShaderMaterial {
private _maxDisplayBoost: GainmapDecodingParameters['maxDisplayBoost']
private _hdrCapacityMin: GainMapMetadata['hdrCapacityMin']
private _hdrCapacityMax: GainMapMetadata['hdrCapacityMax']
/**
*
* @param params
*/
constructor ({ gamma, offsetHdr, offsetSdr, gainMapMin, gainMapMax, maxDisplayBoost, hdrCapacityMin, hdrCapacityMax, sdr, gainMap }: GainMapMetadata & GainmapDecodingParameters & { sdr: Texture, gainMap: Texture }) {
super({
name: 'GainMapDecoderMaterial',
vertexShader,
fragmentShader,
uniforms: {
sdr: { value: sdr },
gainMap: { value: gainMap },
gamma: { value: new Vector3(1.0 / gamma[0], 1.0 / gamma[1], 1.0 / gamma[2]) },
offsetHdr: { value: new Vector3().fromArray(offsetHdr) },
offsetSdr: { value: new Vector3().fromArray(offsetSdr) },
gainMapMin: { value: new Vector3().fromArray(gainMapMin) },
gainMapMax: { value: new Vector3().fromArray(gainMapMax) },
weightFactor: {
value: (Math.log2(maxDisplayBoost) - hdrCapacityMin) / (hdrCapacityMax - hdrCapacityMin)
}
},
blending: NoBlending,
depthTest: false,
depthWrite: false
})
this._maxDisplayBoost = maxDisplayBoost
this._hdrCapacityMin = hdrCapacityMin
this._hdrCapacityMax = hdrCapacityMax
this.needsUpdate = true
this.uniformsNeedUpdate = true
}
get sdr () { return this.uniforms.sdr.value as Texture }
set sdr (value: Texture) { this.uniforms.sdr.value = value }
get gainMap () { return this.uniforms.gainMap.value as Texture }
set gainMap (value: Texture) { this.uniforms.gainMap.value = value }
/**
* @see {@link GainMapMetadata.offsetHdr}
*/
get offsetHdr () { return (this.uniforms.offsetHdr.value as Vector3).toArray() }
set offsetHdr (value: [number, number, number]) { (this.uniforms.offsetHdr.value as Vector3).fromArray(value) }
/**
* @see {@link GainMapMetadata.offsetSdr}
*/
get offsetSdr () { return (this.uniforms.offsetSdr.value as Vector3).toArray() }
set offsetSdr (value: [number, number, number]) { (this.uniforms.offsetSdr.value as Vector3).fromArray(value) }
/**
* @see {@link GainMapMetadata.gainMapMin}
*/
get gainMapMin () { return (this.uniforms.gainMapMin.value as Vector3).toArray() }
set gainMapMin (value: [number, number, number]) { (this.uniforms.gainMapMin.value as Vector3).fromArray(value) }
/**
* @see {@link GainMapMetadata.gainMapMax}
*/
get gainMapMax () { return (this.uniforms.gainMapMax.value as Vector3).toArray() }
set gainMapMax (value: [number, number, number]) { (this.uniforms.gainMapMax.value as Vector3).fromArray(value) }
/**
* @see {@link GainMapMetadata.gamma}
*/
get gamma () {
const g = (this.uniforms.gamma.value as Vector3)
return [1 / g.x, 1 / g.y, 1 / g.z] as [number, number, number]
}
set gamma (value: [number, number, number]) {
const g = (this.uniforms.gamma.value as Vector3)
g.x = 1.0 / value[0]
g.y = 1.0 / value[1]
g.z = 1.0 / value[2]
}
/**
* @see {@link GainMapMetadata.hdrCapacityMin}
* @remarks Logarithmic space
*/
get hdrCapacityMin () { return this._hdrCapacityMin }
set hdrCapacityMin (value: number) {
this._hdrCapacityMin = value
this.calculateWeight()
}
/**
* @see {@link GainMapMetadata.hdrCapacityMin}
* @remarks Logarithmic space
*/
get hdrCapacityMax () { return this._hdrCapacityMax }
set hdrCapacityMax (value: number) {
this._hdrCapacityMax = value
this.calculateWeight()
}
/**
* @see {@link GainmapDecodingParameters.maxDisplayBoost}
* @remarks Non Logarithmic space
*/
get maxDisplayBoost () { return this._maxDisplayBoost }
set maxDisplayBoost (value: number) {
this._maxDisplayBoost = Math.max(1, Math.min(65504, value))
this.calculateWeight()
}
private calculateWeight () {
const val = (Math.log2(this._maxDisplayBoost) - this._hdrCapacityMin) / (this._hdrCapacityMax - this._hdrCapacityMin)
this.uniforms.weightFactor.value = Math.max(0, Math.min(1, val))
}
}