Просмотр исходного кода

PointsNodeMaterial: Fix scaling bugs (#31627)

* Fix scaling bugs

* Clean up

* Update screenshot
WestLangley 5 месяцев назад
Родитель
Сommit
0188ec227e

BIN
examples/screenshots/webgpu_lights_custom.jpg


BIN
examples/screenshots/webgpu_sandbox.jpg


+ 41 - 26
src/materials/nodes/PointsNodeMaterial.js

@@ -1,5 +1,5 @@
 import SpriteNodeMaterial from './SpriteNodeMaterial.js';
-import { viewport } from '../../nodes/display/ScreenNode.js';
+import { viewportSize, screenSize } from '../../nodes/display/ScreenNode.js';
 import { positionGeometry, positionLocal, positionView } from '../../nodes/accessors/Position.js';
 import { modelViewMatrix } from '../../nodes/accessors/ModelNode.js';
 import { materialPointSize } from '../../nodes/accessors/MaterialNode.js';
@@ -70,61 +70,76 @@ class PointsNodeMaterial extends SpriteNodeMaterial {
 
 	setupVertex( builder ) {
 
-		const mvp = super.setupVertex( builder );
+		const { material, camera } = builder;
+
+		const { rotationNode, scaleNode, sizeNode, sizeAttenuation } = this;
+
+		let mvp = super.setupVertex( builder );
 
 		// skip further processing if the material is not a node material
 
-		if ( builder.material.isNodeMaterial !== true ) {
+		if ( material.isNodeMaterial !== true ) {
 
 			return mvp;
 
 		}
 
-		// ndc space
+		// point size
 
-		const { rotationNode, scaleNode, sizeNode } = this;
+		let pointSize = sizeNode !== null ? vec2( sizeNode ) : materialPointSize;
 
-		const alignedPosition = positionGeometry.xy.toVar();
-		const aspect = viewport.z.div( viewport.w );
+		const dpr = builder.renderer.getPixelRatio();
 
-		// rotation
+		pointSize = pointSize.mul( dpr );
 
-		if ( rotationNode && rotationNode.isNode ) {
+		// size attenuation
 
-			const rotation = float( rotationNode );
+		if ( camera.isPerspectiveCamera && sizeAttenuation === true ) {
 
-			alignedPosition.assign( rotate( alignedPosition, rotation ) );
+			// follow WebGLRenderer's implementation, and scale by half the canvas height in logical units
+			const scale = float( 0.5 ).mul( screenSize.y ).div( dpr );
 
-		}
+			pointSize = pointSize.mul( scale.div( positionView.z.negate() ) );
 
-		// point size
+		}
 
-		let pointSize = sizeNode !== null ? vec2( sizeNode ) : materialPointSize;
+		// scale
 
-		if ( this.sizeAttenuation === true ) {
+		if ( scaleNode && scaleNode.isNode ) {
 
-			pointSize = pointSize.mul( pointSize.div( positionView.z.negate() ) );
+			pointSize = pointSize.mul( vec2( scaleNode ) );
 
 		}
 
-		// scale
+		// compute offset
 
-		if ( scaleNode && scaleNode.isNode ) {
+		let offset = positionGeometry.xy;
 
-			pointSize = pointSize.mul( vec2( scaleNode ) );
+		// apply rotation
+
+		if ( rotationNode && rotationNode.isNode ) {
+
+			const rotation = float( rotationNode );
+
+			offset = rotate( offset, rotation );
 
 		}
 
-		alignedPosition.mulAssign( pointSize.mul( 2 ) );
+		// account for point size
+
+		offset = offset.mul( pointSize );
+
+		// scale by viewport size
+
+		offset = offset.div( viewportSize.div( 2 ) );
+
+		// compensate for the perspective divide
 
-		alignedPosition.assign( alignedPosition.div( viewport.z ) );
-		alignedPosition.y.assign( alignedPosition.y.mul( aspect ) );
+		offset = offset.mul( mvp.w );
 
-		// back to clip space
-		alignedPosition.assign( alignedPosition.mul( mvp.w ) );
+		// add offset
 
-		//clipPos.xy += offset;
-		mvp.addAssign( vec4( alignedPosition, 0, 0 ) );
+		mvp = mvp.add( vec4( offset, 0, 0 ) );
 
 		return mvp;
 

粤ICP备19079148号