ソースを参照

Merge pull request #5720 from TrevorDev/guiRectFix

fix issues related to invalidate rect optimization
David Catuhe 6 年 前
コミット
4a1d2b9227

+ 1 - 1
dist/preview release/what's new.md

@@ -23,7 +23,7 @@
   - Added new [ScrollViewer](https://doc.babylonjs.com/how_to/scrollviewer) with mouse wheel scrolling for larger containers to be viewed using Sliders ([JohnK](https://github.com/BabylonJSGuide/) / [Deltakosh](https://github.com/deltakosh))
   - Moved to a measure / draw mechanism ([Deltakosh](https://github.com/deltakosh))
   - Added support for [nine patch stretch](https://www.babylonjs-playground.com/#G5H9IN#2) mode for images. ([Deltakosh](https://github.com/deltakosh))
-  - InvalidateRect added to AdvancedDynamicTexture to improve perf for highly populated GUIs ([TrevorDev](https://github.com/TrevorDev))
+  - InvalidateRect added to AdvancedDynamicTexture to improve perf for heavily populated GUIs ([TrevorDev](https://github.com/TrevorDev))
 
 ## Updates
 

+ 15 - 28
gui/src/2D/advancedDynamicTexture.ts

@@ -346,39 +346,27 @@ export class AdvancedDynamicTexture extends DynamicTexture {
         this._useInvalidateRectOptimization = value;
     }
 
-    private _clearRectangle: Nullable<Measure> = null;
+    // Invalidated rectangle which is the combination of all invalidated controls after they have been rotated into absolute position
     private _invalidatedRectangle: Nullable<Measure> = null;
     /**
      * Invalidates a rectangle area on the gui texture
-     * @param clearMinX left most position of the rectangle to clear in the texture
-     * @param clearMinY top most position of the rectangle to clear in the texture
-     * @param clearMaxX right most position of the rectangle to clear in the texture
-     * @param clearMaxY bottom most position of the rectangle to clear in the texture
-     * @param minX left most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
-     * @param minY top most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
-     * @param maxX right most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
-     * @param maxY bottom most position of the rectangle to invalidate in absolute coordinates (not taking in account local transformation)
+     * @param invalidMinX left most position of the rectangle to invalidate in the texture
+     * @param invalidMinY top most position of the rectangle to invalidate in the texture
+     * @param invalidMaxX right most position of the rectangle to invalidate in the texture
+     * @param invalidMaxY bottom most position of the rectangle to invalidate in the texture
      */
-    public invalidateRect(clearMinX: number, clearMinY: number, clearMaxX: number, clearMaxY: number, minX: number, minY: number, maxX: number, maxY: number) {
+    public invalidateRect(invalidMinX: number, invalidMinY: number, invalidMaxX: number, invalidMaxY: number) {
         if (!this._useInvalidateRectOptimization) {
             return;
         }
-        if (!this._clearRectangle || !this._invalidatedRectangle) {
-            this._clearRectangle = new Measure(clearMinX, clearMinY, clearMaxX - clearMinX + 1, clearMaxY - clearMinY + 1);
-            this._invalidatedRectangle = new Measure(minX, minY, maxX - minX + 1, maxY - minY + 1);
+        if (!this._invalidatedRectangle) {
+            this._invalidatedRectangle = new Measure(invalidMinX, invalidMinY, invalidMaxX - invalidMinX + 1, invalidMaxY - invalidMinY + 1);
         } else {
             // Compute intersection
-            var maxX = Math.ceil(Math.max(this._clearRectangle.left + this._clearRectangle.width - 1, clearMaxX));
-            var maxY = Math.ceil(Math.max(this._clearRectangle.top + this._clearRectangle.height - 1, clearMaxY));
-            this._clearRectangle.left = Math.floor(Math.min(this._clearRectangle.left, clearMinX));
-            this._clearRectangle.top = Math.floor(Math.min(this._clearRectangle.top, clearMinY));
-            this._clearRectangle.width = maxX - this._clearRectangle.left + 1;
-            this._clearRectangle.height = maxY - this._clearRectangle.top + 1;
-
-            maxX = Math.max(this._invalidatedRectangle.left + this._invalidatedRectangle.width - 1, maxX);
-            maxY = Math.max(this._invalidatedRectangle.top + this._invalidatedRectangle.height - 1, maxY);
-            this._invalidatedRectangle.left = Math.min(this._invalidatedRectangle.left, minX);
-            this._invalidatedRectangle.top = Math.min(this._invalidatedRectangle.top, minY);
+            var maxX = Math.ceil(Math.max(this._invalidatedRectangle.left + this._invalidatedRectangle.width - 1, invalidMaxX));
+            var maxY = Math.ceil(Math.max(this._invalidatedRectangle.top + this._invalidatedRectangle.height - 1, invalidMaxY));
+            this._invalidatedRectangle.left = Math.floor(Math.min(this._invalidatedRectangle.left, invalidMinX));
+            this._invalidatedRectangle.top = Math.floor(Math.min(this._invalidatedRectangle.top, invalidMinY));
             this._invalidatedRectangle.width = maxX - this._invalidatedRectangle.left + 1;
             this._invalidatedRectangle.height = maxY - this._invalidatedRectangle.top + 1;
         }
@@ -480,7 +468,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
                 this._rootContainer._markAllAsDirty();
             }
         }
-        this.invalidateRect(0, 0, textureSize.width - 1, textureSize.height - 1, 0, 0, textureSize.width - 1, textureSize.height - 1);
+        this.invalidateRect(0, 0, textureSize.width - 1, textureSize.height - 1);
     }
     /** @hidden */
     public _getGlobalViewport(scene: Scene): Viewport {
@@ -563,8 +551,8 @@ export class AdvancedDynamicTexture extends DynamicTexture {
         this._isDirty = false; // Restoring the dirty state that could have been set by controls during layout processing
 
         // Clear
-        if (this._clearRectangle) {
-            this._clearMeasure.copyFrom(this._clearRectangle);
+        if (this._invalidatedRectangle) {
+            this._clearMeasure.copyFrom(this._invalidatedRectangle);
         } else {
             this._clearMeasure.copyFromFloats(0, 0, renderWidth, renderHeight);
         }
@@ -580,7 +568,6 @@ export class AdvancedDynamicTexture extends DynamicTexture {
         this.onBeginRenderObservable.notifyObservers(this);
         this._rootContainer._render(context, this._invalidatedRectangle);
         this.onEndRenderObservable.notifyObservers(this);
-        this._clearRectangle = null;
         this._invalidatedRectangle = null;
     }
     /** @hidden */

+ 4 - 9
gui/src/2D/controls/container.ts

@@ -285,12 +285,12 @@ export class Container extends Control {
 
     /** @hidden */
     public _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean {
-        if (!this.isVisible || this.notRenderable) {
+        if (!this.isDirty && (!this.isVisible || this.notRenderable)) {
             return false;
         }
 
         if (this._isDirty) {
-            this._tempCurrentMeasure.copyFrom(this._currentMeasure);
+            this._currentMeasure.transformToRef(this._transformMatrix, this._prevCurrentMeasureTransformedIntoGlobalSpace);
         }
 
         let rebuildCount = 0;
@@ -348,12 +348,7 @@ export class Container extends Control {
         context.restore();
 
         if (this._isDirty) {
-            this.invalidateRect(
-                Math.min(this._currentMeasure.left, this._tempCurrentMeasure.left),
-                Math.min(this._currentMeasure.top, this._tempCurrentMeasure.top),
-                Math.max(this._currentMeasure.left + this._currentMeasure.width, this._tempCurrentMeasure.left + this._tempCurrentMeasure.width) - 1,
-                Math.max(this._currentMeasure.top + this._currentMeasure.height, this._tempCurrentMeasure.top + this._tempCurrentMeasure.height) - 1
-            );
+            this.invalidateRect();
 
             this._isDirty = false;
         }
@@ -378,7 +373,7 @@ export class Container extends Control {
             // Only redraw parts of the screen that are invalidated
             if (invalidatedRectangle) {
                 if (!child._intersectsRect(invalidatedRectangle)) {
-                    // continue;
+                    continue;
                 }
             }
             child._render(context, invalidatedRectangle);

ファイルの差分が大きいため隠しています
+ 1861 - 1871
gui/src/2D/controls/control.ts


+ 41 - 0
gui/src/2D/measure.ts

@@ -1,3 +1,5 @@
+import { Matrix2D } from "./math2D";
+import { Vector2, Polygon } from "babylonjs";
 
 /**
  * Class used to store 2D control sizes
@@ -48,6 +50,45 @@ export class Measure {
     }
 
     /**
+     * Computes the axis aligned bounding box measure for two given measures
+     * @param a Input measure
+     * @param b Input measure
+     * @param result the resulting bounding measure
+     */
+    public static CombineToRef(a: Measure, b: Measure, result: Measure) {
+        var left = Math.min(a.left, b.left);
+        var top = Math.min(a.top, b.top);
+        var right = Math.max(a.left + a.width, b.left + b.width);
+        var bottom = Math.max(a.top + a.height, b.top + b.height);
+        result.left = left;
+        result.top = top;
+        result.width = right - left;
+        result.height = bottom - top;
+    }
+
+    /**
+     * Computes the axis aligned bounding box of the measure after it is modified by a given transform
+     * @param transform the matrix to transform the measure before computing the AABB
+     * @param result the resulting AABB
+     */
+    public transformToRef(transform: Matrix2D, result: Measure) {
+        var rectanglePoints = Polygon.Rectangle(this.left, this.top, this.left + this.width, this.top + this.height);
+        var min = new Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
+        var max = new Vector2(0, 0);
+        for (var i = 0; i < 4; i++) {
+            transform.transformCoordinates(rectanglePoints[i].x, rectanglePoints[i].y, rectanglePoints[i]);
+            min.x = Math.floor(Math.min(min.x, rectanglePoints[i].x));
+            min.y = Math.floor(Math.min(min.y, rectanglePoints[i].y));
+            max.x = Math.ceil(Math.max(max.x, rectanglePoints[i].x));
+            max.y = Math.ceil(Math.max(max.y, rectanglePoints[i].y));
+        }
+        result.left = min.x;
+        result.top = min.y;
+        result.width = max.x - min.x;
+        result.height = max.y - min.y;
+    }
+
+    /**
      * Check equality between this measure and another one
      * @param other defines the other measures
      * @returns true if both measures are equals

BIN
tests/validation/ReferenceImages/TransformStackPanel.png


+ 5 - 0
tests/validation/config.json

@@ -2,6 +2,11 @@
   "root": "https://rawgit.com/BabylonJS/Website/master",
   "tests": [
     {
+      "title": "GUI Transform StackPanel",
+      "playgroundId": "#BS60AB#0",
+      "referenceImage": "TransformStackPanel.png"
+    },
+    {
       "title": "GUI StackPanel",
       "playgroundId": "#LLVZ90#0",
       "referenceImage": "StackPanel.png"