private struct GatherRenderMeshJob : IJobEntityBatch
{
[ReadOnly]
public EntityTypeHandle EntityType;
[ReadOnly]
public SharedComponentTypeHandle<RenderMesh> RenderMeshType;
[ReadOnly]
public ComponentTypeHandle<LocalToWorld> LocalToWorldType;
public NativeList<Chunk>.ParallelWriter Output;
public NativeHashMap<Color, Entity>.ParallelWriter Map;
public void Execute(ArchetypeChunk batchInChunk, int batchIndex)
{
var colors = new UnsafeList<Vector4>(batchInChunk.Count, Allocator.Persistent);
var transforms = new UnsafeList<Matrix4x4>(batchInChunk.Count, Allocator.Persistent);
var entities = batchInChunk.GetNativeArray(this.EntityType);
var localToWorlds = batchInChunk.GetNativeArray(this.LocalToWorldType);
var mesh = batchInChunk.GetSharedComponentIndex(this.RenderMeshType);
for (var index = 0; index < entities.Length; index++)
{
Vector4 c = IndexToColor(entities[index].Index);
colors.AddNoResize(c);
}
transforms.AddRange(localToWorlds.GetUnsafeReadOnlyPtr(), localToWorlds.Length);
this.Map.AddBatchUnsafe((Color*)colors.Ptr, (Entity*)entities.GetUnsafeReadOnlyPtr(), entities.Length);
this.Output.AddNoResize(new Chunk
{
Mesh = mesh,
Colors = colors,
Transforms = transforms,
});
}
}```
#archived-dots
1 messages · Page 268 of 1
2nd shader? for what?
it nearly certainly has dependencies on my core library for some extension methods or something
skinned mesh renderers
ah
there's a weird issue that i could never figure out
commandBuffer.DrawMeshInstanced
commandBuffer.DrawRenderer
end up in different color spaces
so i had to convert the skin mesh render color space in the shader (did it that was just for performance reasons)
i don't know the issue, i couldn't figure out wtf was going on so i gave up and just went with the fix
here I go again xD
chunk is a struct in this class
{
public int Mesh;
public UnsafeList<Vector4> Colors;
public UnsafeList<Matrix4x4> Transforms;
}```
it's not a unity thing
ooh
😄
i should probably just directly do it myself
rather than like 2 implicit casts
probably be faster as well
justs you add a lot of elements to hashmap at once
i've posted it here a few times
you can just iterate if you dont want to deal with pointers
oh well
AddRangeNative
kek
what is this extension?
I assume it's cool one
since it works with pointer
kek
normal List
where T : struct
{
if (length == 0)
{
return;
}
var index = list.Count;
var newLength = index + length;
// Resize our list if we require
if (list.Capacity < newLength)
{
list.Capacity = newLength;
}
var items = NoAllocHelpers.ExtractArrayFromListT(list);
var size = UnsafeUtility.SizeOf<T>();
// Get the pointer to the end of the list
var bufferStart = (IntPtr)UnsafeUtility.AddressOf(ref items[0]);
var buffer = (byte*)(bufferStart + (size * index));
UnsafeUtility.MemCpy(buffer, arrayBuffer, length * (long)size);
NoAllocHelpers.ResizeList(list, newLength);
}```
probably doesn't help as you probably don't have NoAllocHelpers
😄
(which is actually an internal UnityEngine static class)
Does utility let you have conditions like getting a axe to cut the wood or would that be goap
The GetAxe Utility would be a score factoring in the need for wood and the missing axe.
The CutWood Utility would be a score factoring in the need for wood and the possession of an axe.
So unless your agent already posses an axe the utility for cutting is 0 and the GetAxe would score high. If you have an axe the Utility to Get an Axe scores 0 and the Utility to cut wood scores high
That makes the action basically chain automatically so thats why i tried to convince Issue to not use Actionqueues
action queues have nothing to do with AI tho
It's for controls
at very minimum it's a must for literal queued player actions
true.
i was able to skip action queues because i let my playerinput be processed by the UtilityAI too. kind of weird case
player basically defines the Action that should be executed and UtilityAi handles how its done
but i see why youd want that queue for your playerinput
public static BlobAssetReference<Collider> Create(NativeArray<float3> vertices, NativeArray<int3> triangles) =>
Why
Why NativeArray<float3> vertices, NativeArray<int3> triangles
Why not NativeArray<MyVertexType> vertices, NativeArray<ushort> triangles
Now I have to populate 2 vertex arrays and 2 triangle arrays when generating my meshes
You can use the low level API to create a vertex attribute descriptor so you only need 2 native arrays (vertex, index)
That's already what I'm doing, but I can't send them to MeshCollider.Create
I have a NativeArray<MyVertexType> for vertices and a NativeArray<ushort> for triangles, not a NativeArray<float3> and a NativeArray<int3>
Sorry what's MeshCollider.Create? is this related to Unity.Physics?
Ah mb then, I'm still not very familiar with Unity.Physics and thought you were talking about plain old meshes
Anyway, what Unity Physics do I need to add to the terrain chunk entities I create at run-time for players to be able to walk on my terrain and not fall through it?
Just adding Translation, LocalToWorld, and PhysicsCollider components isn't enough, players still fall through terrain with this:
var meshColliderReference = MeshCollider.Create(vertices, triangles);
EntityCommandWriter.SetComponent(entityIndex, entity, new PhysicsCollider
{
Value = meshColliderReference,
});
All my terrain chunk entities are from this archetype:
var chunkArchetype = dstManager.CreateArchetype(
typeof(LocalToWorld),
typeof(Translation),
typeof(PhysicsCollider),
typeof(PhysicsWorldIndex),
typeof(TerrainChunkTag),
typeof(TerrainChunkToGenerateTag),
typeof(TerrainBlock)
);
- components added by
Unity.Rendering.RenderMeshUtility
Hey guys, can someone give me a quick lesson on using local methods? I have a Entities.ForEach.Schedule, and just under it I have three local methods declared. When using .Run() they work, but Schedule() gives me this: Assets\Scripts\GameBoard\GameBoardSystem.cs(121,13): error DC0004: Entities.ForEach Lambda expression captures a non-value type 'this'. This is only allowed with .WithoutBurst() and .Run()
I'm assuming that it has to do with my local methods. Is there a special thing I can do to make this work or best just to convert them to static and pass in extra context (i.e. command buffer, etc)?
Oh shit, nvmd, I converted to static and I still get this error. What could be triggering this?
Where can I paste my code for review/input?
you need to paste fields into local variables, in order for ForEach to capture it
I'm aware of that, but it seems I am using something somewhere that I'm unaware of. Was wondering if I can post my code somewhere to get a second look at it from someone else?
yeah, just paste it here
You sure? Don't want to clutter chat.
@covert lagoon https://docs.unity3d.com/Packages/com.unity.physics@0.50/manual/interacting_with_bodies.html you can also make an entity without and with physics authoring components and just inspect exactly what components you need through the debugger or inspector
this chat is made for this, what are you on xD
lol alright. Other chatroom fret on this, that's why I hesitate. Alight one sec...
Shit. Nitro doesn't let me 😛
What websites can I paste it in and share link here?
pastebin
I think
usually
if text is too large
it'll just create txt file automatically
when you ctrl+v
Pastebin
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
and which line is error referrring to?
On pastebin, it would be Line 7
So not much help there lol
The local methods? Yeah I tried that, gave me the same error
That was my first assumption
Alright, I'll update that right now.
Done. Just tested works great with Run. Switching to Schedule gives me the exact same error.
Would you like to see the entire script file?
Oooff, I found two variables _camera and _physicsWorldSystem that were referenced unnoticeably. I just did var camera = _camera and var physicsWorld = _physicsWorldSystem just before Entities.ForEach.
And now I get this error:
Entities.ForEach Lambda expression captures a non-value type 'camera'. This is only allowed with .WithoutBurst() and .Run()
So I'm pretty sure now this is the exact issue. Although I don't understand how to get around this...
well
that's your answer
Managed types aren't allowed in scheduled/bursted jobs
get all data you need before the job
ArgumentException: A component with type:Unity.Physics.PhysicsWorldIndex has not been added to the entity.
Why?
Archetype:
var chunkArchetype = dstManager.CreateArchetype(
typeof(LocalToWorld),
typeof(Translation),
typeof(Rotation),
typeof(PhysicsWorldIndex),
typeof(PhysicsCollider),
typeof(TerrainChunkTag),
typeof(TerrainChunkToGenerateTag),
typeof(TerrainBlock)
);
Setting the PhysicsWorldIndex shared component (this appears in the stack trace of the exception posted above):
dstManager.SetSharedComponentData(entity, new PhysicsWorldIndex());
OMG, what a noob mistake! Yeah I collected the data beforehand now the error went away. But now I'm facing: : The previously scheduled job Broadphase:PrepareStaticBodyDataJob reads from the Unity.Collections.NativeArray1[Unity.Physics.RigidBody] PrepareStaticBodyDataJob.RigidBodies. You are trying to schedule a new job GameBoardSystem:GameBoardSystem_LambdaJob_2_Job, which writes to the same Unity.Collections.NativeArray1[Unity.Physics.RigidBody] (via GameBoardSystem_LambdaJob_2_Job.JobData.physicsWorld.CollisionWorld.m_Bodies). To guarantee safety, you must include Broadphase:PrepareStaticBodyDataJob as a dependency of the newly scheduled job.
Now I remember back in the 0.15 days that there was a way to inject Dependency into the PhysicsWorldSystem, how does that work now in v1?
If I use type punning for structs in C#, do I need to specify the struct layout, or can I rely on it being at the "beginning" of the struct as long as it is the first field in the struct?
Whole code:
using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;
public class TerrainAuthoring : MonoBehaviour, IConvertGameObjectToEntity
{
private const int SizeX = 128;
private const int SizeY = 16;
private const int SizeZ = 128;
public UnityEngine.Material material;
public void Convert(
Entity entity,
EntityManager dstManager,
GameObjectConversionSystem conversionSystem
)
{
var chunkArchetype = dstManager.CreateArchetype(
typeof(LocalToWorld),
typeof(Translation),
typeof(Rotation),
typeof(PhysicsCollider),
typeof(PhysicsWorldIndex),
typeof(TerrainChunkTag),
typeof(TerrainChunkToGenerateTag),
typeof(TerrainBlock)
);
for (var x = -SizeX / 2; x < SizeX / 2; x += TerrainChunkTag.SizeX)
{
for (var z = -SizeZ / 2; z < SizeZ / 2; z += TerrainChunkTag.SizeZ)
{
for (var y = 0; y < SizeY; y += TerrainChunkTag.SizeY)
{
var chunkEntity = dstManager.CreateEntity(chunkArchetype);
dstManager.SetComponentData(chunkEntity, new Translation
{
Value = new float3(x, y, z),
});
dstManager.SetComponentData(chunkEntity, new PhysicsCollider
{
Value = BlobAssetReference<Unity.Physics.Collider>.Null,
});
dstManager.SetSharedComponentData(entity, new PhysicsWorldIndex());
var renderMeshDesc = new RenderMeshDescription(new Mesh(), material);
RenderMeshUtility.AddComponents(chunkEntity, dstManager, renderMeshDesc);
}
}
}
}
}
sorry, I don't use physics
Oof. Thanks anyway.
C#, Visual Basic, and C++ compilers apply the Sequential layout value to structures by default.
So I'm guessing it's fine.
dstManager.SetSharedComponentData(entity, new PhysicsWorldIndex());
you're using entity not chunkEntity
Oh my fucking God
I'm going to go sleep
I can't even properly come up with sentences anymore
Holy shit it works
Obviously I don't get that error anymore
But most importantly, the player no longer falls through the terrain
I having this weird behiavor, i have a system JumpSystem thats use PhysicsVelocityExtension ApplyLinearImpulse to make my player Jump, thats works well, but i have another system MoveSystem that moves the player in Input.Axis direction using Translation += dir * speed * deltaTime.
So apparently modify Translation directly makes PhysicsVelocity Component go crazy , i mean , jump just work fine its update my physics.velocity.Linear.y axis , but when i move its also updating all of my physics.velocity.Linear axis , and the angular two . Are this behavior expected ? 😦 Maybe my move system need to update velocity.Linear axis and not to use translation at all ?
Is there a reason you aren't using the physics system for all movement?
What I'm getting at is that modifying translation directly circumvents the physics system, and can have weird behaviour.
If you really want physics based movement (and not a character controller), I would use the physics system for all movement. I've not written a movement system in DOTS yet though, so maybe others will have more insight.
There is no reason , i'm trying to make my own ThirdPersonController from scratch
thanks , i will try to use the physics systems for all movement
Is there a way to change Group for Unity's system?
I want to drop it into my own group
You can write custom bootstrapping to set up your own update groups
What do you mean by "Unity System"? Things like SimulationSystemGroup?
not group
If anyone is savvy with ECS Physics. Please help me figure this out: InvalidOperationException: The previously scheduled job Broadphase:PrepareStaticBodyDataJob reads from the Unity.Collections.NativeArray1[Unity.Physics.RigidBody] PrepareStaticBodyDataJob.RigidBodies. You are trying to schedule a new job GameBoardSystem:GameBoardSystem_LambdaJob_2_Job, which writes to the same Unity.Collections.NativeArray1[Unity.Physics.RigidBody] (via GameBoardSystem_LambdaJob_2_Job.JobData.collisionWorld.m_Bodies). To guarantee safety, you must include Broadphase:PrepareStaticBodyDataJob as a dependency of the newly scheduled job.
I tried _buildPhysicsWorld.RegisterPhysicsRuntimeSystemReadWrite() in OnStartRunning()
And I also tried adding _buildPhysicsWorld.AddInputDependencyToComplete(Dependency); in OnUpdate(). Both have failed.
The only Physics related thing I am doing in OnUpdate() is collisionWorld.CalculateDistance(queryInput, out var hit)
How can I prevent this conflict?
CompanionGameObjectUpdateSystem
I want this to update inside my group (since, doing it every frame is useless)
Sounds like solution is right here
you must include Broadphase:PrepareStaticBodyDataJob as a dependency of the newly scheduled job.
How do I get that JobHandle?
Woah, I just passed _stepPhysicsWorld.FinalSimulationJobHandle into the Schedule and it worked!
SystemGroups have methods to add and remove systems from their update list. I've never tried it though
hmm
Just make sure to remove it from the system it's currently in. Otherwise I think it's updated twice.
weird question but is it possible to create an OnEnable() method of a gameobject in a Systembase
Is there a way to make this Burst Compatible? Or System.Func is just not allowed?
private static bool VerifyNeighbor(DynamicBuffer<NumTacElement> numTacElements, int index,
int targetIndex, Func<int, int> next)
You mean when the system is created or when the entity is created?
no managed anything
System.Func is a managed type, so it isn't burstable
Ah. No equivalents for that I pressume?
kinda there is
You can use burstable function pointers.
https://docs.unity3d.com/Packages/com.unity.burst@1.4/manual/docs/AdvancedUsages.html#function-pointers
just in general or I guess when the system is created
Systems have an OnCreate method that is virtual
I would say that's quite a bit different than a function pointer 😅
I'll look into that, thanks
ty ty, I will read this over.
Make sure to read the caveats / limitations though.
Shit, I only need it to increment an int in certain steps (depending on circumstance). So it's as simple as i => ++i or i => i-9.
Maybe I should just hard code it and call it a day? lol
There's a new version of this that uses source generators.
https://forum.unity.com/threads/sources-included-polymorphism-in-dots-now-with-source-generators.1264616/
that's the spirit
xD
but actually
in terms of ECS
you are supposed to go away from OOP constraints
They are not supposed to work in ECS
Things like DRY still apply though, and is harder to achieve in DOTS compared to monobehaviors imo
That's why things like burstable function pointers can still be useful. Also the library you posted (polymorphism) is a huge hallmark of OOP. It can still be useful in data oriented design.
lol
Oh but function pointers require you define the actual operation ahead of time instead of from within code. It would be easier for me to hard code them because of their simplicity. Seems I just have to accept that this is an ECS limitation.
The reason they need to be defined beforehand is because burst needs to synchronously compile when you create a build.
I'm not 100% sure why this is an issue for you though? Do you mean something like lambdas?
Yeah
They basically function like non-capturing lambdas
I understand.
Thanks for that, saved that in my favorites.
Well, that's it for me today. I was able to convert to Schedule and fix all the errors. Thank you guys for your help and guidance. Take care 😉
omg that is so bad
that's exactly the opposite of how you should think for ecs
Do I understand correctly that it just creates struct type based of index and then just runs it's method?
I think there are still uses for it. I wouldn't personally put logic in them, but having polymorphic data can be useful
that's what generics are for (in ecs)
It creates a union
That doesn't work if you have a collection of differently typed objects
How would you handle a single component that contains a variable sized struct with generics?
wdym exactly?
For example, you have a component that contains some type of struct, but the components all need to be handled in some similar way, but their data differs
And the data is variably sized
(basically polymorphism)
??? if they all contain the same 'some kind of struct' and need to be handled similarily, then where's the problem?
Say you have 3 different types of structs, and this component needs to store all 3 different types, but only one at a time
yeah?
How would you put that in a component?
discriminated union
it puts logic on components
His example does, the asset doesn't
You can just pass the "correct" type to a function in a system that then handles it
The actual use is the automatic generation of the correctly sized union
that would be ok. but don't put LOGIC on components
That's literally the first thing I said
^
that wasn't explicit enough for me tbh. 'i personally wouldn't' -> no! you should NEVER put logic on components. personally or not
XD
That's your opinion. People are free to do whatever they want 🤷
and write bad code in the process
hear me out. what if we put logic on components but make them classes and rename them monobehaviours?!
and instead of entities we call them gameobjects.
Blasphemy.
👍
That's why I found it funny that enzi found it interesting how phil thought (putting logic in components). It's OOP with extra steps
I just think of it of a way to implement OOP inside ECS
kek
has it's niche case, but I just don't see it
i've written an analyzer that bans any use of non-data-oriented-aspects in ecs
wha
for example methods in components
How would you handle commonly required operations? e.g. many systems in a game need to equip / unequip items from entities or something. Store the function statically somewhere and call it in a system? Create entities and a reactive system? Use some other communication method like native streams?
exactly
I think for a lot of people there isn't a huge difference between having the function live somewhere statically vs storing it in the component
it's not meant for the people. it's meant for the program. you DONT DO THIS in data-oriented code
and if there's no difference, then why not just always make it static
I'm not super well versed in this. What makes it bad performance wise? Branch prediction / caching?
it's how data-oriented-design works
you SEPERATE data and logic
So a design issue, not a "program" issue
both
What makes it worse performance wise?
it captures this, the address may be moved around and other little things.
but primarily it's just not how DDD is to be approached
I forgot how to add angular axis constraints to physics bodies again
curiously does it handle equality overrides etc
I've never really thought about performance considerations, I just never do it because of
it's how data-oriented-design works
@misty wedge also, many programming languages do not allow methods in structs, only in classes. c# is very lightweighton that
Does C disallow methods in structs? I've never tried
C has no methods
C++ does not disallow methods in structs
As far as I know, the only difference between structs and classes in C++ is the default member visibility
Struct members are public by default whereas class members are private by default
in c++ there really is not even a difference between struct and class, since any can be allocated on stack or heap regardless
How do I disable angular velocity for a physics body, aaaaaaaaa
Right now I have this:
public void Convert(
Entity entity,
EntityManager dstManager,
GameObjectConversionSystem conversionSystem
)
{
dstManager.AddComponents(entity, new ComponentTypes(
typeof(PhysicsJoint),
typeof(PlayerControllerTag),
typeof(PlayerInput)
));
dstManager.AddComponentObject(entity, camera);
dstManager.SetComponentData(entity, PhysicsJoint.CreateLimitedDOF(
RigidTransform.identity,
new bool3(false),
new bool3(true)
));
}
The GameObject being converted already has the PhysicsBody and PhysicsShape authoring components
I can move the entity by changing its velocity just fine but it keeps rolling over
I never knew you couldn't even put a function in a struct in C haha
I don't want to change the angular velocity, I want to add constraints so that it's always 0
plain c is not object oriented.
so it does make sense
Yeah I know, but I didn't know that you can't even store a "static" (I know there's not such thing in C) function in a struct
The non-DOTS way would just be to tick a few boxes under the Rigidbody component in the inspector
so maybe set it to 0 each frame? i don't think there's built in functionality for constraints (yet?)
There is
then use that?
but that applies to joints?
theoretically a method instance might have more overhead than a static method because of vtabling but I've never profiled it down to that level yet 🤔
yes.
+1
not just theoretically, it's been profiled kek
static methods are faster, but REAAALLY slightly
allthough it wasn't tested in ECS, so can't know for sure regarding our use case
i am 99% certain it won't really change with ecs
im too lazy to profile and find out how much overhead a method in an instance has compared to a static method 😅
just don't do methods on components. the design aspect doesn't change either way
Why don't we have more documentation
for what?
Everything DOTS
Why does it use the virtual method table though? The method isn't virtual
I just want to contrain angular velocity axises
the documentation is pretty good for an experimental package
there's no such built in functionality (yet?)
what you linked is for JOINTS
I am 99% sure I saw something doing this by creating a joint where entity A is the entity we want to constrain and entity B is the null entity
But now I'm reading the documentation for PhysicsJoint.CreateLimitedDOF which I also remember seeing a while ago, and it already creates a joint by itself
Haven't looked too deeply into vtables & c# but i think it might be by design. For instance you could do something like this:
public class A {
public void Foo() {
}
}
public class B : A {
public new void Foo() {
}
}
It's not marked virtual, but because B is derivative of A, you will need a vtable in order to bind new void Foo() with B such that you can call bInstance.Foo().
That makes sense to me, but structs can't inherit from anything.
true
i haven't looked into how the sealed keywords works on the il level to say anything else on this
Can you store a BlobAssetReference inside a struct that is referenced by a BlobAssetReference?
I guess it would only be an issue when trying to serialize the BlobAssetReference...
I finally managed to get everything working
Very nice!
Thanks
If I pass a struct to a function with in, is the struct copied if I call a method on it?
in means it will be passed by reference
why does calling complete straight away make jobs run on main thread - why not still run on other threads but lock the main thread and wait until they are done, you lose the parallel work when needing it done straight away which is silly
Are you sure they're run on the main thread?
yeah mine is running on main at the moment
Do you have a profiler screenshot?
it's supposed to run in parallel, if there's enough job for "stealing"
not sure what you mean by that
worker threads only steal jobs if there's enough of it
enough of what though?
of jobs
well im calling 4 jobs straight away in a forloop on the main thread so it should take some
What he means is that the batch amount needs to be large enough so that the work can actually be scheduled to multiple threads
So if you scheduleparallel with a batch size of 32, but only pass a list that is 10 long, it will run on a single thread
this is how i call them:
while (segments.MoveNext())
{
NativeHashSet<Path2> closed = new NativeHashSet<Path2>(8, Allocator.TempJob);
NativeList<Path2> currentPath = new NativeList<Path2>(8, Allocator.TempJob);
GetCycles2 job = new(path, data, closed, currentPath);
var jh = job.Schedule();
jh.Complete();
HandleData(currentPath);
closed.Dispose();
currentPath.Dispose();
}
in total im calling 6 jobs
Yes, but you are forcing a complete before you schedule the next one
You need to combine the handles, and then call complete on the combined handles
oh i see
that might be difficult
how would i get all the results back
since my native containers are made in the loop with them =/
I think you could just keep track of the job structs in a list or something? The reference to your containers should still be correct
what are you doing with HandleData?
hm, is it possible to keep NativeContainer pointer in NativeContainer?
if it is
you can just make a list of lsits
and then unpack it once job is done
oh maybe
true and it would need parallel writing and that doesn't allow resize
So maybe something along the lines of:
var list = new List<GetCyclesJob2>();
var handle = Dependency;
while (segments.MoveNext())
{
NativeHashSet<Path2> closed = new NativeHashSet<Path2>(8, Allocator.TempJob);
NativeList<Path2> currentPath = new NativeList<Path2>(8, Allocator.TempJob);
GetCycles2 job = new GetCycles2(path, data, closed, currentPath);
list.Add(job);
var jh = job.Schedule();
closed.Dispose(jh);
handle = JobHandle.CombineDependencies(jh);
}
handle.Complete();
foreach (var job in list)
{
HandleData(job.currentPath);
job.currentPath.Dispose();
}
save them to HasHmap?
is it possible?
oh yeah
this also works
you can actually use
closed.Dispose(jh); whats this doing
DeallocateOnComplete attribute as well
Disposing the collection once the handle completes
oh it doesnt immediately dispose?
i see
ngl tho, unless your jobs are really huge
I'd suggest combining them all to 1
Scheduling is costly
while burst makes even large jobs really fast
if i combine there is still the issue of getting all the data back correctly
pardon the pun
😄
judging by unity forum
you can store NativeArray as value through pointer in HashMap
what does that mean
that means you will create list of lists in a job
so NativeHashSet<NativeList<Node>> ?
NativeHashMap
allthough
maybe Set is fine
I'm not really familiar with them all
kek
I guess it is fine
but it'll be a pointer
doubt it'll allow you storing List itself
You'd need to store an IntPtr, as you can't directly store type pointers in collections. At that point you might as well just use UnsafeList though...
so NativeList<UnsafeList<Node>> ?
though i still have the issue of parallel writing
it doesn't allow list resizing
It probably needs to be UnsafeList<UnsafeList<Node>>
And if you want to write to the same list in parallel, you would need to grab an UnsafeList.ParallelWriter
(and like you said, this will not auto resize)
Unused
0 B
Is the archetype chunk utilization of my terrain chunk entities perfect?
yeh the no resize is a problem
other than SCD can I save a class (MB comp) in an IComp without making a mess with archetypes?
I don't want to affect my main entity archetype. class sounds like a good solution, never tried this or ever written one 😄
class icomp and storing it on the entity directly basically do the same thing
just adding an extra step unless your class icomp has something else on it
i should look at the source code how unity adds MBs to entities. maybe I find out how to get the ptr then
it's for a mapping system and I want to use NativeHashMap instead of Dictionary so I can call add/remove methods from burst
so saving it on an entity is more or less a last resort
i just realisd parallel jobs using indices makes the use of iterating a multi hash map impossible -_- how annoying
You cannot use the build settings to build your project. How long will people keep doing this???
Does somebody have experience what's faster for setting transform position/rotation: iterating transform on an entity or TransformAccessArray. Currently I have a TAA solution but that has its downsides
Uhm, has anyone checked this? Child is not part of the archetype in the archetype window? How's that?
well, I dunno. the archetype window seems buggy. it doesn' show some buffers. IComps seem okay.
and WTH, I never realized that an endless combination of archetypes is built in the conversion stage which can be viewed with "show empty archetypes"
Then how come I just did it?
It worked the second time
It's still wrong
Do you want me to use Build Settings assets?
You need to use the build configuration asset
I think I'll need to use that when adding the NetCode for Entities package
You always need it
Why?
Because it says so
Who's "it"
normal build won't serialize subscenes. that's one of the major things why to use build conf, because there you can explicitly reference the subscenes
Also the asset is just .much much nicer
So subscenes won't be loaded?
not even exported. files are missing if you want to load them
Yeah
so, right now my conclusion is: archetype window doesn't show more than 31 components
any idea to handle entity references like target gracefully when the target entity is destroyed. having to check for entity exists kind of suck :/
my current idea is simply to only have 1 target component (or a buffer if i need multiple targets)
and then just validate it once start of every frame
alternatively, don't destroy your entities just disable them and clean them up later
and clean up the target in the AI with an is dead check or something which is pretty common in some path anyway
but yeah my design i'm going to try to go with is avoid HasComponent
and just code in a way to ensure state is valid
we have so many hascomponent checks in project at work and i feel there must be a better way
Tough decisions, I wanted to avoid a structural change but my health comp has a HealthState.Dead enum anyway which I could use to avoid that but that's no good for entity query. Just destroying the entity is a bit forceful. Best thing I guess is to have a dedicated job at the beginning that checks for valid targets instead of having multiple checks all over jobs.
something in your code needs to detect when target is dead/destroyed
because you have to react to that
may as well just do it once and ensure state
very true, I only have 1 target comp so at least I don't have to iterate over several entity queries
thing is target is not my only reference. I create a small archetype for path finding requests that has an Icomp and a buffer which another job iterates to walk the path from the buffer. I thought about adding this as LinkedEntityGroup to the main entity but then another buffer on the main entity ... ugh
until entities dying I had no HasComponent ... haha
i think i'll build a NMHM for this. I hate data like childs, parents, linkedentitygroup and other useless shit to be in a chunk
and have a seperate method that basically overrides commandBuffer.DestroyEntity
I also hope Unity redesigns this. It's just lazy of them to put everything in as buffer and IComps for something so essential
like what do they expect? simd code for linkedEntityGroup? lol
With jobs like these I'm also struggling to handle the chunk version. Just getting the write handle increases the version number but if everything runs smooth there's no actual write
well yeah, if you're using change filtering you can only use ComponentDataFromEntity and CommandBuffers to set the value
Yeah, that would not be worth it I believe.
Then I rather abuse the pointer system and get a sneaky RO ... hehe - not that I would ever doing something this dirty
What are some best practices when I have situations with cross-scene referencing? Like on ECS sub-scene I have authoring GO and I want to associate a non-ECS side UI GO.
Elaborate?
Well I have a game board type of deal. And a UI button that when pressed will set a flag (via BlobAssetReference) that the game board on ECS side will pick up and perform the specific action and reset the flag. But the Game UI canvas sits outside the ECS subscene.
All I need is for the game board authoring to be aware of the UI and just copy the BAR to its data component during conversion.
I don't really get what you're struggling with
That’s alright, don’t worry about it. I guess I just can’t explain it right.
is it possible to add an interface to a job besides the Ijob ones so i can put jobs into a regular list with polymorphism. sadly ijob and ijobfor etc dont share a base interface -_-
hmm you could maybe work with wrappers around the job that share the same interface.
I dont know about best practices but whats stopping you from using events? Just handle it with the methods you would normally use to communicate across additive Scenes where you cant have direct references.
Btw Blobassets are not supposed to be used for changing data.
would this be a reliable way to know when all jobs are complete:
int jobCount = 0;
void OnCyclesComplete(GetCycles2 job)
{
Debug.Log("Path Found");
for (int i = 0; i < job.Path.Length; i++)
Debug.Log(job.Path[i].NodeA);
job.Dispose();
jobCount--;
if (jobCount == 0) // is this a safe bet?
_callBack?.Invoke();
}
var segments = data.GetValuesForKey(n);
while (segments.MoveNext())
{
var s = segments.Current;
var closed = new NativeHashSet<Path2>(8, Allocator.TempJob);
var cycle = new NativeList<Path2>(8, Allocator.TempJob);
var job = new GetCycles2(new Path2(s), data, closed, cycle);
JobController.Instance.Add(ref job, OnCyclesComplete);
jobCount++;
}
god damn it , it wont let me parallel read from a multi hash map wtf
why is reading from these containers restricted so much if its read only
are you reading it while it's being used on main thread?
because it definitely is fine to read in multiple threads
oh i think i know what it is. im disposing it when the first job's callback occurs
but other jobs are still running
ok my counter system did the trick to solve that problem
does profiler have a search box
i can never find the jobs 😄
it happens so fast im probably not even near the frame it occured in
ah i found them at last
guys is the entity inspector actually bumping the changeversion of components??? I have a system that usually only runs after a certain playerinput once. if i open the entity inspector it triggers every frame
So maybe this is only in live edit mode then?
ill try what happens with closed subscene. but even in live edit i would consider that a bug
earlier you talked about changeversion. So CDFE doesnt bump it when you read?
I am still trying to figure out sensible pattern to use changefilter...
nothing changes the version when you read
hm yes i worded that badly sry. i meant if i declare write access on a CDFE and then not actually access an entity nothing happens?
what tertle meant was that CDFE does only bump the version for chunks you are writing to while a write handle changes every version of a chunk
yes thats what i was asking basically. so if i want to use changefilter and have a low amount of writes anyway CDFE seems good
a pain I'm dealing with 🙂 but CDFE is not a good option for my case
yes, more or less your only option. command buffer is another, although I'd just write to the CDFE, especially when it's not involved in a race condition anyway
CDFE is much faster than one would expect. at least I'm always underestimating it
mostly because it has good caching. a write is still a write and no matter what, always somewhat expensive
so if you are using change filtering/DidChange it's a good solution to circumvent the global write handle problem
What is actually the problem with only bumping the changeversion on a chunk where an actual write occured? is it that much more expensive to check?
Thinking about it myself i guess it would be alot more expensive. but so much more convienient too 😦
the problem is with write handles like var targetInfos = chunk.GetNativeArray(TargetInfo_WriteHandle); it doesn't matter if you actually write something back. just acquiring the handle will bump up the chunk version so a DidChange will occur even when there was none
so other systems that also rely on DidChange will have true because the whole chunk got bumped
basically, if you have one write handle DidChange will always be true
yep. my question was why the bumping of the changeversion needed to be at that step and not later when i actually write. but that would need some form of indirect access to the data then
yeah, some form of code-gened lazy loading would be great. maybe that will come at some point
id like to have manual control over it if needed.
I do hope so because it's very difficult to get DidChange work correctly
changefilters would be super powerful but atm it requires so many sacrifices
preferably, yes. that's why DreamingImLatios is suggesting manual tracking of SystemVersion and utilizing ChunkComponents for it
I have not really understood the manual tracking though
yes that works if the system runs anyway. but if i want the system to run once every X seconds because of some event then i dont want to manually poll the changeversion
Preferably id like to skip the whole systemupdate
In one of my cases its userinput that triggers a chain of events that only need to be processed exactly once. this will happen very rarely
i use system groups for this
just put a collection of systems in a group that only needs to run on a condition then put the condition in that actual system group
to determine if it should update
i use this for things like, ghosts spawning on client to set them up
BTW Inspection bumps the version regardless of LiveEdit
definitely a pain because it'd trigger a constant navmesh rebuild for me
it ofc only happens if you inspect the entity with the component you are changefiltering for. so just dont inspect the wrong entities then xD
means i cant inspect my units anymore lol.
its a complicated chain of events spanning abilities, Formation, playerinput... cant pack it in 1 systemgroup sadly
but it sounds like nothing should execute unless you have user input?
some of the systems also execute when ai is deciding something
its a weird case. i see your point with the systemgroup. ill think about whether i can restructure the architecture a bit
its a useful pattern for improving performance a bit
rather than a lot of systems having to constantly check their queries if they should run etc
just hide it behind 1 check
thats really good for userinput stuff for sure. atm i am polling way too much
Ill write a Bug Post on Forum
Is there any reason to use byte over int?
if I know for sure, I'll never go above above 250
sure it's 1 byte instead of 4
is storing a method inside a field in the struct and then using it inside a job a good idea?
it's against ECS design
It's not inherently good or bad. It's all about your own situation and considering pros and cons. I've done this in a couple of places but more so with properties.
If you need to calculate X based on Y and Z and they all make sense as members of the component, there is no problem that I'm aware of with X being a member of the component as a property. If you need a method because you need to pass something in from outside the component then it's worth reconsidering.
there's nothing wrong with it.
i would argue having logic on components probably goes against pure ecs ideas and generally should be avoided
however there are certainly case where properties/methods on components are useful and quite helpful especially if they are used to present the data that exists on the component .e.g CalculatePercentageHealth() => Health / MaxHealth;
If I had to simply this as a rule I'd say, avoid any method that requires external data. If the method can work with only the data on the component then it's probably 'fine'.
that said, blindly following rules and patterns is dumb and there are always exceptions. make up your own mind and use whatever solution fits your problem the best.
unity even builds a dedicated feature with IAspect for it which is this idea on crack
as long as it's shaping a better code architecture that's easy to understand, maintain and extend everything is allowed. ecs has no real pattern or design to speak of.
Enzi bro what are you working on
How to make one entity the parent of another at runtime? When I add the Parent component to the child before adding LocalToParent, it says I need LocalToParent. When I add LocalToParent to the child before Parent, it says I need Parent
well that is what function pointers are for
and no. that's not really against ecs design
@rotund token sir, smth wrong with your algorithm of entity selection
var colors = new UnsafeList<Color32>(batchInChunk.Count, Allocator.Persistent);
var transforms = new UnsafeList<Matrix4x4>(batchInChunk.Count, Allocator.Persistent);
var entities = batchInChunk.GetNativeArray(EntityType);
var localToWorlds = batchInChunk.GetNativeArray(LocalToWorldType);
var mesh = batchInChunk.GetSharedComponentIndex(RenderMeshType);
for (var index = 0; index < entities.Length; index++)
{
var ind = entities[index].Index;
colors.AddNoResize(IndexToColor(ind));
}
transforms.AddRange(localToWorlds.GetUnsafeReadOnlyPtr(), localToWorlds.Length);
Map.AddBatchUnsafe((Color*) colors.Ptr, (Entity*) entities.GetUnsafeReadOnlyPtr(), entities.Length);
same code, I didn't change anything
yet Map seems really off
oh wait
I did change it from Vector4
check the creation of the render texture
in my code vs your code
because of the previous mentioned issue of renderbatched vs rendermesh calls using different color space
it's setup very specifically
oh just looked at your screenshot
yeah that's just wrong it definitely creates the colours fine
private void UpdateCamera()
{
_renderTexture = RenderTexture.GetTemporary(
_camera.pixelWidth,
_camera.pixelHeight,
24,
RenderTextureFormat.Default,
RenderTextureReadWrite.Linear);
_renderTexture.antiAliasing = 1;
_renderTexture.filterMode = FilterMode.Point;
_renderTexture.autoGenerateMips = false;
}
it was always off for some reason
the values in your hashmap are just garbage
I managed to fix it a bit by removing all bounds checks (no idea how it fixed anything), but then after bringing them back
I keep fighting this issue
have you break pointed on your colors array before merging it to the hashmap
Map.AddBatchUnsafe((Color*) colors.Ptr, (Entity*) entities.GetUnsafeReadOnlyPtr(), entities.Length);
well yes
you're storing it as Color32
that's not a float
thats 4x bytes
no where are you converting the bytes to floats
and that's why
you're not converting it though
your hashmap is Color, Entity
but no where are you converting Color32 to Color
you have remapped the byte memory into float memory
and it produces the above garbage
private static Color IndexToColor(int index)
{
var r = (float) (index & 0xFF);
var g = (float) ((index >> 8) & 0xFF);
var b = (float) ((index >> 16) & 0xFF);
var a = (float) (255 - (index >> 24));
return new Color(r, g, b, a);
}
will that do?
no because that will be wrong color
that will be 255x higher
color is 0-1
you're passing in 0-255
I'm confused
private static Color IndexToColor(int index)
{
var r = (byte) (index & 0xFF);
var g = (byte) ((index >> 8) & 0xFF);
var b = (byte) ((index >> 16) & 0xFF);
var a = (byte) (255 - (index >> 24));
return new Color32(r, g, b, a);
}
Here's your original
yes
new Color32(r, g, b, a);
thats in byte format
it hten implicit casts to Color
which is really just /255f
your IndexToColor is not the same as mine
private static Color IndexToColor(int index)
{
var r = (byte)(index & 0xFF);
var g = (byte)((index >> 8) & 0xFF);
var b = (byte)((index >> 16) & 0xFF);
var a = (byte)(255 - (index >> 24)); // flip the A just to make it easier to read since it'll likely never be used anyway
return new Color32(r, g, b, a);
}
it is from your file
I used it the whole time
var colors = new UnsafeList<Color32>(batchInChunk.Count, Allocator.Persistent);
your colors list is Color32 though
sorry wait, your new screenshots looks fine though?
(im not paying that much attention atm... new poe league ^_^")
is it possible to set material to RenderMesh in Burstable system?
hmmmmm
private Color GetColorAtMousePos(Vector2 curPos)
{
RenderTexture.active = _renderTexture;
Rect rect = new Rect(curPos.x, curPos.y, 1, 1);
// Rect rect = new Rect(curPos.x, curPos.y, 1, 1);
_pixelTexture.ReadPixels(rect, 0, 0);
_pixelTexture.Apply();
RenderTexture.active = null;
RenderTexture.ReleaseTemporary(_renderTexture);
return _pixelTexture.GetPixel(0, 0);
}
am I doing smth wrong?
why color is incorrect?
oh wait, maybe height is inverted
well, it works when there's just 2 entities
but when I added 8
it doesn't
now colour is wrong again
sooo, it feels like it draws only 1 mesh during instanced call
not sure what's up sorry
i tested it with quite a few instances and it seemed to work fine
hmm ok did some investigation
i can kind of repo something but it's late and i need to sleep so i haven't figured out what part is broken
but it's definitely not just drawing 1 (at least for me)
ok, this is extremely weird
after some game time
it started to draw them
wtf
and for some reason now
it draws same instanced
several time
wait
now it creates 9 chunks, lol
to draw 9 entities
Color is fine though
smth about chunks creation
i can definitely repo the missing stuff
so yeah will look at it tomorrow
need to sleep
@rustic rain if you want to solve it sooner i think it's the shader
yeah, it was indeed shader
but chunks creation is still messed up
it creates chunk for every entity
meanwhile chunk itself has length of all actual chunks
so it makes a draw call for array of 9, meanwhile there's only 1 valid matrix
can I get link to the repo? I think I missed that one
thanks!
I wonder, should I allocate and dispose of a list per system update, or should I cache it inside the system and reuse?
what's the best job type for lists? IJobParallelFor needs length and for that I need to Complete() job that populate the list. Is there a way to do it smart or have I to use IJob and manually iterate inside?
I have NativeList and I want to make a job that do some calculations on every element of that list
but the problem is, I populate it from another job so I don't know the size of this list to use IJobParallelFor when I schedule it
well, why not just do it on single thread?
Try NativeList.AsDeferredJobArray() - its use case is that a list is populate by a prior job and then treated as a native array in the following job
will it check if list has length of 0?
not sure - havent tried that yet 🤔
strange
IndexOutOfRangeException: Index 0 is out of range of '0' Length.
but i'm sure i'm adding something in previous job
How can I see how much time a system takes to update in the standalone game?
you can connect a profiler to your app
By following this? https://docs.unity3d.com/Manual/profiler-profiling-applications.html
@coarse turtle is it a good setup? because it's still showing that array has 0 length
jobHandle = new JobDeffer{ array = array.AsDeferredJobArray() }.Schedule(
array ,
5,
jobHandle
);
probably
there is even a standalone profiler now
But I was told to use Build Configuration assets instead of the Build Settings window to build my game
Hopefully setting "Configuration" to "Develop" here will make it work
yea looks right just from that snippet 🤔
before that I just do:
jobHandle = new JPF { writer = list.AsParallelWriter() }.Schedule(1, 5, jobHandle);
which do:
public struct JPF : IJobParallelFor
{
[WriteOnly] public NativeList<TestStruct>.ParallelWriter writer;
public void Execute(int i)
{
writer.AddNoResize(
new TestStruct
{
input = 0,
scale = 1,
shape = 1,
horizontalShift = 0,
verticalShift = 0,
value = 0
}
);
}
}
for testing purposes
let me try something out
when you create your list to write to, you initialize it w/ the maximum capacity right?
iirc - you also might not be populating the list to the maximum capacity either right?
yea so i just tried that example, i guess with AsDeferredJobArray you'll need to keep the size consistent when you write & read. So if you intend to process 10 elements as a parallel writer - when you read as an array in the next job, you'll likely want to process the array w/ 10 elements. You'll also want to do an early out check if in the event you don't write which kind of seems like a waste to do in a job 🤔
like wtf, so it seems useless job type
I can do it with standard IJobParallelFor if i've got max capacity
btw IJobParallelFor is the old API. Its now IJobFor.ScheduleParallel()
I'm making a game with Minecraft-like terrain but finite. Still, there are many terrain chunks and I don't want to regenerate the mesh for every single one there is to regenerate the mesh for in a single frame.
How can I update only a certain number of them at most per frame, especially since IJobEntity*s only accept EntityQuerys?
@hot basin do you also use a IJobParallelForDefer job?
if i need burst to recompile is it enough to clear the burst cache?
Burst is complaining about a generic job not beeing initialized correctly. even after i removed all generic stuff inside the job.
best to just restart unity
yep a JobDeffer mentioned earlier is IJobParallelForDefer
public partial class EffectHandlerSys<T> : SystemBase where T : struct, IComponentData
{
private EntityQuery updateEffectQuery;
protected override void OnCreate()
{
updateEffectQuery = GetEntityQuery(ComponentType.ReadWrite<ActiveEffect>(),
ComponentType.ReadOnly<EffectSettings>(),
typeof(AttributeModifier<T>),
ComponentType.ReadOnly<EffectModifier>());
}
protected override void OnUpdate()
{
var time = Time.ElapsedTime;
Dependency = new UpdateEffectJob
{
time = time,
activeEffectHandle = GetBufferTypeHandle<ActiveEffect>(),
effectSettingsHandle = GetComponentTypeHandle<EffectSettings>(true),
//targetModifierFromEntity = GetComponentDataFromEntity<AttributeModifier<T>>(),
effectModifierHandle = GetComponentTypeHandle<EffectModifier>(true)
}.Schedule(updateEffectQuery, Dependency);
}
}```
im out of ideas. Burst always complaining about unresolved generics
But Burst should be able to resolve with this:
public class UpdateSpeedEffectSys : EffectHandlerSys<Speed>{}
Note that i dont even use any generics inside the job anymore. it has something to do with scheduling the job
Error msg : " Reflection data was not set up by an Initialize() call "
Well i couldnt figure out what i was doing wrong with IJobChunk. Switched to manual chunk iteration with IJobFor and it works.
Nah burst can't resolve that
so what do i have to register in the assembly then?
with IJobFor burst has no problems :S
I already showed you how I do it
@rotund token hi maybe you would know how to run 2 jobs, one that populate a NativeList and second one that use that list to do some calculations? (more on that above)
but TL:DR: I don't know how many elements there will be so I tried IJobParallelForDefer but it don't see the content of populated list
here is the setup of deffered job
and here I'm populating the list
as for code of deffered job it have nothing but:
[BurstCompile]
public struct JobDeffer : IJobParallelForDefer
{
public NativeArray<TestStruct> array;
public void Execute(int i)
{
var element = array[i];
array[i] = element;
}
}
as I strip down it to bare minimum to get it running first
i take it 'array' on your scheduling is not an array, but a nativelist
ah so this part is necassary :
protected override GenericJob CreateJob() => default;
i thought it would just be enough to create a concrete system like you do.
I get IndexOutOfRangeException: Index 0 is out of range of '0' Length. on var element = array[i]; line
ok so first thing i'm seeing
is you're populating an as parallel native list
asparallel native list can't resize, so either you know the size beforehand or just the max capacity?
I assume SharedComponentFilters only allow for WithAll setting? no excluding?
@hot basin you're not still on 0.17 are you?
i feel like i remember an issue with the nativelist and parallel writer not being copied properly
I changed it to IJobFor and used the list directly but result is the same
kind of implies your original job is not writing anything
your original list has capacity right
nah that whole line there is the magic
var list = new NativeList<TestStruct>(10, Allocator.TempJob);
public struct JPF : IJobFor
{
[WriteOnly] public NativeList<TestStruct> writer;
public void Execute(int i)
{
writer.Add(
new TestStruct
{
input = 0,
scale = 1,
shape = 1,
horizontalShift = 0,
verticalShift = 0,
value = 0
}
);
}
}
jobHandle = new JPF { writer = list }.Schedule(1, jobHandle);
jobHandle = new JobDeffer{ array = list.AsDeferredJobArray() }.Schedule(
list,
5,
jobHandle
);
this is all I do
here
it's array as list.AsDeferredJobArray() returns array
thanks! i googled a bit and came across this: https://nagachiang.github.io/unity-dots-creating-generic-systems-with-generic-jobs/#
Sure its old but i thought the rules for burst havent changed much since then. Guess you shouldnt look at 1,5 yr old posts.
array , // THIS HERE SHOULD BE list
5,
jobHandle
);```
oh yeah it is, sorry I'm editing it as we speak
I have this problem bothering me:
I need some kind of system to enable/disable rendering on entities based on where player's view at (at which room).
And all new entities coming/leaving room also need to get according treatment.
Rooms are sharedcomponent with only field - integer ID
So in best case scenario I'd simply just do:
AddComp<DisableRendering> to query of all sharedcomponents that aren't current room
And RemoveComp<DisableRendering> to query of shared components that is current room.
But here's the problem: shared comp filter has no excluding option. So one solution: I add this tag to literally all, and then remove it from current room entities. Every update.
I don't like this solution at all. Any other ideas to solve this?
why not just keep a record somewhere of current visible room?
I do have a record of current visible room
so when current room becomes not visible, just add the disable rendering component then?
it's just that entering/leaving entities or player who switches room through non-direct player action make things dirty
rooms are shared component
so what?
so in order to do clean query
without adding unnecessary tags, that will be removed right after adding
I need to do query for every room
no you don't?
how?
public void SetRendering(InSystemComponent system)
{
EntityManager.AddComponent<DisableRendering>(_toDisableQuery);
_toEnableQuery.SetSharedComponentFilter(system);
EntityManager.RemoveComponent<DisableRendering>(_toEnableQuery);
}
Here how I do it right now
Query.SetSharedFilter(new room {Value = oldVisibleRoom})
Query.SetSharedFilter(new room {Value = newVisibleRoom})
why doesn't that work?
but there are 70 rooms
yes but they're all previously invisible
ooooh
you only need to change what was previously visible
that is smart
I didn't think of it
xD
well
actually, that's also has it's problem
entities are supposed to get created constantly
so new NPCs
come up
in different rooms
literally every second
and when you create them you should set their initial state depending on their room
so it won't be fail proof
but it will be efficient
what about doing it dirty way
public void SetRendering(InSystemComponent system)
{
EntityManager.AddComponent<DisableRendering>(_toDisableQuery);
_toEnableQuery.SetSharedComponentFilter(system);
EntityManager.RemoveComponent<DisableRendering>(_toEnableQuery);
}
like this, every update
is it really that bad?
depends if you are hitting something in the query
if the query is empty this basically just early outs
EntityManager.AddComponent<DisableRendering>(_toDisableQuery);
this is supposed to affect thousands
oh wait
more like
dozens
from 20 to 100 on average I'd say
and then I'll remove that tag
right after adding
every update
100s of structural changes a frame doesn't sound great
its not hundreds though since the whole chunk is changed at once. no copies. but not sure what the consequences are. profiling would be interesting i think
really wish, Unity would just make excluding filter option
@rotund token so no luck with that defer job?
u mean None/WithNone?
yeah, but for shared component filter
looks fine but i think you need to make a quick test on latest collections though
i think i can't move to latest collections
anyone has a suggestion for handling entities that get very big or any insight how you are handling this? I currently have an entity that now gets a second collider, one for collision one for triggers (aggro radius) and I feel like it's getting all a little too big and it should be split.
dont look at my entites. im happy if 3 fit into 1 chunk
curious why you need a second collider - that doesn't sound like the performance king enzi i know
if you have some sets of components that are completely orthogonal to each other it might be worth it to split those sets into entities and only have the one result that matters for your "main" entity written back. e.g. I could split my AI into a different brain entitiy that only communicates its decision to the "body" entity. im pretty sure in my case it would give me performance but at the cost of more abstraction
i was wondering too what would be the better way to do this. Im using Overlapsphere right now
is it because you need different sizes?
me or enzi? for me yes its about size. i havent compared to colliders performance wise
yeah, different size. no that sounds like performance madness, I know. Thinking a lot about how to tackle this 😄
are you relying on physics events?
yeah, best case I'd just use dots physics
I also have a way of just querying the entities close to the player. They get the "SLOD0" tag. then i can do a quick distance check to all of them without actually using physics.
if it doesn't work out I'll write some small spatial hashing system for this.
@solemn hollow this checks every entity against each other?
every entity on screen basically. and ofc you can filter for specific entities too then
There was a forum post where performance was profiled between actually using physics queries or just distance checking
I heard good things about unitys BVH tree so I thought why not
and only after a really huge number physics actually won i think
huh interesting
for threat overlap spheres make more sense to me than colliders
yep tertle, I think I'll do that instead. Also looking into just distance checking.
if you're goal is 250k i don't think distance checking them all will work that well 😄
yeah, that will be a bit too many
but yeah i found you can do alternatives for nearest neighbour stuff than unity physics
can you elaborate?
well i think i've discussed my hash map solution previously
for my nearest neighbour calcs for my orca system
ah right, ok 🙂
unity used hashmaps as well similarly for their original nordeus demo
just 1 thing to be careful of i reckon is that you might be able to create a faster simulation/lookup code for a specific case, and you might be able to do this for half a dozen cases
so individually they might be a lot faster but they could end up being a lot slower if you have a bunch of individual cases
compared to using a slightly slower alternative that only needs to be built once
like your physics world is probably being built every fixed update regardless, any new simulation you build per frame is in addition to that
right, that's the thing why I was thinking about triggers in the first place. Have it all in one place and not several others in addition that are overall slower
physics collider for enemies and players are here to stay anyway. at least, I think they will. 😄
so in 0.50?
dont you need entities for this test
just make a tiny project with updated collections
your code wasn't using entities as far as i can tell
God I feel so discouraged from working on my current project because its on unity 2021 and basically everything needs the ECS system to work.
thanks for that - was what i expected from my quick google.
ngl tho
result shader is literally just
example shader for instancing from manual page
xD
is it possible to make color out of index in shader?
so instead of Vector4 array
you assign just int array
it's hashing
even if you could, you still need to know the colour in c# to check the entity
what's the benefit though?
since currently you don't convert back to int
oh i guess you're only doing it once - that makes sense
less CPU->GPU bandwitdh, less data to store or compute
also will ease the pain of all that
color conversion nonsense
since you will be free to do conversion in normal (non-bursted) C#
I just can't really think of what are options in HLSL
can't you use same hash function in HLSL and C#?
hash function?
it's about converting integer to 4 bytes/floats
key point is able to reproduce Color -> integer conversion
your only options for arrays on property block are setfloatarray, setvectorarray, setmatrixarray
so im not sure how we'd get the integers in
you could union the int to a float to keep precision, i dont know enough about shaders to convert that back though
SetFloatArray works fine
I used to do it
you simply treat float as int
and then convert on gpu
in the end you get the color
so you simply just reverse whatever algorithm is used in shader
you can't cast it though
hence i suggested union
not enough precision
wdym?
nothing stops from simply using float tho
you'll probably need float in the end for algorythm, allthough not sure about it
but tbh, I still don't get why what you mean by precision drop
can always use uint
32 bit
ok (ignoring negatives) integers can represent every integer value accurately from 0 to 2.1billion
float can only do 0 to 16mill
you convert 200,000,000 to float and 200,000,001 to float
you get the exact same value
oh
anything above 16mill will have multiple integers being represented by the same float value
maybe this is not an issue
you aren't expecting integer indexes to go that high
but i've seen indexes in the millions before
(you know, because i created 10mill+ entities =D)
I have not much idea what you're talking about 🙂 just one info - gpus and shaders are not built for ints. internally they convert to float, so stay with float as much as possible in a shader
he wants to pass an array of integers and covert them to color on the gpu
instead of doing it on the cpu beforehand and passing an array of vector4
the problem is the range of integer values, while in most cases would not happen, could realistically in some cases exceed the integer accuracy of floats
from what I see around
yes
accuracy*
now i get it
welp
can always send Vector4 xD
which will be some kind of sum
of id
you avoid doing conversion on CPU
it's really not that slow in a multi-threaded bursted job though
it's still slower than doing it on fully paralleled GPU
also
shipping vector
is niche case
i always find this argument a bit weird
most modern games are gpu not cpu bound
especially when it comes to threads
most games have ample spare cpu cores to do calculations on
but are often maxing their gpu
so while it's faster on a gpu
why not use the free resources instead
do you have 100% cpu thread utilization though?
or are you main thread blocked
this is purely worker thread cost
well, rn I never really profiled anything I do
but it's just usually the kind of games I work with
RImworld is hugely bound to main thread perfomance
so when I did mods, I would always consider doing compute shader for large computations
meanwhile gpu can be intel hd graphics
xD
rimworld is not using burst AFAIK 🙂
yeah main thread
the huge advantage of jobs is it's opening up other threads to developers safely
anyway just a random thought
i just randomly hear, why use jobs/burst when you can use the gpu
and it often annoys me ^_^
haha same 😄
RW not using anything xD
Literally all written on it's own component system (not even ECS)
why use CPU at all? GPU has 512+ cores!
anyway, I still don't know what this is about? the entity picker system?
yeah
just wanted to move id to color conversion to shader
{
Vector4 c = IndexToColor(entities[index].Index);
colors.AddNoResize(c);
}``` this part?
I'm trying to think what difference it makes in the end. You would still iterate and write the same amount of data, would you not? the bit shift to color 32 is basically free, just some ticks, minus the write operation. in the end you'd have the same array because you need to upload it to the gpu anyway
I will not compute and store colors on cpu side
I will only convert read color to id
Way less code clutter
yeah you'd only need to calculate 1 (reverse) color on cpu vs 1 color for every entity
if you want to optimize: var colors = new UnsafeList<Vector4>(batchInChunk.Count, Allocator.Persistent); var transforms = new UnsafeList<Matrix4x4>(batchInChunk.Count, Allocator.Persistent); is a good start.
allocation could be moved outside the job
for a large amount of render meshes this will take the longest time in the job
That's why I'll just get rid of it altogether xD
are you using that in game or is this just an editor thing?
i disagree with this (which is why i did it this way to begin with)
the cost and pain of figuring out and ensuring each chunks capacity on main thread is not worth it
why not use entityIndex from IJobChunk ?
what do you mean?
i mean, I get why you've written it that way. it was not meant to run every frame
even if it was run every frame i'd probably do it this way
lets say you have 1000 chunks
are you suggesting on main thread you iterate every chunk, get its entity count, and ensure an array exists in the hashmap of that size?
get the count from the query, set the capacity, use firstEntityIndex + i to find the index in the array
wouldn't even need a list
maybe I'm missing something 🙂
no i think what you're saying makes sense
you can store start index/length in the hashmap
and subarray it
to pass to the shader
you have thought this further now than me, hehe.
the rest of the job will be super fast.
well they reason they are split is they need to be passed per chunk to the renderer
you can't pass the whole thing
ahhh, that's what I was missing