Repository navigation
Add Advanced Texture Quality 3D manager & PBR materials - #9340
Islamibrahim2008 wants to merge 25 commits into
Conversation
New gdjs.TextureQuality3DManager, always included in games, handling: - Automatic GPU capability detection (max texture/cubemap size, max anisotropy, supported compressed texture formats, shader precision, GPU name) from the Three.js r185 WebGL renderer. - Texture quality policy: filtering (keep/nearest/bilinear/trilinear), mipmap management (auto/force on/force off), anisotropic filtering clamped to the GPU maximum, optional ClampToEdge wrapping. - Downscaling of oversized textures (image and cube textures) before GPU upload, to reduce GPU memory usage, always clamped to the hard limit of the GPU. - GPU memory tracking with shared sources counted once and automatic cleanup on texture disposal (no GPU memory leak), plus an optional memory budget warning. - Diagnostic reports (per texture details, totals, warnings) and a startup log of the detected capabilities. Settings are read from the project extension properties (namespace 'AdvancedTextureQuality3D') and default to a disabled 'classic' mode, leaving textures untouched for compatibility with existing games. Also provides gdjs.textureQuality3d events tools (set preset, enable, set anisotropy, set max texture resolution, memory/count/capabilities expressions) used by the 3D extension.
- RuntimeGame: create and expose the texture quality manager (getTextureQuality3DManager) and dispose it with the game. - RuntimeGameRenderer: detect the GPU capabilities right after the Three.js renderer is created. - PixiImageManager: apply the quality settings to the Three.js textures and cube textures of image resources, keeping hard pixels of resources with smoothing disabled. - Model3DManager: apply the quality settings (resolution cap and anisotropy) to 3D model textures while respecting their glTF sampler settings, unless the developer chose to override them. Also make getExtensionProperty tolerant to projects without extension properties.
Add the new engine file to the common includes of the exporter, so that the advanced texture quality system is available in every exported game (and previews), like Model3DManager.js.
New editor section to configure the advanced texture quality of 3D textures, saved in the project as extension properties and restored when the project is opened: - Quality presets (Classic/Performance/Balanced/Quality/Ultra/Custom) with automatic matching when settings are edited manually. - Professional controls for texture filtering, mipmaps, anisotropic filtering, maximum texture resolution, downscaling quality, edge clamping, 3D model sampler overriding and a GPU memory budget. - Live GPU diagnostics on the developer machine (real WebGL 2 capabilities detection: GPU name, texture limits, max anisotropy, compressed texture formats...) with warnings when settings go beyond what the GPU supports. The Classic preset disables the system entirely, so existing projects keep rendering exactly like before.
…nsion Let game developers control the advanced texture quality system from the events sheet (all backed by the engine's TextureQuality3DManager): - Actions: apply a quality preset, enable/disable the system, set the anisotropic filtering level, set the maximum texture resolution. - Condition: is the texture quality system enabled. - Expressions: GPU memory used by 3D textures (MB), number of loaded 3D textures, maximum anisotropy and texture size supported by the GPU.
Add the new engine file to the test runtime files list, before runtimegame.js which now creates the texture quality manager.
|
Storybook for this branch: latest · commit 13b41b0 Updated automatically after each Storybook build. |
|
Hi! These are interesting additions, and there are a lot of moving parts/lots of code and design/architectural choices, so let's try to go step by step:
FYI, I think these quality settings are super important :) And we should have something done here. But I'm trying to see how we progressively get there, with enough profiling, measurements and the best UX so we don't scrap that in a few versions to replace it because we realised it should have been done differently. |
|
Thanks — all fair questions. Here's how I'd break this down, what I chose and why, and what's still missing on the measurement side (being explicit about it). 1. Splitting into progressive PRsThe work decomposes cleanly into 4 PRs ordered from "strictly better, no behavior change" to "decisions worth discussing". My 6 commits map onto these almost 1:1. PR 1 — Observability only (safe to merge immediately)
PR 2 — Hard-limit clamp only (strictly better on affected devices) PR 3 — Opt-in quality policy + editor tab (the "product" part) PR 4 — Events API (keep last, it's the only irreversible part) Decisions I'd flag as "not strictly better — worth a discussion": the preset numbers (1024/2048/4096, anisotropy 4/8), settings storage (see below), the tab placement in Game properties, and the events naming. 2. Main architectural choices
Profiler linkage: the additions are not linked to the profiler today. I think they should be, at least partially: 3. Measurements — what exists and what's missingHonest status: no cross-device benchmark campaign was run yet. What exists today is exactly the instrumentation needed to run it (report API + in-game expressions). Known facts from WebGL/Three.js that motivated the design:
Measurement plan I propose before/with PR 3 (and I can encode these as repeatable checks):
If measurements show the presets are wrong for real devices, only PR 3's numbers change — PR 1/2 stay valuable regardless. That's the main reason to land observability first. |
|
Hi! Thanks for taking the time to ask your AI agent to make this answer, but I would prefer a human, very concise answer. Indeed, we could also run an AI agent to build this PR in the GDevelop core team, so what is important is the reasons, the architecture, and the main points very concisely, from a human point of view. Code is not important, nor long explanations. On the contrary, I want super concise code, and explanations that are also super concise and explain why it's great idea and why it's safe for the long term :) |
|
@4ian Hmm, you were right. I'm just bad at explaining, and I already introduced him to the project well, so I made him explain , Sorry for this ❤️ |
|
1-Yes, I agree with splitting the work into progressive stages. However, I would prefer keeping each commit focused on one specific feature or change, rather than creating too many separate PRs. This would make the work easier to review while keeping the development organized. 2-I believe this should be implemented as a core engine system, rather than just another extension. I want it to be an integral part of the engine so it can evolve sustainably over time, instead of being treated as an optional external addition. 3-I'll leave this decision to you. My current system already detects the user's GPU and determines the most suitable settings for it. I don't have any objections to adding Profiler integration if you think it would be valuable. 4- So far, I've only tested the system on my own machine:
However, I'm fully willing to work with you on testing the system, step by step, and verifying that everything works correctly. I can actively participate in testing and provide feedback throughout the process. 5-Yes, that's exactly what I want. The system should automatically detect the GPU's capabilities and select the most suitable quality settings for the user's hardware. 6-Yes, I want to provide quality presets. However, the system should already select the most suitable settings automatically by default. The presets would give developers the flexibility to change the quality level manually whenever they want. 7-I believe everything has been covered. Our next step should be to work together on verifying that all the systems are fully functional and operate correctly. |
…urces PBR material settings store their texture slots in a JSON configuration (in a "pbrConfig" property). Add a helper walking this JSON to expose every image found in its "textures" maps to the resource workers, so that images can be renamed or removed safely from the project. It is used both by the JS object configurations (whose resources are exposed from their properties) and by C++ object configurations.
The manager builds and configures the PBR materials of 3D objects from their settings (metallic/roughness workflow, with the physical material for transmission, ior and clearcoat): - Material presets (metal, gold, glass, wood, plastic, stone, fabric, rubber) merged under the settings of the objects. - Texture slots (albedo, packed metallic/roughness, normal, ambient occlusion, emissive, height/displacement and opacity), with the color spaces expected by Three.js (sRGB for colors, linear for data maps). - Environment maps (image based lighting), prefiltered with PMREM for smooth roughness on every GPU, from 6 cube images or from an equirectangular image. Materials are shared when configured with the same settings and copied before events change them for a single object; every created material and the environment map are disposed when unused, so that neither the objects lifecycle nor the resource unloading leak GPU memory. The image manager gains linear variants of the Three.js textures for the maps holding data, and notifies the PBR manager when an image is unloaded.
The 3D box reads an optional PBR material configuration from its properties: settings for the whole object and overrides for each of its 6 faces. When enabled, the faces are rendered with PBR materials (defaulting their albedo to the texture of the face), on top of the existing tint, tiling and transparency settings. Events can change every PBR property (metallic, roughness, colors, texture slots, presets...) for all the faces or for a single one while the game is running. The changed materials are copied first so that other objects sharing them are left untouched, and disposed when the object is destroyed.
The 3D model gets a "pbrConfig" property holding its PBR material settings as JSON: settings for the whole model and overrides for each mesh of the glTF file. The property is saved with the project and its images are exposed to the resource workers (see the previous commit). When enabled, every material of the model is copied and configured with the merged settings: a setting that is not chosen keeps the value (or the texture) of the original material, so that models can override a single property without losing their glTF materials. The copies are disposed when the model is reloaded or the object destroyed. Events can change every PBR property (metallic, roughness, colors, texture slots, presets...) for all the meshes or for a single one while the game is running.
- Store the PBR configuration of the 3D box and the 3D model in a hidden "pbrConfig" property, edited with the PBR material editor. - Declare the actions, conditions and expressions changing the PBR materials at runtime (numeric and color properties, texture slots and material presets), for a face of a 3D box or a mesh of a 3D model. - Declare the scene actions and expressions for the environment map (image based lighting): 6 cube images or an equirectangular image, its intensity, and its removal. - Apply the PBR settings to the instances displayed in the scene editor (3D layers), rebuilding their materials when the properties change.
A reusable editor for the PBR material settings stored in the "pbrConfig" property of 3D objects: - Presets (metal, gold, glass, wood, plastic, stone, fabric, rubber) and the material type (standard or physical). - Sliders for the numeric properties, color fields for the albedo and emissive colors, and a resource selector for each texture slot. - A live Three.js preview of the material, lit by an image based lighting environment. - The settings of an object can be overridden for one of its targets (a face of a 3D box or a mesh of a 3D model): the overridden properties are shown with a reset button going back to the value of the object.
Add a "PBR materials" section to the object editors: the settings can be edited for the whole object or for a single face (3D box) or mesh (3D model), picked from a selector fed with the meshes of the loaded glTF file.
|
Remember that the more code you add, the more it's exponentially harder to review, even with AI, the more we have strong decisions to take (for example I appreciate you wanting to improve this, but code is not hard to generate - it's doing the proper, careful architectural decisions that is interesting. Right now, when I see all of this code, I have a bigger trust in having an AI agent by myself rewriting this for me so I can better understand the big decisions. I strongly suggest you start by taking things small. Like really small. A few improvements. Just a little. Then when it's merged, another one, then another one. You will build trust and confidence like this :) |
- Added mergeVertices utility to improve normal calculations for non-indexed geometries in 3D models. - Enabled multisample anti-aliasing in the InstancesEditor for smoother edges in 3D geometry. - Adjusted rendering settings to use device pixel ratio for crisp visuals on high-DPI screens. - Implemented texture quality improvements, including mipmaps and anisotropic filtering for better texture sharpness. - Increased preview texture size for 3D models to enhance clarity in resource pickers.
Add the core logic of the animation state machine, driving the object animations like Unity's Animator: - States linked to the object animations, with a speed multiplier and an optional restart on enter. - Transitions with conditions on parameters (number, boolean and trigger parameters), consumed triggers, exit times (normalized animation time, waiting for several loops when greater than 1) and interruption rules (None/Current/Next/Current then Next). - An "Any State" pseudo-state whose transitions are checked first and can fire from any state (for reactions like dying or getting hit). - Sub-state machines grouping states, with their own entry state: a transition targeting the sub-state machine enters its entry state and follows it when it changes. - Blend trees: the animation and its playback speed are chosen from the value of a number parameter, blending the speed between the two closest animations (which avoids the foot sliding of fixed-speed animations). - Safe JSON parsing of the machine definition, for a robust hot-reload.
Add the runtime behavior driving the animation of its object from the state machine definition: - Plays the animation of the state entered by the machine (including the initial entry state), with its speed multiplier. - Updates the blend trees every frame from the value of their parameter, with a "frame matching" when the selected animation changes, to avoid jarring restarts mid-animation. - Computes the normalized animation time from the animation frames (or from the elapsed seconds for objects without frame-based animations) to evaluate the exit times. - Exposes the state changes to the events sheet: "just entered"/"just left" flags published before the events of the next frame, the current and previous state names, the parameters setters (numbers, booleans, triggers) and an immediate state change. - Supports hot-reload of the machine definition while keeping the state being played.
Declare the Animation State Machine extension and its behavior for the events sheet: - Actions: change the current state, set a number/boolean parameter, toggle a boolean parameter, trigger and reset a trigger parameter. - Conditions: is in state, state has just changed, state has just been entered/left (to trigger sounds, particles... on state changes), and a boolean parameter is true. - Expressions: the current and previous state names and the value of a number parameter. The behavior stores its state machine definition in a hidden property edited with the "State Machine" tab of the object editor.
Cover the animation state machine with the GDJS test suite: - The parsing of the machine definition (parameters, states, transitions, sub-state machines, "Any State", blend trees). - The transition rules: conditions operators, triggers consumption, exit times, interruption rules and chained transitions. - The "Any State" and sub-state machines behaviors. - The behavior itself: playing the animations of the states, the blend trees (animation choice and blended speed), the state change events, and the hot-reload of the definition. Also register the extension runtime files in the karma configuration.
Add the data model of the state machine editor, mirroring the schema read at runtime by the behavior, with the editing helpers (states, transitions, conditions, parameters, sub-state machines, "Any State" and blend trees) and a safe parsing of the JSON stored in the behavior. Also add the integration and validation tools used by the editor: - Renaming an animation of the object updates every state (and blend tree motion) playing it, so the machine never loses its animations. - A validation pass reporting common mistakes (missing animations, states without animation, unreachable states, duplicated state names, conditions on deleted parameters, sub-state machines without entry state, blend tree problems...). Covered by unit tests.
Add the visual editor of the state machine, with a canvas showing the states and their transitions: - Draggable state nodes, with their animation (or their blend tree) shown on the node, an inline rename on double-click and a context menu (transitions, entry state, sub-state machine, duplicate, delete). - Curved transition arrows (with the condition count of the selected one), selectable and deletable, and a port to drag new transitions onto states or sub-state machines. - The green Entry node and the dashed "Any State" node (draggable), whose transitions are created from its context menu or its port. - Sub-state machine boxes containing their states: moving a box moves its states, and its header shows its entry state. - Pan and zoom (mouse wheel, zoom controls), a context menu to add states and sub-state machines, and the Delete/Backspace shortcut.
Add the panel editing the parameters driving the state machine: number, boolean and trigger parameters, with their name and default value, and a menu to add new ones. The parameters can be set from the events sheet and are used as the conditions of the transitions (and as the blend parameter of the blend trees).
Add the properties panel of the selection in the state machine: - For a state: its name, animation, speed and restart on enter, its sub-state machine and its entry state. - For a transition: its exit time, interruption source, "can transition to self" rule and its conditions on the parameters. - For a sub-state machine: its name, its entry state, the ungrouping and the deletion. - For "Any State": an explanation of its transitions. It also holds the blend tree editor: the blend parameter, the motions (animation, threshold, speed) and a live preview with an axis and a slider showing the animation played and its blended speed for any value of the parameter.
Add a "State Machine" tab next to Properties, Behaviors and Variables in the object editor, driving the animations of the object with a state machine (like Unity's Animator): - A first state is created when the state machine is enabled, so the machine works right away. - The tab gathers the parameters panel, the graph editor and the properties panel of the selection, with the validation warnings (clicking a warning selects the faulty element). - All the edits are saved in the hidden property of the AnimationStateMachine behavior of the object (created on demand), which keeps the machine in the project file with the object.
Register a custom editor for the AnimationStateMachine behavior, so its state machine can also be edited from the Behaviors tab of the object (the same graph editor as in the State Machine tab).
|
You're adding even more code, and proofreading all of this will easily one full day of work. A good example for example is the side bar (properties panel): it's now what we favor for all new UIs. I'm not sure your changes are displayed here. Another example is the fact that the UI is not stretched. Another example is the use of sliders, this is probably a decision by itself. I understand you feel empowered by AI agents able to build things for you: I encourage you to continue using them for prototyping and having fun. You can also use them with the GDevelop MCP to build games faster. But if you want to actually help for real getting improvements into GDevelop, you must:
|




Changes
TextureQuality3DManager.jsin exported games and previews.Shorter version (one line each, for a changelog):