@@ -13,6 +13,8 @@ import { RenderPassPrepass } from './render-pass-prepass.js';
13
13
import { RenderPassSsao } from './render-pass-ssao.js' ;
14
14
import { SSAOTYPE_COMBINE , SSAOTYPE_LIGHTING , SSAOTYPE_NONE } from './constants.js' ;
15
15
import { Debug } from '../../core/debug.js' ;
16
+ import { RenderPassDownsample } from './render-pass-downsample.js' ;
17
+ import { Color } from '../../core/math/color.js' ;
16
18
17
19
class CameraFrameOptions {
18
20
formats ;
@@ -71,6 +73,8 @@ class RenderPassCameraFrame extends RenderPass {
71
73
72
74
taaPass ;
73
75
76
+ scenePassHalf ;
77
+
74
78
_renderTargetScale = 1 ;
75
79
76
80
/**
@@ -96,13 +100,20 @@ class RenderPassCameraFrame extends RenderPass {
96
100
reset ( ) {
97
101
98
102
this . sceneTexture = null ;
103
+ this . sceneTextureHalf = null ;
99
104
100
105
if ( this . rt ) {
101
106
this . rt . destroyTextureBuffers ( ) ;
102
107
this . rt . destroy ( ) ;
103
108
this . rt = null ;
104
109
}
105
110
111
+ if ( this . rtHalf ) {
112
+ this . rtHalf . destroyTextureBuffers ( ) ;
113
+ this . rtHalf . destroy ( ) ;
114
+ this . rtHalf = null ;
115
+ }
116
+
106
117
// destroy all passes we created
107
118
this . beforePasses . forEach ( pass => pass . destroy ( ) ) ;
108
119
this . beforePasses . length = 0 ;
@@ -116,6 +127,7 @@ class RenderPassCameraFrame extends RenderPass {
116
127
this . ssaoPass = null ;
117
128
this . taaPass = null ;
118
129
this . afterPass = null ;
130
+ this . scenePassHalf = null ;
119
131
}
120
132
121
133
sanitizeOptions ( options ) {
@@ -180,6 +192,29 @@ class RenderPassCameraFrame extends RenderPass {
180
192
}
181
193
}
182
194
195
+ createRenderTarget ( name , depth , stencil , samples , flipY ) {
196
+
197
+ const texture = new Texture ( this . device , {
198
+ name : name ,
199
+ width : 4 ,
200
+ height : 4 ,
201
+ format : this . hdrFormat ,
202
+ mipmaps : false ,
203
+ minFilter : FILTER_LINEAR ,
204
+ magFilter : FILTER_LINEAR ,
205
+ addressU : ADDRESS_CLAMP_TO_EDGE ,
206
+ addressV : ADDRESS_CLAMP_TO_EDGE
207
+ } ) ;
208
+
209
+ return new RenderTarget ( {
210
+ colorBuffer : texture ,
211
+ depth : depth ,
212
+ stencil : stencil ,
213
+ samples : samples ,
214
+ flipY : flipY
215
+ } ) ;
216
+ }
217
+
183
218
setupRenderPasses ( options ) {
184
219
185
220
const { device } = this ;
@@ -188,6 +223,12 @@ class RenderPassCameraFrame extends RenderPass {
188
223
189
224
this . hdrFormat = device . getRenderableHdrFormat ( options . formats , true , options . samples ) || PIXELFORMAT_RGBA8 ;
190
225
226
+ // HDR bloom is not supported on RGBA8 format
227
+ this . _bloomEnabled = options . bloomEnabled && this . hdrFormat !== PIXELFORMAT_RGBA8 ;
228
+
229
+ // bloom needs half resolution scene texture
230
+ this . _sceneHalfEnabled = this . _bloomEnabled ;
231
+
191
232
// camera renders in HDR mode (linear output, no tonemapping)
192
233
cameraComponent . gammaCorrection = GAMMA_NONE ;
193
234
cameraComponent . toneMapping = TONEMAP_NONE ;
@@ -196,25 +237,15 @@ class RenderPassCameraFrame extends RenderPass {
196
237
cameraComponent . shaderParams . ssaoEnabled = options . ssaoType === SSAOTYPE_LIGHTING ;
197
238
198
239
// create a render target to render the scene into
199
- this . sceneTexture = new Texture ( device , {
200
- name : 'SceneColor' ,
201
- width : 4 ,
202
- height : 4 ,
203
- format : this . hdrFormat ,
204
- mipmaps : false ,
205
- minFilter : FILTER_LINEAR ,
206
- magFilter : FILTER_LINEAR ,
207
- addressU : ADDRESS_CLAMP_TO_EDGE ,
208
- addressV : ADDRESS_CLAMP_TO_EDGE
209
- } ) ;
210
-
211
- this . rt = new RenderTarget ( {
212
- colorBuffer : this . sceneTexture ,
213
- depth : true ,
214
- stencil : options . stencil ,
215
- samples : options . samples ,
216
- flipY : ! ! targetRenderTarget ?. flipY // flipY is inherited from the target renderTarget
217
- } ) ;
240
+ const flipY = ! ! targetRenderTarget ?. flipY ; // flipY is inherited from the target renderTarget
241
+ this . rt = this . createRenderTarget ( 'SceneColor' , true , options . stencil , options . samples , flipY ) ;
242
+ this . sceneTexture = this . rt . colorBuffer ;
243
+
244
+ // when half size scene color buffer is used
245
+ if ( this . _sceneHalfEnabled ) {
246
+ this . rtHalf = this . createRenderTarget ( 'SceneColorHalf' , false , false , 1 , flipY ) ;
247
+ this . sceneTextureHalf = this . rtHalf . colorBuffer ;
248
+ }
218
249
219
250
this . sceneOptions = {
220
251
resizeSource : targetRenderTarget ,
@@ -231,7 +262,7 @@ class RenderPassCameraFrame extends RenderPass {
231
262
collectPasses ( ) {
232
263
233
264
// use these prepared render passes in the order they should be executed
234
- return [ this . prePass , this . ssaoPass , this . scenePass , this . colorGrabPass , this . scenePassTransparent , this . taaPass , this . bloomPass , this . composePass , this . afterPass ] ;
265
+ return [ this . prePass , this . ssaoPass , this . scenePass , this . colorGrabPass , this . scenePassTransparent , this . taaPass , this . scenePassHalf , this . bloomPass , this . composePass , this . afterPass ] ;
235
266
}
236
267
237
268
createPasses ( options ) {
@@ -248,8 +279,11 @@ class RenderPassCameraFrame extends RenderPass {
248
279
// TAA
249
280
const sceneTextureWithTaa = this . setupTaaPass ( options ) ;
250
281
282
+ // downscale to half resolution
283
+ this . setupSceneHalfPass ( options , sceneTextureWithTaa ) ;
284
+
251
285
// bloom
252
- this . setupBloomPass ( options , sceneTextureWithTaa ) ;
286
+ this . setupBloomPass ( options , this . sceneTextureHalf ) ;
253
287
254
288
// compose
255
289
this . setupComposePass ( options ) ;
@@ -328,9 +362,23 @@ class RenderPassCameraFrame extends RenderPass {
328
362
}
329
363
}
330
364
365
+ setupSceneHalfPass ( options , sourceTexture ) {
366
+
367
+ if ( this . _sceneHalfEnabled ) {
368
+ this . scenePassHalf = new RenderPassDownsample ( this . device , this . sceneTexture , true ) ;
369
+ this . scenePassHalf . name = 'RenderPassSceneHalf' ;
370
+ this . scenePassHalf . init ( this . rtHalf , {
371
+ resizeSource : sourceTexture ,
372
+ scaleX : 0.5 ,
373
+ scaleY : 0.5
374
+ } ) ;
375
+ this . scenePassHalf . setClearColor ( Color . BLACK ) ;
376
+ }
377
+ }
378
+
331
379
setupBloomPass ( options , inputTexture ) {
332
- // HDR bloom is not supported on RGBA8 format
333
- if ( options . bloomEnabled && this . hdrFormat !== PIXELFORMAT_RGBA8 ) {
380
+
381
+ if ( this . _bloomEnabled ) {
334
382
// create a bloom pass, which generates bloom texture based on the provided texture
335
383
this . bloomPass = new RenderPassBloom ( this . device , inputTexture , this . hdrFormat ) ;
336
384
}
@@ -387,9 +435,7 @@ class RenderPassCameraFrame extends RenderPass {
387
435
388
436
// TAA history buffer is double buffered, assign the current one to the follow up passes.
389
437
this . composePass . sceneTexture = sceneTexture ;
390
- if ( this . options . bloomEnabled && this . bloomPass ) {
391
- this . bloomPass . sourceTexture = sceneTexture ;
392
- }
438
+ this . scenePassHalf ?. setSourceTexture ( sceneTexture ) ;
393
439
}
394
440
}
395
441
0 commit comments