- Home /
How do I assign a public variable inside a JobComponentSystem(ECS)?
I'm attempting to test the viability of running a compute-shader inside OnUpdate() inside the ECS Job system. However, I'm not sure when and where the JobComponentSystem object is created so I can't assign the compute shader below. I'm afraid my only option is to find it at runtime in the OnCreateManager() method. Even still, I don't think you can access Resources from job's threads at this time so I'm not quite sure how I'd find the compute-shader using pure scripting.
I thoroughly googled before coming here. I don't think anybody else has been crazy enough to try something like this yet.
The following code compiles, but of course gives a NullReference Error for the compute Shader when it runs.
using System.Collections;
using Unity.Collections;
using UnityEngine;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
public class PositionSystem : JobComponentSystem
{
public ComputeShader locGen;
public struct PositionData
{
public readonly ComponentDataArray<Position> Pos;
public readonly int Length;
}
[Unity.Burst.BurstCompile]
public struct PositionJob : IJobProcessComponentData<Position, Rotation>
{
public float deltaTime;
public void Execute(ref Position position, [ReadOnly] ref Rotation rotation)
{
//float3 value = position.Value;
//position.Value = value;
}
}
[Inject] PositionData m_Positions;
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
int kernelHandle = locGen.FindKernel("CSMain");
RenderTexture tex = new RenderTexture(256, 256, 24);
tex.enableRandomWrite = true;
tex.Create();
locGen.SetTexture(kernelHandle, "Result", tex);
locGen.Dispatch(kernelHandle, 256 / 8, 256 / 8, 1);
/*
for (int i = 0; i < m_Positions.Length; i++)
{
//Debug.Log(m_Positions.Pos[i].Value);
}*/
PositionJob posJob = new PositionJob
{
deltaTime = Time.deltaTime
};
JobHandle positionHandle = posJob.Schedule(this, inputDeps);
positionHandle.Complete();
return positionHandle;
}
}
@5argon please halp :)
Answer by racer161 · Nov 30, 2018 at 11:02 PM
So as it turns out, all my notions about ECS and Jobs were wrong.
OnUpdate() is actually called from the main thread so you can access (mostly?)everything from the monobehaviour API. What ended up actually doing is loading my ComputeShader at the top of my class and then finding a plane in my scene to paste the render texture to every update.
So basically I ended up not utilizing the jobs system at all. But my plan is to move the execution of this ComputeShader into a job of its own and use an ISharedComponentData to share a compute buffer between ECS and my compute shader which I'm hoping will give me a pretty good powerhouse for the simulation I'm attempting to do.
For now, here's the code that allows you to run the ComputeShader in OnUpdate(), which again, AFAIK is run on the main thread.
public class PositionSystem : JobComponentSystem
{
public ComputeShader locGen = Resources.Load<ComputeShader>("locationDraw");
public GameObject plane;
public struct PositionData
{
public readonly ComponentDataArray<Position> Pos;
public readonly int Length;
}
[Unity.Burst.BurstCompile]
public struct PositionJob : IJobProcessComponentData<Position, Rotation>
{
public float deltaTime;
public void Execute(ref Position position, [ReadOnly] ref Rotation rotation)
{
//float3 value = position.Value;
//position.Value = value;
}
}
[Inject] PositionData m_Positions;
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
int kernelHandle = locGen.FindKernel("CSMain");
RenderTexture tex = new RenderTexture(256, 256, 24);
tex.enableRandomWrite = true;
tex.Create();
locGen.SetTexture(kernelHandle, "Result", tex);
locGen.Dispatch(kernelHandle, 256 / 8, 256 / 8, 1);
//really hacky way to assign this, but its just for debug so who cares
if(plane == null) plane = GameObject.FindGameObjectWithTag("RenderPlane");
plane.GetComponent<MeshRenderer>().material.SetTexture("_MainTex",tex);
/*
for (int i = 0; i < m_Positions.Length; i++)
{
//Debug.Log(m_Positions.Pos[i].Value);
}*/
PositionJob posJob = new PositionJob
{
deltaTime = Time.deltaTime
};
JobHandle positionHandle = posJob.Schedule(this, inputDeps);
positionHandle.Complete();
return positionHandle;
}
}
I'd also like to mention here the viability of running compute shaders in tandem with ECS is not good. The lag introduced by copying data from the GPU to the CPU and back again nearly cancels out the benefit of the architecture.
It's clear ECS was engineered to be a lower latency replacement for ComputeShaders for small projects like pathfinding, trivial physics and the like. This leaves the GPU free for things like post processing and volumetric lighting in the new HDRP.
Your answer
Follow this Question
Related Questions
Is it possible to use a "hybrid" of BOTH Hybrid and Pure ECS? 0 Answers
Is it possible to have an entity component which behaves as a Stack? 0 Answers
How can I get a component data from an entity inside a JobComponentSystem? 1 Answer
[ECS] Create Entities from Job ( IJobForEachWithEntity) using an EntityCommandBuffer 1 Answer