@@ -20,13 +20,14 @@ import { VRButton } from './webxr/VRButton.js';
2020import { ARButton } from './webxr/ARButton.js' ;
2121import { delayedExecute } from './Util.js' ;
2222import { LoaderStatus } from './loaders/LoaderStatus.js' ;
23-
23+ import { RenderMode } from './RenderMode.js' ;
2424
2525const THREE_CAMERA_FOV = 50 ;
2626const MINIMUM_DISTANCE_TO_NEW_FOCAL_POINT = .75 ;
2727const MIN_SPLAT_COUNT_TO_SHOW_SPLAT_TREE_LOADING_SPINNER = 1500000 ;
2828const FOCUS_MARKER_FADE_IN_SPEED = 10.0 ;
2929const FOCUS_MARKER_FADE_OUT_SPEED = 2.5 ;
30+ const CONSECUTIVE_RENDERED_FRAMES_FOR_FPS_CALCULATION = 60 ;
3031
3132/**
3233 * Viewer: Manages the rendering of splat scenes. Manages an instance of SplatMesh as well as a web worker
@@ -121,6 +122,8 @@ export class Viewer {
121122 this . gpuAcceleratedSort = false ;
122123 }
123124
125+ this . renderMode = options . renderMode || RenderMode . Always ;
126+
124127 this . controls = null ;
125128
126129 this . showMeshCursor = false ;
@@ -147,6 +150,7 @@ export class Viewer {
147150
148151 this . currentFPS = 0 ;
149152 this . lastSortTime = 0 ;
153+ this . consecutiveRenderFrames = 0 ;
150154
151155 this . previousCameraTarget = new THREE . Vector3 ( ) ;
152156 this . nextCameraTarget = new THREE . Vector3 ( ) ;
@@ -283,6 +287,10 @@ export class Viewer {
283287 }
284288 }
285289
290+ setRenderMode ( renderMode ) {
291+ this . renderMode = renderMode ;
292+ }
293+
286294 onKeyDown = function ( ) {
287295
288296 const forward = new THREE . Vector3 ( ) ;
@@ -941,6 +949,7 @@ export class Viewer {
941949 this . sortPromiseResolver ( ) ;
942950 this . sortPromise = null ;
943951 this . sortPromiseResolver = null ;
952+ this . forceRenderNextFrame ( ) ;
944953 if ( sortCount === 0 ) {
945954 this . runAfterFirstSort . forEach ( ( func ) => {
946955 func ( ) ;
@@ -1088,13 +1097,60 @@ export class Viewer {
10881097 this . requestFrameId = requestAnimationFrame ( this . selfDrivenUpdateFunc ) ;
10891098 }
10901099 this . update ( ) ;
1091- this . render ( ) ;
1100+ if ( this . shouldRender ( ) ) {
1101+ this . render ( ) ;
1102+ this . consecutiveRenderFrames ++ ;
1103+ } else {
1104+ this . consecutiveRenderFrames = 0 ;
1105+ }
1106+ this . renderNextFrame = false ;
10921107 }
10931108
1109+ forceRenderNextFrame ( ) {
1110+ this . renderNextFrame = true ;
1111+ }
1112+
1113+ shouldRender = function ( ) {
1114+
1115+ let renderCount = 0 ;
1116+ const lastCameraPosition = new THREE . Vector3 ( ) ;
1117+ const lastCameraOrientation = new THREE . Quaternion ( ) ;
1118+ const changeEpsilon = 0.0001 ;
1119+
1120+ return function ( ) {
1121+ let shouldRender = false ;
1122+ let cameraChanged = false ;
1123+ if ( this . camera ) {
1124+ const cp = this . camera . position ;
1125+ const co = this . camera . quaternion ;
1126+ cameraChanged = Math . abs ( cp . x - lastCameraPosition . x ) > changeEpsilon ||
1127+ Math . abs ( cp . y - lastCameraPosition . y ) > changeEpsilon ||
1128+ Math . abs ( cp . z - lastCameraPosition . z ) > changeEpsilon ||
1129+ Math . abs ( co . x - lastCameraOrientation . x ) > changeEpsilon ||
1130+ Math . abs ( co . y - lastCameraOrientation . y ) > changeEpsilon ||
1131+ Math . abs ( co . z - lastCameraOrientation . z ) > changeEpsilon ||
1132+ Math . abs ( co . w - lastCameraOrientation . w ) > changeEpsilon ;
1133+ }
1134+
1135+ shouldRender = this . renderMode !== RenderMode . Never && ( renderCount === 0 || this . splatMesh . visibleRegionChanging ||
1136+ cameraChanged || this . renderMode === RenderMode . Always || this . dynamicMode === true || this . renderNextFrame ) ;
1137+
1138+ if ( this . camera ) {
1139+ lastCameraPosition . copy ( this . camera . position ) ;
1140+ lastCameraOrientation . copy ( this . camera . quaternion ) ;
1141+ }
1142+
1143+ renderCount ++ ;
1144+ return shouldRender ;
1145+ } ;
1146+
1147+ } ( ) ;
1148+
10941149 render = function ( ) {
10951150
10961151 return function ( ) {
10971152 if ( ! this . initialized || ! this . splatRenderingInitialized ) return ;
1153+
10981154 const hasRenderables = ( threeScene ) => {
10991155 for ( let child of threeScene . children ) {
11001156 if ( child . visible ) return true ;
@@ -1141,14 +1197,18 @@ export class Viewer {
11411197 let frameCount = 0 ;
11421198
11431199 return function ( ) {
1144- const currentTime = getCurrentTime ( ) ;
1145- const calcDelta = currentTime - lastCalcTime ;
1146- if ( calcDelta >= 1.0 ) {
1147- this . currentFPS = frameCount ;
1148- frameCount = 0 ;
1149- lastCalcTime = currentTime ;
1200+ if ( this . consecutiveRenderFrames > CONSECUTIVE_RENDERED_FRAMES_FOR_FPS_CALCULATION ) {
1201+ const currentTime = getCurrentTime ( ) ;
1202+ const calcDelta = currentTime - lastCalcTime ;
1203+ if ( calcDelta >= 1.0 ) {
1204+ this . currentFPS = frameCount ;
1205+ frameCount = 0 ;
1206+ lastCalcTime = currentTime ;
1207+ } else {
1208+ frameCount ++ ;
1209+ }
11501210 } else {
1151- frameCount ++ ;
1211+ this . currentFPS = null ;
11521212 }
11531213 } ;
11541214
@@ -1227,6 +1287,7 @@ export class Viewer {
12271287 this . sceneHelper . setFocusMarkerOpacity ( newFocusMarkerOpacity ) ;
12281288 this . sceneHelper . updateFocusMarker ( this . nextCameraTarget , this . camera , renderDimensions ) ;
12291289 wasTransitioning = true ;
1290+ this . forceRenderNextFrame ( ) ;
12301291 } else {
12311292 let currentFocusMarkerOpacity ;
12321293 if ( wasTransitioning ) currentFocusMarkerOpacity = 1.0 ;
@@ -1237,6 +1298,7 @@ export class Viewer {
12371298 this . sceneHelper . setFocusMarkerOpacity ( newFocusMarkerOpacity ) ;
12381299 if ( newFocusMarkerOpacity === 0.0 ) this . sceneHelper . setFocusMarkerVisibility ( false ) ;
12391300 }
1301+ if ( currentFocusMarkerOpacity > 0.0 ) this . forceRenderNextFrame ( ) ;
12401302 wasTransitioning = false ;
12411303 }
12421304 } ;
@@ -1250,6 +1312,7 @@ export class Viewer {
12501312
12511313 return function ( ) {
12521314 if ( this . showMeshCursor ) {
1315+ this . forceRenderNextFrame ( ) ;
12531316 this . getRenderDimensions ( renderDimensions ) ;
12541317 outHits . length = 0 ;
12551318 this . raycaster . setFromCameraAndScreenPosition ( this . camera , this . mousePosition , renderDimensions ) ;
@@ -1261,6 +1324,7 @@ export class Viewer {
12611324 this . sceneHelper . setMeshCursorVisibility ( false ) ;
12621325 }
12631326 } else {
1327+ if ( this . sceneHelper . getMeschCursorVisibility ( ) ) this . forceRenderNextFrame ( ) ;
12641328 this . sceneHelper . setMeshCursorVisibility ( false ) ;
12651329 }
12661330 } ;
@@ -1279,7 +1343,7 @@ export class Viewer {
12791343 const meshCursorPosition = this . showMeshCursor ? this . sceneHelper . meshCursor . position : null ;
12801344 const splatRenderCountPct = this . splatRenderCount / splatCount * 100 ;
12811345 this . infoPanel . update ( renderDimensions , this . camera . position , cameraLookAtPosition ,
1282- this . camera . up , meshCursorPosition , this . currentFPS , splatCount ,
1346+ this . camera . up , meshCursorPosition , this . currentFPS || 'N/A' , splatCount ,
12831347 this . splatRenderCount , splatRenderCountPct , this . lastSortTime ) ;
12841348 } ;
12851349
0 commit comments