Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 0 additions & 2 deletions examples/jsm/controls/TrackballControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,6 @@ function onMouseMove( event ) {

if ( state === _STATE.ROTATE && ! this.noRotate ) {

this._movePrev.copy( this._moveCurr );
this._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );

} else if ( state === _STATE.ZOOM && ! this.noZoom ) {
Expand Down Expand Up @@ -939,7 +938,6 @@ function onTouchMove( event ) {
switch ( this._pointers.length ) {

case 1:
this._movePrev.copy( this._moveCurr );
this._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );
break;

Expand Down
21 changes: 21 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -1710,6 +1710,18 @@ export const Compatibility = {
TEXTURE_COMPARE: 'depthTextureCompare'
};

/**
* Represents the refresh types of render objects.
*
* @type {ConstantsRenderObjectRefreshType}
* @constant
*/
export const RenderObjectRefreshType = {
NONE: 0,
SHARED: 1,
FULL: 2
};

/**
* This type represents mouse buttons and interaction types in context of controls.
*
Expand Down Expand Up @@ -1759,3 +1771,12 @@ export const Compatibility = {
* @property {string} FIRST - Flat interpolation using the first vertex.
* @property {string} EITHER - Flat interpolation using either vertex.
*/

/**
* Represents the refresh types of render objects.
*
* @typedef {Object} ConstantsRenderObjectRefreshType
* @property {number} NONE - No refresh required.
* @property {number} SHARED - Only shared uniform buffers require an update.
* @property {number} FULL - The render object requires a full refresh.
*/
3 changes: 2 additions & 1 deletion src/materials/nodes/PointsNodeMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { modelViewMatrix } from '../../nodes/accessors/ModelNode.js';
import { materialPointSize } from '../../nodes/accessors/MaterialNode.js';
import { rotate } from '../../nodes/utils/RotateNode.js';
import { float, uniform, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
import { renderGroup } from '../../nodes/core/UniformGroupNode.js';

import { PointsMaterial } from '../PointsMaterial.js';
import { Vector2 } from '../../math/Vector2.js';
Expand Down Expand Up @@ -200,7 +201,7 @@ class PointsNodeMaterial extends SpriteNodeMaterial {

}

const scale = /*@__PURE__*/ uniform( 1 ).onFrameUpdate( function ( { renderer } ) {
const scale = /*@__PURE__*/ uniform( 1 ).setGroup( renderGroup ).onRenderUpdate( function ( { renderer } ) {

const size = renderer.getSize( _size ); // logical units

Expand Down
110 changes: 101 additions & 9 deletions src/materials/nodes/manager/NodeMaterialObserver.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { RenderObjectRefreshType, DynamicDrawUsage } from '../../../constants.js';

const refreshUniforms = [
'alphaMap',
'alphaTest',
Expand All @@ -9,49 +11,63 @@ const refreshUniforms = [
'attenuationColor',
'attenuationDistance',
'bumpMap',
'bumpScale',
'clearcoat',
'clearcoatMap',
'clearcoatNormalMap',
'clearcoatNormalScale',
'clearcoatRoughness',
'color',
'dashOffset',
'dashSize',
'dispersion',
'displacementBias',
'displacementMap',
'displacementScale',
'emissive',
'emissiveIntensity',
'emissiveMap',
'envMap',
'envMapIntensity',
'envMapRotation',
'gapSize',
'gradientMap',
'ior',
'iridescence',
'iridescenceIOR',
'iridescenceMap',
'iridescenceThickness',
'iridescenceThicknessMap',
'lightMap',
'lightMapIntensity',
'linewidth',
'map',
'matcap',
'metalness',
'metalnessMap',
'normalMap',
'normalScale',
'opacity',
'reflectivity',
'retroreflectivity',
'rotation',
'roughness',
'roughnessMap',
'scale',
'sheen',
'sheenColor',
'sheenColorMap',
'sheenRoughness',
'sheenRoughnessMap',
'shininess',
'size',
'specular',
'specularColor',
'specularColorMap',
'specularIntensity',
'specularIntensityMap',
'specularMap',
'steps',
'thickness',
'transmission',
'transmissionMap'
Expand Down Expand Up @@ -158,6 +174,20 @@ class NodeMaterialObserver {

}

/**
* Returns `true` if the given 3D object uses instance buffers with dynamic draw usage.
* Such buffers must be uploaded once per render so the render object requires a full refresh.
*
* @param {Object3D} object - The 3D object.
* @return {boolean} Whether the given 3D object uses instance buffers with dynamic draw usage or not.
*/
hasDynamicInstancing( object ) {

return object.isInstancedMesh === true && ( object.instanceMatrix.usage === DynamicDrawUsage ||
( object.instanceColor !== null && object.instanceColor.usage === DynamicDrawUsage ) );

}

/**
* Returns `true` if the current rendering produces motion vectors.
*
Expand Down Expand Up @@ -205,6 +235,22 @@ class NodeMaterialObserver {

}

if ( object.isInstancedMesh === true ) {

data.instanceMatrixVersion = object.instanceMatrix.version;
data.instanceColorVersion = object.instanceColor !== null ? object.instanceColor.version : null;
data.morphTextureVersion = object.morphTexture !== null ? object.morphTexture.version : null;

}

if ( object.isBatchedMesh === true ) {

data.matricesTextureVersion = object._matricesTexture.version;
data.colorsTextureVersion = object._colorsTexture !== null ? object._colorsTexture.version : null;
data.indirectTextureVersion = object._indirectTexture.version;

}

if ( renderObject.bundle !== null ) {

data.version = renderObject.bundle.version;
Expand Down Expand Up @@ -599,6 +645,47 @@ class NodeMaterialObserver {

}

// instancing

if ( object.isInstancedMesh === true ) {

const instanceColorVersion = object.instanceColor !== null ? object.instanceColor.version : null;
const morphTextureVersion = object.morphTexture !== null ? object.morphTexture.version : null;

if ( renderObjectData.instanceMatrixVersion !== object.instanceMatrix.version ||
renderObjectData.instanceColorVersion !== instanceColorVersion ||
renderObjectData.morphTextureVersion !== morphTextureVersion ) {

renderObjectData.instanceMatrixVersion = object.instanceMatrix.version;
renderObjectData.instanceColorVersion = instanceColorVersion;
renderObjectData.morphTextureVersion = morphTextureVersion;

return false;

}

}

// batching

if ( object.isBatchedMesh === true ) {

const colorsTextureVersion = object._colorsTexture !== null ? object._colorsTexture.version : null;

if ( renderObjectData.matricesTextureVersion !== object._matricesTexture.version ||
renderObjectData.colorsTextureVersion !== colorsTextureVersion ||
renderObjectData.indirectTextureVersion !== object._indirectTexture.version ) {

renderObjectData.matricesTextureVersion = object._matricesTexture.version;
renderObjectData.colorsTextureVersion = colorsTextureVersion;
renderObjectData.indirectTextureVersion = object._indirectTexture.version;

return false;

}

}

// lights

if ( renderObjectData.lights ) {
Expand Down Expand Up @@ -721,16 +808,16 @@ class NodeMaterialObserver {
*
* @param {RenderObject} renderObject - The render object.
* @param {NodeFrame} nodeFrame - The current node frame.
* @return {boolean} Whether the given render object requires a refresh or not.
* @return {number} The refresh type, see {@link RenderObjectRefreshType}.
*/
needsRefresh( renderObject, nodeFrame ) {

if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) || this.needsVelocity( nodeFrame.renderer ) )
return true;
if ( this.hasNode || this.hasAnimation || this.hasDynamicInstancing( renderObject.object ) || this.firstInitialization( renderObject ) || this.needsVelocity( nodeFrame.renderer ) )
return RenderObjectRefreshType.FULL;

const { renderId } = nodeFrame;

let force = false;
let refreshType = RenderObjectRefreshType.NONE;

// shared UBOs are potentially never updated when objects don't change. Below block
// make sure these UBOs are updated at least once.
Expand All @@ -739,22 +826,27 @@ class NodeMaterialObserver {

this.renderId = renderId;

// no early out here. instead, force the render object to use the equals() code path so its internal cache state gets synched
// no early out here. instead, use the equals() code path below so the internal cache state gets synched

force = true;
refreshType = RenderObjectRefreshType.SHARED;

}

const isStatic = renderObject.object.static === true;
const isBundle = renderObject.bundle !== null && renderObject.bundle.static === true && this.getRenderObjectData( renderObject ).version === renderObject.bundle.version;

if ( isStatic || isBundle )
return force;
return refreshType;

const lightsData = this.getLights( renderObject.lightsNode, renderId );
const notEqual = this.equals( renderObject, lightsData, renderId ) !== true;

return ( force || notEqual );
if ( this.equals( renderObject, lightsData, renderId ) === false ) {

refreshType = RenderObjectRefreshType.FULL;

}

return refreshType;

}

Expand Down
6 changes: 3 additions & 3 deletions src/nodes/accessors/Instance.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import { vec3, mat4, Fn } from '../tsl/TSLBase.js';
import { OnAfterObjectUpdate, OnFrameUpdate } from '../utils/EventNode.js';
import { OnAfterObjectUpdate, OnBeforeFrameUpdate } from '../utils/EventNode.js';
import { normalLocal, transformNormal } from './Normal.js';
import { positionLocal, positionPrevious } from './Position.js';
import { varyingProperty } from '../core/PropertyNode.js';
Expand Down Expand Up @@ -172,10 +172,10 @@ export const instance = /*@__PURE__*/ Fn( ( [ matrices, colors = null ], builder

}

// Synchronization of dynamic buffer updates per frame
// Synchronization of dynamic buffer updates per frame.
if ( interleavedMatrix !== null || interleavedColor !== null ) {

OnFrameUpdate( () => {
OnBeforeFrameUpdate( () => {

if ( interleavedMatrix !== null && interleavedMatrix.version !== matrices.version ) {

Expand Down
7 changes: 4 additions & 3 deletions src/nodes/display/ScreenNode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Node from '../core/Node.js';
import { NodeUpdateType } from '../core/constants.js';
import { renderGroup } from '../core/UniformGroupNode.js';
import { uniform } from '../core/UniformNode.js';
import { nodeImmutable, vec2 } from '../tsl/TSLBase.js';
import { Vector2 } from '../../math/Vector2.js';
Expand Down Expand Up @@ -151,15 +152,15 @@ class ScreenNode extends Node {

if ( scope === ScreenNode.SIZE ) {

output = uniform( _screenSizeVec || ( _screenSizeVec = new Vector2() ) );
output = uniform( _screenSizeVec || ( _screenSizeVec = new Vector2() ) ).setGroup( renderGroup );

} else if ( scope === ScreenNode.VIEWPORT ) {

output = uniform( _viewportVec || ( _viewportVec = new Vector4() ) );
output = uniform( _viewportVec || ( _viewportVec = new Vector4() ) ).setGroup( renderGroup );

} else if ( scope === ScreenNode.DPR ) {

output = uniform( 1 );
output = uniform( 1 ).setGroup( renderGroup );

} else {

Expand Down
37 changes: 37 additions & 0 deletions src/renderers/common/Bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,43 @@ class Bindings extends DataMap {

}

/**
* Updates only the shared uniform buffers of the given render object.
*
* @param {RenderObject} renderObject - The render object.
*/
updateSharedForRender( renderObject ) {

const bindings = this.getForRender( renderObject );

for ( const bindGroup of bindings ) {

for ( const binding of bindGroup.bindings ) {

if ( binding.isNodeUniformsGroup === true && binding.groupNode.shared === true ) {

const updatedGroup = this.nodes.updateGroup( binding );

if ( updatedGroup === false ) continue;

const updated = binding.update();

if ( updated ) {

this.backend.updateBinding( binding );

}

if ( binding.updateRanges.length > 0 ) binding.clearUpdateRanges();

}

}

}

}

/**
* Deletes the bindings for the given compute node.
*
Expand Down
Loading
Loading