From d9d5c1f8d75ff837c26fd8e31d1d0cf6c4623a5b Mon Sep 17 00:00:00 2001 From: Eugene Maksymenko Date: Sun, 27 Mar 2022 20:13:15 +0300 Subject: [PATCH] Fix Placemark rotation and tilt (https://github.com/WorldWindEarth/worldwindjs/issues/63): 1) Change order of unitSquareTransform matrix operations to fix image stretching on rotation and apply correct pivot point. 2) Normalize unitSquareTransform matrix Z-range to prevent texture clipping on tilting. --- src/shapes/Placemark.js | 74 ++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/src/shapes/Placemark.js b/src/shapes/Placemark.js index ee38d37c1..0729b2625 100644 --- a/src/shapes/Placemark.js +++ b/src/shapes/Placemark.js @@ -424,9 +424,6 @@ define([ * cannot be created or should not be created at the time this method is called. */ Placemark.prototype.makeOrderedRenderable = function (dc) { - var w, h, s, - offset; - this.determineActiveAttributes(dc); if (!this.activeAttributes) { return null; @@ -459,34 +456,61 @@ define([ var visibilityScale = this.eyeDistanceScaling ? Math.max(0.0, Math.min(1, this.eyeDistanceScalingThreshold / this.eyeDistance)) : 1; + // Initialize the unit square transform to the identity matrix. + this.imageTransform.setToIdentity(); + // Compute the placemark's transform matrix and texture coordinate matrix according to its screen point, image size, // image offset and image scale. The image offset is defined with its origin at the image's bottom-left corner and // axes that extend up and to the right from the origin point. When the placemark has no active texture the image // scale defines the image size and no other scaling is applied. + var offset, offsetX, offsetY, scaleX, scaleY; if (this.activeTexture) { - w = this.activeTexture.originalImageWidth; - h = this.activeTexture.originalImageHeight; - s = this.activeAttributes.imageScale * visibilityScale; + var w = this.activeTexture.originalImageWidth; + var h = this.activeTexture.originalImageHeight; + var s = this.activeAttributes.imageScale * visibilityScale; offset = this.activeAttributes.imageOffset.offsetForSize(w, h); - - this.imageTransform.setTranslation( - Placemark.screenPoint[0] - offset[0] * s, - Placemark.screenPoint[1] - offset[1] * s, - Placemark.screenPoint[2]); - - this.imageTransform.setScale(w * s, h * s, 1); + offsetX = offset[0] * s; + offsetY = offset[1] * s; + scaleX = w * s; + scaleY = h * s; } else { - s = this.activeAttributes.imageScale * visibilityScale; + var size = this.activeAttributes.imageScale * visibilityScale; offset = this.activeAttributes.imageOffset.offsetForSize(s, s); + offsetX = offset[0]; + offsetY = offset[1]; + scaleX = scaleY = size; + } - this.imageTransform.setTranslation( - Placemark.screenPoint[0] - offset[0], - Placemark.screenPoint[1] - offset[1], - Placemark.screenPoint[2]); + // Position image on screen + this.imageTransform.multiplyByTranslation( + Placemark.screenPoint[0], + Placemark.screenPoint[1], + Placemark.screenPoint[2]); + + // Divide Z by 2^24 to prevent texture clipping when tilting (where 24 is depth buffer bit size). + // Doing so will limit depth range to (diagonal length)/2^24 and make its value within 0..1 range. + this.imageTransform.multiplyByScale(1, 1, 1 / (1 << 24) ); + + // Perform the tilt so that the image tilts back from its base into the view volume + if (this.imageTilt) { + var actualTilt = this.imageTiltReference === WorldWind.RELATIVE_TO_GLOBE ? + dc.camera.tilt + this.imageTilt : this.imageTilt; + this.imageTransform.multiplyByRotation(-1, 0, 0, actualTilt); + } - this.imageTransform.setScale(s, s, 1); + // Perform image rotation + if (this.imageRotation) { + var actualRotation = this.imageRotationReference === WorldWind.RELATIVE_TO_GLOBE ? + dc.camera.heading - this.imageRotation : -this.imageRotation; + this.imageTransform.multiplyByRotation(0, 0, 1, actualRotation); } + // Apply pivot translation + this.imageTransform.multiplyByTranslation(-offsetX, -offsetY, 0); + + // Apply scale + this.imageTransform.multiplyByScale(scaleX, scaleY, 1); + this.imageBounds = WWMath.boundingRectForUnitQuad(this.imageTransform); // If there's a label, perform these same operations for the label texture. @@ -711,18 +735,6 @@ define([ Placemark.matrix.copy(dc.screenProjection); Placemark.matrix.multiplyMatrix(this.imageTransform); - var actualRotation = this.imageRotationReference === WorldWind.RELATIVE_TO_GLOBE ? - dc.navigator.heading - this.imageRotation : -this.imageRotation; - Placemark.matrix.multiplyByTranslation(0.5, 0.5, 0); - Placemark.matrix.multiplyByRotation(0, 0, 1, actualRotation); - Placemark.matrix.multiplyByTranslation(-0.5, -0.5, 0); - - // Perform the tilt before applying the rotation so that the image tilts back from its base into - // the view volume. - var actualTilt = this.imageTiltReference === WorldWind.RELATIVE_TO_GLOBE ? - dc.navigator.tilt + this.imageTilt : this.imageTilt; - Placemark.matrix.multiplyByRotation(-1, 0, 0, actualTilt); - program.loadModelviewProjection(gl, Placemark.matrix); // Enable texture for both normal display and for picking. If picking is enabled in the shader (set in