Skip to content

Commit 4c36f5f

Browse files
authored
WebGPURenderer: Added double-side transmission 2/2 (#29718)
* renders all back-side first in case of materials with transmission * cleanup
1 parent 9aa74de commit 4c36f5f

File tree

2 files changed

+85
-11
lines changed

2 files changed

+85
-11
lines changed

src/renderers/common/RenderList.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { DoubleSide } from '../../constants.js';
2+
13
function painterSortStable( a, b ) {
24

35
if ( a.groupOrder !== b.groupOrder ) {
@@ -46,6 +48,14 @@ function reversePainterSortStable( a, b ) {
4648

4749
}
4850

51+
function needsDoublePass( material ) {
52+
53+
const hasTransmission = material.transmission > 0 || material.transmissionNode;
54+
55+
return hasTransmission && material.side === DoubleSide && material.forceSinglePass === false;
56+
57+
}
58+
4959
class RenderList {
5060

5161
constructor( lighting, scene, camera ) {
@@ -54,6 +64,7 @@ class RenderList {
5464
this.renderItemsIndex = 0;
5565

5666
this.opaque = [];
67+
this.transparentDoublePass = [];
5768
this.transparent = [];
5869
this.bundles = [];
5970

@@ -72,6 +83,7 @@ class RenderList {
7283
this.renderItemsIndex = 0;
7384

7485
this.opaque.length = 0;
86+
this.transparentDoublePass.length = 0;
7587
this.transparent.length = 0;
7688
this.bundles.length = 0;
7789

@@ -127,15 +139,35 @@ class RenderList {
127139

128140
if ( object.occlusionTest === true ) this.occlusionQueryCount ++;
129141

130-
( material.transparent === true || material.transmission > 0 ? this.transparent : this.opaque ).push( renderItem );
142+
if ( material.transparent === true || material.transmission > 0 ) {
143+
144+
if ( needsDoublePass( material ) ) this.transparentDoublePass.push( renderItem );
145+
146+
this.transparent.push( renderItem );
147+
148+
} else {
149+
150+
this.opaque.push( renderItem );
151+
152+
}
131153

132154
}
133155

134156
unshift( object, geometry, material, groupOrder, z, group ) {
135157

136158
const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group );
137159

138-
( material.transparent === true ? this.transparent : this.opaque ).unshift( renderItem );
160+
if ( material.transparent === true || material.transmission > 0 ) {
161+
162+
if ( needsDoublePass( material ) ) this.transparentDoublePass.unshift( renderItem );
163+
164+
this.transparent.unshift( renderItem );
165+
166+
} else {
167+
168+
this.opaque.unshift( renderItem );
169+
170+
}
139171

140172
}
141173

@@ -154,6 +186,7 @@ class RenderList {
154186
sort( customOpaqueSort, customTransparentSort ) {
155187

156188
if ( this.opaque.length > 1 ) this.opaque.sort( customOpaqueSort || painterSortStable );
189+
if ( this.transparentDoublePass.length > 1 ) this.transparentDoublePass.sort( customTransparentSort || reversePainterSortStable );
157190
if ( this.transparent.length > 1 ) this.transparent.sort( customTransparentSort || reversePainterSortStable );
158191

159192
}

src/renderers/common/Renderer.js

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ class Renderer {
370370
const lightsNode = renderList.lightsNode;
371371

372372
if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );
373-
if ( this.transparent === true && transparentObjects.length > 0 ) this._renderObjects( transparentObjects, camera, sceneRef, lightsNode );
373+
if ( this.transparent === true && transparentObjects.length > 0 ) this._renderTransparents( transparentObjects, camera, sceneRef, lightsNode );
374374

375375
// restore render tree
376376

@@ -452,7 +452,7 @@ class Renderer {
452452

453453
const opaqueObjects = renderList.opaque;
454454

455-
if ( opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );
455+
if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );
456456

457457
this._currentRenderBundle = null;
458458

@@ -728,13 +728,14 @@ class Renderer {
728728
const {
729729
bundles,
730730
lightsNode,
731+
transparentDoublePass: transparentDoublePassObjects,
731732
transparent: transparentObjects,
732733
opaque: opaqueObjects
733734
} = renderList;
734735

735736
if ( bundles.length > 0 ) this._renderBundles( bundles, sceneRef, lightsNode );
736737
if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );
737-
if ( this.transparent === true && transparentObjects.length > 0 ) this._renderObjects( transparentObjects, camera, sceneRef, lightsNode );
738+
if ( this.transparent === true && transparentObjects.length > 0 ) this._renderTransparents( transparentObjects, transparentDoublePassObjects, camera, sceneRef, lightsNode );
738739

739740
// finish render pass
740741

@@ -1438,7 +1439,47 @@ class Renderer {
14381439

14391440
}
14401441

1441-
_renderObjects( renderList, camera, scene, lightsNode ) {
1442+
_renderTransparents( renderList, doublePassList, camera, scene, lightsNode ) {
1443+
1444+
if ( doublePassList.length > 0 ) {
1445+
1446+
// render back side
1447+
1448+
for ( const { material } of doublePassList ) {
1449+
1450+
material.side = BackSide;
1451+
1452+
}
1453+
1454+
this._renderObjects( doublePassList, camera, scene, lightsNode, 'backSide' );
1455+
1456+
// render front side
1457+
1458+
for ( const { material } of doublePassList ) {
1459+
1460+
material.side = FrontSide;
1461+
1462+
}
1463+
1464+
this._renderObjects( renderList, camera, scene, lightsNode );
1465+
1466+
// restore
1467+
1468+
for ( const { material } of doublePassList ) {
1469+
1470+
material.side = DoubleSide;
1471+
1472+
}
1473+
1474+
} else {
1475+
1476+
this._renderObjects( renderList, camera, scene, lightsNode );
1477+
1478+
}
1479+
1480+
}
1481+
1482+
_renderObjects( renderList, camera, scene, lightsNode, passId = null ) {
14421483

14431484
// process renderable objects
14441485

@@ -1472,23 +1513,23 @@ class Renderer {
14721513

14731514
this.backend.updateViewport( this._currentRenderContext );
14741515

1475-
this._currentRenderObjectFunction( object, scene, camera2, geometry, material, group, lightsNode );
1516+
this._currentRenderObjectFunction( object, scene, camera2, geometry, material, group, lightsNode, passId );
14761517

14771518
}
14781519

14791520
}
14801521

14811522
} else {
14821523

1483-
this._currentRenderObjectFunction( object, scene, camera, geometry, material, group, lightsNode );
1524+
this._currentRenderObjectFunction( object, scene, camera, geometry, material, group, lightsNode, passId );
14841525

14851526
}
14861527

14871528
}
14881529

14891530
}
14901531

1491-
renderObject( object, scene, camera, geometry, material, group, lightsNode ) {
1532+
renderObject( object, scene, camera, geometry, material, group, lightsNode, passId = null ) {
14921533

14931534
let overridePositionNode;
14941535
let overrideFragmentNode;
@@ -1570,13 +1611,13 @@ class Renderer {
15701611
this._handleObjectFunction( object, material, scene, camera, lightsNode, group, 'backSide' ); // create backSide pass id
15711612

15721613
material.side = FrontSide;
1573-
this._handleObjectFunction( object, material, scene, camera, lightsNode, group ); // use default pass id
1614+
this._handleObjectFunction( object, material, scene, camera, lightsNode, group, passId ); // use default pass id
15741615

15751616
material.side = DoubleSide;
15761617

15771618
} else {
15781619

1579-
this._handleObjectFunction( object, material, scene, camera, lightsNode, group );
1620+
this._handleObjectFunction( object, material, scene, camera, lightsNode, group, passId );
15801621

15811622
}
15821623

0 commit comments

Comments
 (0)