t1k:unity:dots-rendering:graphics
| Field | Value |
|---|---|
| Module | dots-rendering |
| Version | 2.1.7 |
| Effort | high |
| Tools | — |
Keywords: DOTS, GPU, graphics, rendering
How to invoke
Section titled “How to invoke”/t1k:unity:dots-rendering:graphicsUnity DOTS Entities Graphics
Section titled “Unity DOTS Entities Graphics”Terminology
Section titled “Terminology”- DOTS — Data-Oriented Technology Stack
- ECS — Entity Component System
- ECB — EntityCommandBuffer
- LOD — Level of Detail
Skill Purpose
Section titled “Skill Purpose”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-ecsskill (ISystem, Baker, SystemAPI, ECB patterns).
When This Skill Triggers
Section titled “When This Skill Triggers”- 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
Quick Reference
Section titled “Quick Reference”| Topic | Reference File |
|---|---|
| Package setup, component roles, namespaces, baking, RenderBounds, RenderFilterSettings, debug checklist | rendering-setup-guide.md |
| MaterialProperty attribute, per-entity overrides, color animation, flash pattern | material-overrides-guide.md |
| LOD group baking, LOD crossfade, mesh deformation, blend shapes, skinning | lod-deformation-guide.md |
| Runtime spawning, prefab-based spawning, mesh/material swap, enable/disable, pooling | runtime-patterns-guide.md |
Performance Rules
Section titled “Performance Rules”- Minimize
RenderMeshArray(shared component) changes — each uniqueRenderMeshArraycreates a new archetype chunk, fragmenting memory - Swap mesh/material via
MaterialMeshInfoindices — cheap index update vs replacing entireRenderMeshArray - Use
DisableRenderingtag 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
Key Conventions
Section titled “Key Conventions”- Namespace:
[YourProject].Rendering - To render an entity, it must have
LocalToWorld,RenderMeshArray,MaterialMeshInfo, andRenderBounds - To share mesh/material data across entities, use
RenderMeshArrayasISharedComponentData - To override a material property per-entity, declare an
IComponentDatastruct with[MaterialProperty("_ShaderPropName")] - To hide an entity without destroying it, add
DisableRenderingtag; remove to show - To swap mesh or material cheaply, update
MaterialMeshInfoindices — avoid replacingRenderMeshArray - 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
IJobParallelForvia ECB - For ShaderGraph material properties, use the Reference name (not Display Name) in
[MaterialProperty]
Documentation
Section titled “Documentation”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:
Quad Mesh Setup
Section titled “Quad Mesh Setup”// 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 SpriteAnimationSystempublic struct SpriteAnimation : IComponentData { public int FrameCount, Columns, CurrentFrame; public float FrameDuration, Elapsed; }Material Setup
Section titled “Material Setup”- Shader:
Universal Render Pipeline/Unlit(no lighting needed for 2D sprites) - Enable GPU Instancing on material
- Set
_BaseMapto sprite texture [MaterialProperty]overrides batch efficiently via Entities Graphics
Critical Gotchas
Section titled “Critical Gotchas”-
âš ï¸ ChunkWorldRenderBounds NaN = invisible entities — If
ChunkWorldRenderBoundsgets 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 → clearLibrary/EntityScenes/→ Play. Seeunity-light-bakingandunity-shadow-optimizationskills. -
âš ï¸ 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 to0.01f. Seeamplify-impostorsskill. -
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. -
MCP
query_entitiesrequires fully-qualified type names — Use[YourNamespace].YourTagComponentnotYourTagComponent,Unity.Transforms.LocalTransformnotLocalTransform. -
âš ï¸ Transparent materials = per-entity draw calls (CRITICAL) — URP entities with
_SURFACE_TYPE_TRANSPARENT(alpha blend) automatically getDepthSorted_Tagfrom 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. -
âš ï¸ 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
SideViewTransformSystemmaps Z→Y for visual placement but must ALSO compress Z viaDepthSpreadmultiplier (default 0.1) to prevent flickering. Root cause: AlphaTest materials use opaque Z-buffer sorting with_ZWrite=1;transparencySortAxisonly 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). -
âš ï¸ BillboardSprite shader:
_LightDirection/_LightPositionundeclared on glcore (Linux OpenGL Core) — TheBillboardSprite.shadershadow pass#includesShadows.hlslbut NOTShadowCasterPass.hlsl. On glcore,_LightDirectionand_LightPositionare declared insideShadowCasterPass.hlsl, notShadows.hlsl. Result: shader compilation fails on Linux withundeclared identifier '_LightDirection'. Vulkan is unaffected. Fix: Add explicit declarations before the CBUFFER in the shadow-pass HLSL block:float3 _LightDirection; float3 _LightPosition;. Apply tocom.the1studio.dots-core/Runtime/Rendering/BillboardSprite.shader. Verified on Unity 6000.3.9f1 / glcore (Linux). Re-apply after any fresh import of the submodule.
Unresolved Questions
Section titled “Unresolved Questions”MaterialMeshInfo.IEnableablesemantics in v1.4+: per-material-slot or whole entity?- Unity 6 embedded Entities Graphics (v6.x): API diff vs 1.4.x (
RenderMeshstruct removal status) - GPU instancing interaction with material property override components when same material is shared across multiple RenderMeshArrays
- Official stance on
WorldRenderBoundsbeing manually writable or strictly system-managed