|
@@ -75,7 +75,7 @@
|
|
|
// gui
|
|
|
|
|
|
gui = new GUI();
|
|
|
- params = { pixelSize: 6, normalEdgeStrength: .3, depthEdgeStrength: .4 };
|
|
|
+ params = { pixelSize: 6, normalEdgeStrength: .3, depthEdgeStrength: .4, pixelAlignedPanning: true };
|
|
|
gui.add( params, 'pixelSize' ).min( 1 ).max( 16 ).step( 1 )
|
|
|
.onChange( () => {
|
|
|
|
|
@@ -84,6 +84,7 @@
|
|
|
} );
|
|
|
gui.add( renderPixelatedPass, 'normalEdgeStrength' ).min( 0 ).max( 2 ).step( .05 );
|
|
|
gui.add( renderPixelatedPass, 'depthEdgeStrength' ).min( 0 ).max( 1 ).step( .05 );
|
|
|
+ gui.add( params, 'pixelAlignedPanning' );
|
|
|
|
|
|
// textures
|
|
|
|
|
@@ -179,6 +180,24 @@
|
|
|
crystalMesh.position.y = .7 + Math.sin( t * 2 ) * .05;
|
|
|
crystalMesh.rotation.y = stopGoEased( t, 2, 4 ) * 2 * Math.PI;
|
|
|
|
|
|
+ const rendererSize = renderer.getSize( new THREE.Vector2() );
|
|
|
+ const aspectRatio = rendererSize.x / rendererSize.y;
|
|
|
+ if ( params["pixelAlignedPanning"] ) {
|
|
|
+
|
|
|
+ pixelAlignFrustum( camera, aspectRatio, Math.floor( rendererSize.x / params[ "pixelSize" ] ),
|
|
|
+ Math.floor( rendererSize.y / params[ "pixelSize" ] ) );
|
|
|
+
|
|
|
+ } else if ( camera.left != - aspectRatio || camera.top != 1.0 ) {
|
|
|
+
|
|
|
+ // Reset the Camera Frustum if it has been modified
|
|
|
+ camera.left = - aspectRatio;
|
|
|
+ camera.right = aspectRatio;
|
|
|
+ camera.top = 1.0 ;
|
|
|
+ camera.bottom = - 1.0 ;
|
|
|
+ camera.updateProjectionMatrix();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
composer.render();
|
|
|
|
|
|
}
|
|
@@ -219,6 +238,39 @@
|
|
|
return cycle + linStep;
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+ function pixelAlignFrustum( camera, aspectRatio, pixelsPerScreenWidth, pixelsPerScreenHeight ) {
|
|
|
+
|
|
|
+ // 0. Get Pixel Grid Units
|
|
|
+ let worldScreenWidth = ( ( camera.right - camera.left ) / camera.zoom );
|
|
|
+ let worldScreenHeight = ( ( camera.top - camera.bottom ) / camera.zoom );
|
|
|
+ let pixelWidth = worldScreenWidth / pixelsPerScreenWidth;
|
|
|
+ let pixelHeight = worldScreenHeight / pixelsPerScreenHeight;
|
|
|
+
|
|
|
+ // 1. Project the current camera position along its local rotation bases
|
|
|
+ let camPos = new THREE.Vector3 (); camera.getWorldPosition ( camPos );
|
|
|
+ let camRot = new THREE.Quaternion(); camera.getWorldQuaternion( camRot );
|
|
|
+ let camRight = new THREE.Vector3( 1.0, 0.0, 0.0 ) .applyQuaternion( camRot );
|
|
|
+ let camUp = new THREE.Vector3( 0.0, 1.0, 0.0 ) .applyQuaternion( camRot );
|
|
|
+ let camPosRight = camPos.dot( camRight );
|
|
|
+ let camPosUp = camPos.dot( camUp );
|
|
|
+
|
|
|
+ // 2. Find how far along its position is along these bases in pixel units
|
|
|
+ let camPosRightPx = camPosRight / pixelWidth;
|
|
|
+ let camPosUpPx = camPosUp / pixelHeight;
|
|
|
+
|
|
|
+ // 3. Find the fractional pixel units and convert to world units
|
|
|
+ let fractX = camPosRightPx - Math.round( camPosRightPx );
|
|
|
+ let fractY = camPosUpPx - Math.round( camPosUpPx );
|
|
|
+
|
|
|
+ // 4. Add fractional world units to the left/right top/bottom to align with the pixel grid
|
|
|
+ camera.left = - aspectRatio - ( fractX * pixelWidth );
|
|
|
+ camera.right = aspectRatio - ( fractX * pixelWidth );
|
|
|
+ camera.top = 1.0 - ( fractY * pixelHeight );
|
|
|
+ camera.bottom = - 1.0 - ( fractY * pixelHeight );
|
|
|
+ camera.updateProjectionMatrix();
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
</script>
|
|
|
</body>
|