Rendering limits and artifact diagnosis
Texture size, memory, banding, Z-fighting and transparent ordering.
Use the visible symptom to choose a fix. Texture allocation limits, memory pressure, color banding, depth precision and transparency ordering are different problems; changing every graphics setting at once makes the cause harder to find.
Texture dimensions are not a memory budget
There is no universal “4096 on phones, 8192 on desktops” limit. Maximum dimensions depend on the active API, driver and GPU. A supported dimension also does not mean the allocation will fit in available memory or run efficiently.
For RenderingDevice renderers, query the active device. This helper also reports the actual rendering method/driver, so a fallback does not go unnoticed:
using Reckfell;
public static class RendererInfo
{
public static string Summary()
{
return RenderingServer.GetCurrentRenderingMethod() + " / " +
RenderingServer.GetCurrentRenderingDriverName();
}
// Null means this API cannot report the limit, not that textures are unlimited.
public static ulong? MaximumTexture2D()
{
var device = RenderingServer.GetRenderingDevice();
// This is the engine's shared device. Do not dispose/free it here.
return device is null ? null :
device.LimitGet(RenderingDevice.Limit.MaxTextureSize2D);
}
}Call RendererInfo.Summary() after renderer initialization. MaximumTexture2D() returns the 2D size limit for the active RenderingDevice, or null when this query is unavailable, including the tested Compatibility/OpenGL path. Null does not mean unlimited textures or zero support. Do not dispose the engine's shared device. Do not use this limit as the maximum for cube, 3D or array textures; they have separate constraints.
The local probe successfully queried this limit in Mobile/Vulkan and Forward+/Vulkan. It did not attempt a maximum-sized allocation. Test representative textures in the actual exported build on the target hardware.
An uncompressed 4096 × 4096 RGBA8 image is 64 MiB before mipmaps. A full mip chain adds approximately one third, bringing it to about 85.3 MiB. Compression, layers, copies, render targets, MSAA and format change the cost; a small download file does not establish GPU memory use.
To reduce an imported texture, set Process → Size Limit (process/size_limit) to a positive maximum dimension and reimport. The importer downsizes the longer side and adjusts the other side to preserve aspect ratio subject to integer rounding; the original source file stays unchanged. Inspect the resulting resource, not just the source image's dimensions. A zero option is not a promise that all hardware limits are disabled. Compression format, mipmaps and target-platform import variants still matter.
Identify banding before changing lighting
Banding appears as steps in a gradient. It can originate in the source texture, compression, intermediate buffers or final output. HDR calculations do not guarantee that the eventual display signal has enough precision for every gradient.
- Inspect the source and imported texture before changing exposure. Converting an already quantized image to float does not restore missing values.
- Check the active renderer, render-target format and output path. Do not infer a fixed color/depth precision from “desktop” or “mobile” alone.
- In a RenderingDevice path,
Viewport.UseDebandingcan help hide output quantization with dithering. It does not reconstruct source detail. In the current Compatibility render-buffer implementation this flag is not consumed; a storedtrueis not proof of an effect. - For deliberately authored gradients, subtle dithering in the asset/material can help. Compare at the final output size; extra noise is not a correction for incorrect color conversion.
See HDR and exposure to separate color encoding, tone mapping and clipped data. Debanding does not fix light leaks or a texture assigned to the wrong material slot.
Distinguish Z-fighting from a texture defect
Z-fighting often looks like flickering patches that change as the camera moves. Nearly coincident surfaces compete for depth. Check for duplicate faces or overlapping meshes before replacing the texture.
- Remove duplicate geometry or give the surfaces a deliberate physical separation.
- Increase
Camera3D.Nearonly as far as the nearest required geometry permits. Too large a near distance clips nearby objects. - Reduce an unnecessarily distant
Far, but do not expect it to compensate for an extremely small near plane. - If
CameraAttributesPhysicalis assigned, changeFrustumNear/FrustumFaron that resource; it supplies the camera's clip values. - Recheck from the closest and farthest intended camera positions, in the active renderer. Reverse-Z and depth formats differ by path; do not promise a single bit count or a universal precision fix.
Polygon/depth adjustments are not a general fix for a physically invalid scene. Extremely large coordinates are also a separate precision problem; see large world coordinates for that workflow.
Choose transparency to match the asset
Alpha blending sorts transparent surfaces at the object/surface level, not by sorting every intersecting triangle. In the Forward+ source, priority and a per-instance depth key control ordering; SortingUseAabbCenter affects how that depth key is computed. “Everything sorts by the Entity origin” is therefore too absolute.
| Requirement | Starting choice | Limitation |
|---|---|---|
| Solid object | Opaque material | Setting albedo alpha alone does not activate transparency. |
| Leaf/fence with opaque and empty areas | BaseMaterial3D.TransparencyEnum.AlphaScissor with an appropriate threshold | No partially transparent coverage; examine cutout edges with the chosen AA. |
| Glass/smoke with partial opacity | Alpha blending | Intersections and ordering can remain wrong. |
| Small transparent part on a large solid mesh | Separate opaque and transparent material surfaces | Requires suitable mesh/material authoring. |
For a controlled layering case, Material.RenderPriority and VisualInstance3D.SortingOffset can change ordering. They do not make intersecting transparent volumes order-independent or restore hidden per-triangle depth information. Priorities are not a universal repair for glass, hair or vegetation.
Transparent surfaces do not participate in every opaque depth/normal pass in the same way. Check the specific screen-space effect before expecting it to handle glass like a solid wall. A depth prepass can change which fragments participate; it does not solve every blended overlap.
Work from a reproducible comparison
Keep the renderer, camera, exposure, viewport size and content fixed. Change one relevant variable, capture only after frame completion, and test motion as well as the still frame. See 3D antialiasing and standard materials for the individual controls.
Runtime evidence covers actual method/driver/device queries plus earlier native pixel checks for material alpha/scissor, MSAA, scaling and selected effects. Texture import resizing, memory exhaustion, banding/debanding, Z-fighting, transparent intersections and the full device/export matrix are source-reviewed guidance here, not claimed visual acceptance tests.