Skip to content

t1k:unity:dots-rendering:graphics

FieldValue
Moduledots-rendering
Version2.1.7
Efforthigh
Tools

Keywords: DOTS, GPU, graphics, rendering

/t1k:unity:dots-rendering:graphics

  • DOTS — Data-Oriented Technology Stack
  • ECS — Entity Component System
  • ECB — EntityCommandBuffer
  • LOD — Level of Detail

Reference guide for the com.unity.entities.graphics package (v1.4.18 for Unity 6). To render ECS entities, use SRP Batcher-compatible batch rendering, material property overrides, LOD baking, and runtime spawn patterns as documented in the reference files below.

Render Pipeline: URP ONLY — This project exclusively uses URP (Universal Render Pipeline). All materials, shaders, and rendering features must target URP. Never use Built-in RP or HDRP materials/shaders.

Prerequisite: dots-ecs skill (ISystem, Baker, SystemAPI, ECB patterns).

  • Rendering entities using ECS (RenderMesh, RenderMeshArray, MaterialMeshInfo)
  • Setting up visual components during baking (authoring to Baker)
  • Overriding material properties per-entity at runtime
  • Spawning many rendered entities at runtime (bullets, particles, crowds)
  • LOD groups in ECS scenes
  • Enabling/disabling rendering of entities
  • Mesh deformation (skinned meshes, blend shapes)
  • Debugging missing renders or black entity meshes
TopicReference File
Package setup, component roles, namespaces, baking, RenderBounds, RenderFilterSettings, debug checklistrendering-setup-guide.md
MaterialProperty attribute, per-entity overrides, color animation, flash patternmaterial-overrides-guide.md
LOD group baking, LOD crossfade, mesh deformation, blend shapes, skinninglod-deformation-guide.md
Runtime spawning, prefab-based spawning, mesh/material swap, enable/disable, poolingruntime-patterns-guide.md
  • Minimize RenderMeshArray (shared component) changes — each unique RenderMeshArray creates a new archetype chunk, fragmenting memory
  • Swap mesh/material via MaterialMeshInfo indices — cheap index update vs replacing entire RenderMeshArray
  • Use DisableRendering tag to hide entities — avoids structural change of destroying/recreating
  • Batch spawn with IJobParallelFor + ECB — never spawn in a main-thread loop
  • Use [MaterialProperty] overrides sparingly — each unique override component type adds to the archetype. Group commonly-toggled properties
  • Prefer LOD baking for distant entities — reduces draw calls and vertex processing
  • Namespace: [YourProject].Rendering
  • To render an entity, it must have LocalToWorld, RenderMeshArray, MaterialMeshInfo, and RenderBounds
  • To share mesh/material data across entities, use RenderMeshArray as ISharedComponentData
  • To override a material property per-entity, declare an IComponentData struct with [MaterialProperty("_ShaderPropName")]
  • To hide an entity without destroying it, add DisableRendering tag; remove to show
  • To swap mesh or material cheaply, update MaterialMeshInfo indices — avoid replacing RenderMeshArray
  • To bake standard rendering, place a GameObject with MeshRenderer and MeshFilter in a SubScene
  • To spawn many entities efficiently, create a prototype entity then clone with a Burst IJobParallelFor via ECB
  • For ShaderGraph material properties, use the Reference name (not Display Name) in [MaterialProperty]

2D Sprite Rendering via Entities Graphics (2026-03-10)

Section titled “2D Sprite Rendering via Entities Graphics (2026-03-10)”

For 2D games, use quad meshes + URP/Unlit materials + [MaterialProperty] overrides:

// Create XZ-plane quad mesh asset (programmatic)
var mesh = new Mesh { name = "Quad2D" };
mesh.vertices = new[] { new Vector3(-0.5f,0,-0.5f), new Vector3(0.5f,0,-0.5f), new Vector3(0.5f,0,0.5f), new Vector3(-0.5f,0,0.5f) };
mesh.triangles = new[] { 0, 2, 1, 0, 3, 2 };
mesh.uv = new[] { new Vector2(0,0), new Vector2(1,0), new Vector2(1,1), new Vector2(0,1) };
mesh.normals = new[] { Vector3.up, Vector3.up, Vector3.up, Vector3.up };

MaterialProperty Components (dots-rpg Core)

Section titled “MaterialProperty Components (dots-rpg Core)”
// UV tiling/offset for sprite sheet animation
[MaterialProperty("_BaseMap_ST")]
public struct SpriteSheetUV : IComponentData { public float4 Value; } // (tileX, tileY, offsetX, offsetY)
// Per-entity color tint
[MaterialProperty("_BaseColor")]
public struct SpriteColor : IComponentData { public float4 Value; } // RGBA
// SpriteAnimation drives SpriteSheetUV each frame via SpriteAnimationSystem
public struct SpriteAnimation : IComponentData { public int FrameCount, Columns, CurrentFrame; public float FrameDuration, Elapsed; }
  • Shader: Universal Render Pipeline/Unlit (no lighting needed for 2D sprites)
  • Enable GPU Instancing on material
  • Set _BaseMap to sprite texture
  • [MaterialProperty] overrides batch efficiently via Entities Graphics

  1. ⚠️ ChunkWorldRenderBounds NaN = invisible entities — If ChunkWorldRenderBounds gets corrupted with NaN/garbage values, ALL entities in the affected chunk become invisible due to frustum culling. Root causes: (a) Baking lightmaps with SubScene CLOSED — per Entities Graphics 1.4 changelog: “You will need to bake with subscenes open.” (b) Mixed/Baked light mode on directional light — use Realtime mode for DOTS scenes. Fix: Set light to Realtime → bake_clear → delete SubScene file → re-run scene setup → clear Library/EntityScenes/ → Play. See unity-light-baking and unity-shadow-optimization skills.

  2. ⚠️ LODGroup + Amplify Impostor = invisible entities (ALL platforms) — Amplify Impostor URP shader is NOT SRP Batcher / BRG compatible. DOTS Entities Graphics uses BRG → impostor LOD1 renders nothing on ANY platform. If LOD0 transition is too high (e.g., 0.15f), LOD1 is the only active LOD → entities invisible. Symptom: Health bars visible but meshes gone, 0 draw calls in stats. Fix: Use ImpostorMaterialHelper.LoadOrCreateUrpLitMaterial() for ECS entities (standard URP/Lit from atlas), or set LOD0 transition to 0.01f. See amplify-impostors skill.

  3. MCP screenshots bypass frustum culling — manage_scene(screenshot) with custom viewpoint uses a temp camera that doesn’t follow normal frustum culling. Entities may appear in MCP screenshots but be invisible in Game view. Always verify rendering via Game view capture.

  4. MCP query_entities requires fully-qualified type names — Use [YourNamespace].YourTagComponent not YourTagComponent, Unity.Transforms.LocalTransform not LocalTransform.

  5. ⚠️ Transparent materials = per-entity draw calls (CRITICAL) — URP entities with _SURFACE_TYPE_TRANSPARENT (alpha blend) automatically get DepthSorted_Tag from Entities Graphics, forcing per-entity back-to-front rendering that defeats BOTH SRP Batcher and GPU instancing. Result: 1 draw call per entity (600 units = 600 draw calls). Fix: Use AlphaTest (cutout) instead — set _Surface=0 (Opaque), _AlphaClip=1, _Cutoff=0.5, keyword _ALPHATEST_ON, RenderQueue=AlphaTest(2450). Only use Transparent for genuinely semi-transparent effects (particles, AoE blasts). BattleDemo2D: 608→28 batches after this fix.

  6. ⚠️ Side-view Z-fighting between cutout quads (CRITICAL) — When a side-view camera looks along +Z and all unit quads sit at their navigation Z positions (0-20 range), quads at similar Z depths Z-fight because the depth buffer cannot resolve sub-unit differences at camera distance ~100. The SideViewTransformSystem maps Z→Y for visual placement but must ALSO compress Z via DepthSpread multiplier (default 0.1) to prevent flickering. Root cause: AlphaTest materials use opaque Z-buffer sorting with _ZWrite=1; transparencySortAxis only affects the Transparent queue. Fix: SideViewConfig.DepthSpread (default 0.1) compresses Z range from ~20 to ~2, giving the depth buffer enough precision to separate overlapping quads. Relative depth order is preserved. Set to 0 to disable (will cause flickering).

  7. ⚠️ BillboardSprite shader: _LightDirection / _LightPosition undeclared on glcore (Linux OpenGL Core) — The BillboardSprite.shader shadow pass #includes Shadows.hlsl but NOT ShadowCasterPass.hlsl. On glcore, _LightDirection and _LightPosition are declared inside ShadowCasterPass.hlsl, not Shadows.hlsl. Result: shader compilation fails on Linux with undeclared identifier '_LightDirection'. Vulkan is unaffected. Fix: Add explicit declarations before the CBUFFER in the shadow-pass HLSL block: float3 _LightDirection; float3 _LightPosition;. Apply to com.the1studio.dots-core/Runtime/Rendering/BillboardSprite.shader. Verified on Unity 6000.3.9f1 / glcore (Linux). Re-apply after any fresh import of the submodule.

  • MaterialMeshInfo.IEnableable semantics in v1.4+: per-material-slot or whole entity?
  • Unity 6 embedded Entities Graphics (v6.x): API diff vs 1.4.x (RenderMesh struct removal status)
  • GPU instancing interaction with material property override components when same material is shared across multiple RenderMeshArrays
  • Official stance on WorldRenderBounds being manually writable or strictly system-managed