Skip to content

Instantly share code, notes, and snippets.

@Lunchbox4K
Last active August 10, 2019 21:00
Show Gist options
  • Save Lunchbox4K/20e061241f0e89a4969a64574d0fac9e to your computer and use it in GitHub Desktop.
Save Lunchbox4K/20e061241f0e89a4969a64574d0fac9e to your computer and use it in GitHub Desktop.
Unity Component Based Instanced Sprite Sheet Renderer (2019.1) Test
/**********************************************************************
* Unity ECS - Test/Sample Code
* Mitchell Pell
* 2019.07.26
* v0.1
*********************************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Transforms;
using Unity.Mathematics;
using Unity.Rendering;
//---------------------------------------------------------------------
public class GameHandlerSpriteSheetRenderer : MonoBehaviour
{
//Enable/Disable sprite sheet animation test
[SerializeField] private bool createAnimatedSpriteSheet;
[SerializeField] private float animationFrameTime;
//Lazy code to get the quad mesh and sprite sheet material.
private static GameHandlerSpriteSheetRenderer s_instance;
public static GameHandlerSpriteSheetRenderer GetInstance() { return s_instance; }
//Mesh assigned in the editor that the SpriteSheetRenderer grabs.
public Mesh quadMesh;
//Sprite sheet material assigned in the editor that the SpriteSheetRenderer grabs.
public Material spriteSheetMaterial;
private void Awake()
{
/* Lazy code setting the instance of this class with quadMesh
* and spriteSheetMaterial defined. */
s_instance = this;
/* Get the Entity Manager and create a new Translation Entity
that the SpriteSheetRenderer will use to draw the Sprite. */
EntityManager entityManager = World.Active.EntityManager;
if (createAnimatedSpriteSheet)
{
AnimatedInstancedSpriteSheetTest(entityManager);
}
}
///
/// Animated Sprite Sprite Test using Instanced UV and the ECS system.
///
private void AnimatedInstancedSpriteSheetTest(EntityManager entityManager)
{
EntityArchetype spriteArchType = entityManager.CreateArchetype(
// SpriteSheetRendere
typeof(Translation),
// SpriteSheetAnimationSystem
typeof(SpriteSheetAnimation_Data)
);
Entity sprite = entityManager.CreateEntity(spriteArchType);
//Set
entityManager.SetComponentData(sprite,
new Translation
{
Value = new float3(0, 0, 0)
}
);
//Set
if (animationFrameTime <= 0) animationFrameTime = 0.2f;
entityManager.SetComponentData(sprite,
new SpriteSheetAnimation_Data
{
m_frameTimer = 0f,
m_frameTimerMax = animationFrameTime,
m_startFrameX = 0,
m_startFrameY = 0,
m_endFrameX = 0,
m_endFrameY = 24,
m_currentFrameX = 0,
m_currentFrameY = 0,
}
);
}
}
Shader "Custom/InstancedSpriteSheetShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_MainTex_UV ("Texture UV", Vector) = (1.000,1.000,0.000,0.000)
_Color ("Color", Color) = (1,1,1,1)
}
SubShader
{
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
LOD 100
Blend SrcAlpha OneMinusSrcAlpha // Traditional transparency
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
//Received Application Data Struct
struct appdata
{
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
float2 uv : TEXCOORD0;
};
//Vertex Struct
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
//Full floating point support with sampler2D_float.
sampler2D_float _MainTex;
// Set Potential Incomming Instancing Instanced Properties
//-------------------------
UNITY_INSTANCING_BUFFER_START(Props)
//Instanced Color
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
//Instanced UV Coordinates ( Animations, SpriteSheets, etc.)
UNITY_DEFINE_INSTANCED_PROP(float4, _MainTex_UV)
UNITY_INSTANCING_BUFFER_END(Props)
// Vertex Shader
v2f vert(appdata v)
{
v2f o; //Vertex Struct
//Instancing
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
//Get Vertex Data from Application
o.vertex = UnityObjectToClipPos(v.vertex);
//Calculate UV
//------------------------
//o.uv = v.uv; // Entire Texture is applied i.e. {1,1,0,0}
//Calculate UV Coordinates from Instancded Application Data
o.uv = (v.uv * UNITY_ACCESS_INSTANCED_PROP(Props, _MainTex_UV).xy) +
UNITY_ACCESS_INSTANCED_PROP(Props, _MainTex_UV).zw;
//------------------------
//Return Vertex Struct to the Fragment Shader.
return o;
}
// Fragment Shader
fixed4 frag(v2f i) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(i);
return (tex2D(_MainTex, i.uv) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color));
//return UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
}
ENDCG
}
}
}
// Resources Used:
// https://docs.unity3d.com/Manual/SL-Blend.html
// https://docs.unity3d.com/Manual/GPUInstancing.html
/**********************************************************************
* Unity ECS - Test/Sample Code
* Mitchell Pell
* 2019.07.26
* v0.1
*********************************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Transforms;
///
/// Animation Frame Component Data.
///
public struct SpriteSheetAnimation_Data : IComponentData
{
public int m_currentFrameX;
public int m_currentFrameY;
public int m_startFrameX;
public int m_endFrameX;
public int m_startFrameY;
public int m_endFrameY;
public float m_frameTimer;
public float m_frameTimerMax;
}
///
/// Animation System to update animation frames.
///
public class SpriteSheetAnimationSystem : JobComponentSystem
{
[BurstCompile]
public struct Job : IJobForEach<SpriteSheetAnimation_Data>
{
public float deltaTime;
public void Execute(
ref SpriteSheetAnimation_Data spriteSheetAnimationData) {
spriteSheetAnimationData.m_frameTimer += deltaTime;
while ( spriteSheetAnimationData.m_frameTimer >=
spriteSheetAnimationData.m_frameTimerMax)
{
spriteSheetAnimationData.m_frameTimer -=
spriteSheetAnimationData.m_frameTimerMax;
if (++spriteSheetAnimationData.m_currentFrameX >
spriteSheetAnimationData.m_endFrameX)
spriteSheetAnimationData.m_currentFrameX =
spriteSheetAnimationData.m_startFrameX;
if (++spriteSheetAnimationData.m_currentFrameY >
spriteSheetAnimationData.m_endFrameY)
spriteSheetAnimationData.m_currentFrameY =
spriteSheetAnimationData.m_startFrameY;
}
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
Job jo = new Job { deltaTime = Time.deltaTime };
return jo.Schedule(this, inputDeps);
}
}
/**********************************************************************
* Unity ECS - Test/Sample Code
* Mitchell Pell
* 2019.07.26
* v0.1
*********************************************************************/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Transforms;
/*
* Renders Sprites using Instanced UV Data
*
*/
[UpdateAfter(typeof(SpriteSheetAnimationSystem))]
public class SpriteSheetRenderer : ComponentSystem
{
public const float UV_UNIT = (1.0f / 4096);
public const float UV_TILE_W = (UV_UNIT * 32);
public const float UV_TILE_H = (UV_UNIT * 32);
public const int UV_TILE_ROWS = 64;
public const int UV_TILE_COLS = 96;
public static readonly Vector4 UV_START = new Vector4(
UV_TILE_W * 16, // W
UV_TILE_H * 8, // H
0f, // X
UV_TILE_H * 42); // Y
protected MaterialPropertyBlock m_materialPropertyBlock;
protected Vector4[] m_materialBlockMainTexUVArray;
protected override void OnCreateManager() {
base.OnCreateManager();
m_materialBlockMainTexUVArray = new Vector4[1];
m_materialBlockMainTexUVArray[0] = UV_START;
m_materialPropertyBlock = new MaterialPropertyBlock();
}
protected override void OnUpdate() {
Entities.ForEach(
// [ For Each Filter ]
(
ref Translation translation,
ref SpriteSheetAnimation_Data spriteSheetAnimationData
// [ For Each Method ]
) => {
//Get the UV Coordinates based on animation system.
m_materialBlockMainTexUVArray[0].z = UV_START.z + (UV_TILE_W * spriteSheetAnimationData.m_currentFrameX);
m_materialBlockMainTexUVArray[0].w = UV_START.w + (UV_TILE_H * spriteSheetAnimationData.m_currentFrameY);
//Add the UV coordinates to the material property block.
m_materialPropertyBlock.SetVectorArray("_MainTex_UV", m_materialBlockMainTexUVArray);
//Set transform matrix
Matrix4x4 transform = Matrix4x4.identity;
transform *= Matrix4x4.Scale(new Vector3(8, 4, 1));
//Render the sprite.
Graphics.DrawMesh(
// Mesh
GameHandlerSpriteSheetRenderer.GetInstance().quadMesh,
// Transform
transform,
// Material
GameHandlerSpriteSheetRenderer.GetInstance().spriteSheetMaterial,
//Layer
0,
Camera.main,
//Submesh index
0,
m_materialPropertyBlock
);
}
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment