Skip to content

Commit

Permalink
BatchedMesh: Add built-in material support (#27115)
Browse files Browse the repository at this point in the history
* Add support for multi draw

* Fix multidraw

* Add batching material properties

* Adjust batching define

* Move normal shaders

* Move vertex transform shadres

* Move batching pars

* Move batching matrix fetch

* Switch _batch_id_ to batchId

* Remove custom shader callback

* Remove unused custom uniforms
  • Loading branch information
gkjohnson authored Nov 6, 2023
1 parent c1e5693 commit e4a5253
Show file tree
Hide file tree
Showing 19 changed files with 87 additions and 105 deletions.
108 changes: 3 additions & 105 deletions examples/jsm/objects/BatchedMesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
RGBAFormat
} from 'three';

const ID_ATTR_NAME = '_batch_id_';
const ID_ATTR_NAME = 'batchId';
const _identityMatrix = new Matrix4();
const _zeroScaleMatrix = new Matrix4().set(
0, 0, 0, 0,
Expand All @@ -18,48 +18,6 @@ const _zeroScaleMatrix = new Matrix4().set(
0, 0, 0, 1,
);

// Custom shaders
const batchingParsVertex = /* glsl */`
#ifdef BATCHING
attribute float ${ ID_ATTR_NAME };
uniform highp sampler2D batchingTexture;
mat4 getBatchingMatrix( const in float i ) {
int size = textureSize( batchingTexture, 0 ).x;
int j = int( i ) * 4;
int x = j % size;
int y = j / size;
vec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );
vec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );
vec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );
vec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );
return mat4( v1, v2, v3, v4 );
}
#endif
`;

const batchingbaseVertex = /* glsl */`
#ifdef BATCHING
mat4 batchingMatrix = getBatchingMatrix( ${ ID_ATTR_NAME } );
#endif
`;

const batchingnormalVertex = /* glsl */`
#ifdef BATCHING
objectNormal = vec4( batchingMatrix * vec4( objectNormal, 0.0 ) ).xyz;
#ifdef USE_TANGENT
objectTangent = vec4( batchingMatrix * vec4( objectTangent, 0.0 ) ).xyz;
#endif
#endif
`;

const batchingVertex = /* glsl */`
#ifdef BATCHING
transformed = ( batchingMatrix * vec4( transformed, 1.0 ) ).xyz;
#endif
`;

// @TODO: SkinnedMesh support?
// @TODO: Future work if needed. Move into the core. Can be optimized more with WEBGL_multi_draw.

Expand Down Expand Up @@ -126,12 +84,7 @@ class BatchedMesh extends Mesh {
// @TODO: Calculate the entire binding box and make frustumCulled true
this.frustumCulled = false;

this._customUniforms = {
batchingTexture: { value: null }
};

this._initMatricesTexture();
this._initShader();

}

Expand All @@ -152,53 +105,6 @@ class BatchedMesh extends Mesh {
const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType );

this._matricesTexture = matricesTexture;
this._customUniforms.batchingTexture.value = this._matricesTexture;

}

_initShader() {

const material = this.material;
const currentOnBeforeCompile = material.onBeforeCompile;
const customUniforms = this._customUniforms;

material.onBeforeCompile = function onBeforeCompile( parameters, renderer ) {

// Is this replacement stable across any materials?
parameters.vertexShader = parameters.vertexShader
.replace(
'#include <skinning_pars_vertex>',
'#include <skinning_pars_vertex>\n'
+ batchingParsVertex
)
.replace(
'#include <uv_vertex>',
'#include <uv_vertex>\n'
+ batchingbaseVertex
)
.replace(
'#include <skinnormal_vertex>',
'#include <skinnormal_vertex>\n'
+ batchingnormalVertex
)
.replace(
'#include <skinning_vertex>',
'#include <skinning_vertex>\n'
+ batchingVertex
);

for ( const uniformName in customUniforms ) {

parameters.uniforms[ uniformName ] = customUniforms[ uniformName ];

}

currentOnBeforeCompile.call( this, parameters, renderer );

};

material.defines = material.defines || {};
material.defines.BATCHING = false;

}

Expand Down Expand Up @@ -706,13 +612,11 @@ class BatchedMesh extends Mesh {

}

onBeforeRender( _renderer, _scene, _camera, _geometry, material/*, _group*/ ) {

material.defines.BATCHING = true;
onBeforeRender( _renderer, _scene, _camera, geometry ) {

// the indexed version of the multi draw function requires specifying the start
// offset in bytes.
const index = _geometry.getIndex();
const index = geometry.getIndex();
const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT;

const visible = this._visible;
Expand Down Expand Up @@ -742,12 +646,6 @@ class BatchedMesh extends Mesh {

}

onAfterRender( _renderer, _scene, _camera, _geometry, material/*, _group*/ ) {

material.defines.BATCHING = false;

}

}

export { BatchedMesh };
16 changes: 16 additions & 0 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,7 @@ class WebGLRenderer {
const materialProperties = properties.get( material );

materialProperties.outputColorSpace = parameters.outputColorSpace;
materialProperties.batching = parameters.batching;
materialProperties.instancing = parameters.instancing;
materialProperties.instancingColor = parameters.instancingColor;
materialProperties.skinning = parameters.skinning;
Expand Down Expand Up @@ -1799,6 +1800,14 @@ class WebGLRenderer {

needsProgramChange = true;

} else if ( object.isBatchedMesh && materialProperties.batching === false ) {

needsProgramChange = true;

} else if ( ! object.isBatchedMesh && materialProperties.batching === true ) {

needsProgramChange = true;

} else if ( object.isInstancedMesh && materialProperties.instancing === false ) {

needsProgramChange = true;
Expand Down Expand Up @@ -1986,6 +1995,13 @@ class WebGLRenderer {

}

if ( object.isBatchedMesh ) {

p_uniforms.setOptional( _gl, object, 'batchingTexture' );
p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures );

}

const morphAttributes = geometry.morphAttributes;

if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) {
Expand Down
2 changes: 2 additions & 0 deletions src/renderers/shaders/ShaderChunk.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import alphatest_fragment from './ShaderChunk/alphatest_fragment.glsl.js';
import alphatest_pars_fragment from './ShaderChunk/alphatest_pars_fragment.glsl.js';
import aomap_fragment from './ShaderChunk/aomap_fragment.glsl.js';
import aomap_pars_fragment from './ShaderChunk/aomap_pars_fragment.glsl.js';
import batching_pars_vertex from './ShaderChunk/batching_pars_vertex.glsl.js';
import begin_vertex from './ShaderChunk/begin_vertex.glsl.js';
import beginnormal_vertex from './ShaderChunk/beginnormal_vertex.glsl.js';
import bsdfs from './ShaderChunk/bsdfs.glsl.js';
Expand Down Expand Up @@ -131,6 +132,7 @@ export const ShaderChunk = {
alphatest_pars_fragment: alphatest_pars_fragment,
aomap_fragment: aomap_fragment,
aomap_pars_fragment: aomap_pars_fragment,
batching_pars_vertex: batching_pars_vertex,
begin_vertex: begin_vertex,
beginnormal_vertex: beginnormal_vertex,
bsdfs: bsdfs,
Expand Down
19 changes: 19 additions & 0 deletions src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export default /* glsl */`
#ifdef USE_BATCHING
attribute float batchId;
uniform highp sampler2D batchingTexture;
mat4 getBatchingMatrix( const in float i ) {
int size = textureSize( batchingTexture, 0 ).x;
int j = int( i ) * 4;
int x = j % size;
int y = j / size;
vec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );
vec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );
vec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );
vec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );
return mat4( v1, v2, v3, v4 );
}
#endif
`;
20 changes: 20 additions & 0 deletions src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
export default /* glsl */`
#ifdef USE_BATCHING
// this is in lieu of a per-instance normal-matrix
// shear transforms in the instance matrix are not supported
mat4 batchingMatrix = getBatchingMatrix( batchId );
mat3 bm = mat3( batchingMatrix );
objectNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );
objectNormal = bm * objectNormal;
#ifdef USE_TANGENT
objectTangent /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );
objectTangent = bm * objectTangent;
#endif
#endif
vec3 transformedNormal = objectNormal;
#ifdef USE_INSTANCING
Expand Down
6 changes: 6 additions & 0 deletions src/renderers/shaders/ShaderChunk/project_vertex.glsl.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
export default /* glsl */`
vec4 mvPosition = vec4( transformed, 1.0 );
#ifdef USE_BATCHING
mvPosition = batchingMatrix * mvPosition;
#endif
#ifdef USE_INSTANCING
mvPosition = instanceMatrix * mvPosition;
Expand Down
6 changes: 6 additions & 0 deletions src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ export default /* glsl */`
vec4 worldPosition = vec4( transformed, 1.0 );
#ifdef USE_BATCHING
worldPosition = batchingMatrix * worldPosition;
#endif
#ifdef USE_INSTANCING
worldPosition = instanceMatrix * worldPosition;
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/depth.glsl.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const vertex = /* glsl */`
#include <common>
#include <batching_pars_vertex>
#include <uv_pars_vertex>
#include <displacementmap_pars_vertex>
#include <morphtarget_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/distanceRGBA.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const vertex = /* glsl */`
varying vec3 vWorldPosition;
#include <common>
#include <batching_pars_vertex>
#include <uv_pars_vertex>
#include <displacementmap_pars_vertex>
#include <morphtarget_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/meshbasic.glsl.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const vertex = /* glsl */`
#include <common>
#include <batching_pars_vertex>
#include <uv_pars_vertex>
#include <envmap_pars_vertex>
#include <color_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/meshlambert.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const vertex = /* glsl */`
varying vec3 vViewPosition;
#include <common>
#include <batching_pars_vertex>
#include <uv_pars_vertex>
#include <displacementmap_pars_vertex>
#include <envmap_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/meshmatcap.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const vertex = /* glsl */`
varying vec3 vViewPosition;
#include <common>
#include <batching_pars_vertex>
#include <uv_pars_vertex>
#include <color_pars_vertex>
#include <displacementmap_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/meshnormal.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const vertex = /* glsl */`
#endif
#include <common>
#include <batching_pars_vertex>
#include <uv_pars_vertex>
#include <displacementmap_pars_vertex>
#include <normal_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/meshphong.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const vertex = /* glsl */`
varying vec3 vViewPosition;
#include <common>
#include <batching_pars_vertex>
#include <uv_pars_vertex>
#include <displacementmap_pars_vertex>
#include <envmap_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/meshphysical.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ varying vec3 vViewPosition;
#endif
#include <common>
#include <batching_pars_vertex>
#include <uv_pars_vertex>
#include <displacementmap_pars_vertex>
#include <color_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/meshtoon.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const vertex = /* glsl */`
varying vec3 vViewPosition;
#include <common>
#include <batching_pars_vertex>
#include <uv_pars_vertex>
#include <displacementmap_pars_vertex>
#include <color_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/shaders/ShaderLib/shadow.glsl.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const vertex = /* glsl */`
#include <common>
#include <batching_pars_vertex>
#include <fog_pars_vertex>
#include <morphtarget_pars_vertex>
#include <skinning_pars_vertex>
Expand Down
1 change: 1 addition & 0 deletions src/renderers/webgl/WebGLProgram.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {

customDefines,

parameters.batching ? '#define USE_BATCHING' : '',
parameters.instancing ? '#define USE_INSTANCING' : '',
parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',

Expand Down
4 changes: 4 additions & 0 deletions src/renderers/webgl/WebGLPrograms.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
const currentRenderTarget = renderer.getRenderTarget();

const IS_INSTANCEDMESH = object.isInstancedMesh === true;
const IS_BATCHEDMESH = object.isBatchedMesh === true;

const HAS_MAP = !! material.map;
const HAS_MATCAP = !! material.matcap;
Expand Down Expand Up @@ -193,6 +194,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities

precision: precision,

batching: IS_BATCHEDMESH,
instancing: IS_INSTANCEDMESH,
instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null,

Expand Down Expand Up @@ -503,6 +505,8 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
_programLayers.enable( 17 );
if ( parameters.alphaHash )
_programLayers.enable( 18 );
if ( parameters.batching )
_programLayers.enable( 19 );

array.push( _programLayers.mask );
_programLayers.disableAll();
Expand Down

0 comments on commit e4a5253

Please sign in to comment.