mkrebser / GPUInstance

Instancing & Animation library for Unity3D
Other
228 stars 44 forks source link

Help with positioning #7

Closed MRfantastic3DGamer closed 1 year ago

MRfantastic3DGamer commented 1 year ago

Hi, I want to use it as a method of introducing animations in dots as the official animation package is still not ready. so i want to place the instances myself in code. but setting position gives an error in as that is only available for billboards. is there a way to set position of instances in code.

mkrebser commented 1 year ago

You can set the position using the .position field on the InstanceData. If you want the entity to automatically move (ie, velocity, following paths, look-at-camera) then you can also use the Path class

There are around 10 different example scripts. You should look at them, eg moving crowd demo: https://github.com/mkrebser/GPUInstance/blob/master/Assets/Demos/crowddemo/crowddemo.cs

MRfantastic3DGamer commented 1 year ago

I looked into the demos but they all either have static position for instances or using path. there is no example of setting position of instances directly.

this is the Monobehaviour code

using System.Collections;
using System.Collections.Generic;
using GPUInstance;
using Unity.Mathematics;
using UnityEngine;
using Random = UnityEngine.Random;

public class MarchPeople : MonoBehaviour
{
    public Camera FrustumCullingCamera;
    public GPUSkinnedMeshComponent character;
    public double GlobalTimeSpeed = 1.0;

    private int2 grid = new int2(100, 100);
    private MeshInstancer m;
    private SkinnedMesh[] instances = new SkinnedMesh[10000];

    void Start()
    {
        // Initialize character mesh list
        int hierarchy_depth, skeleton_bone_count;
        List<GPUSkinnedMeshComponent> characters = new List<GPUSkinnedMeshComponent>();
        characters.Add(character);
        var controllers = GPUSkinnedMeshComponent.PrepareControllers(characters, out hierarchy_depth, out skeleton_bone_count);

        // Initialize GPU Instancer
        this.m = new MeshInstancer();
        this.m.Initialize(max_parent_depth: hierarchy_depth + 2, num_skeleton_bones: skeleton_bone_count, pathCount: 2);

        // Add all animations to GPU buffer
        this.m.SetAllAnimations(controllers);

        // Add all character mesh types to GPU Instancer
        this.m.AddGPUSkinnedMeshType(character);

        // Do stuff
        for (int i = 0; i < 10000; i++)
        {
            var mesh = character;
            var anim = mesh.anim.namedAnimations["walk"];
            instances[i] = new SkinnedMesh(mesh, this.m);
            instances[i].mesh.position = new Vector3(x: i / 100, 0, i % 100);
            instances[i].SetRadius(1.75f); // set large enough radius so model doesnt get culled to early
            instances[i].Initialize();

            instances[i].SetAnimation(anim, speed: 1.4f, start_time: Random.Range(0.0f, 1.0f)); // set animation

            instances[i].UpdateAll();
        }
    }

    void Update()
    {
        Ticks.GlobalTimeSpeed = this.GlobalTimeSpeed;
        this.m.FrustumCamera = this.FrustumCullingCamera;
        {
            var skinnedMesh = instances[0];
            Debug.Log(skinnedMesh.mesh.position);
            var pos = new Vector3(skinnedMesh.mesh.position.x, 0,
                skinnedMesh.mesh.position.z + Time.deltaTime);
            instances[0].mesh.position = pos;
            // log the supposed position of first instance
            Debug.Log(instances[0].mesh.position);
            instances[0].UpdateAll();
        }
        for (var i = 1; i < instances.Length; i++)
        {
            var skinnedMesh = instances[i];
            var pos = new Vector3(skinnedMesh.mesh.position.x, 0,
                skinnedMesh.mesh.position.z + Time.deltaTime);
            skinnedMesh.mesh.position = pos;
            instances[i] = skinnedMesh;
            instances[i].UpdateAll();
        }

        this.m.Update(Time.deltaTime);
    }
}

but the instances are stuck in the same place

mkrebser commented 1 year ago

When you manually modify an instance, you will need to tell the GPU what has been modified.

ie,

instance.DirtyFlags = DirtyFlag.Position | DirtyFlag.Rotation | DirtyFlag.Scale;

will tell the compute program to update the position, rotation, scale of an instance.

There are 'DIrtyFlags' for every property!

mkrebser commented 1 year ago

That being said, if you are just setting a velocity, I would recommend using a path! They can simulate constant motion! And this library will allow you to automatically calculate the full TRS transform of the instance at any time if you need it!

mkrebser commented 1 year ago

Also, the instancemeshdemo.cs has an example of the position being changed every frame! It parents all of the cube instances to a single instance (which allows for manual adjustment of its transform) which allows you to transform the entire scene in real-time!

MRfantastic3DGamer commented 1 year ago

It worked thanks a lot for your help.

Updating position every frame reduced the performance from 60fps to about 35fps for my example with 10k instances but it is still way better than all the other options i have explored, and i am pretty sure unity's official DOTS animation system (whenever it comes) is not going to be this performant.

That being said, if you are just setting a velocity, I would recommend using a path! They can simulate constant motion! And this library will allow you to automatically calculate the full TRS transform of the instance at any time if you need it!

Yes, that would be great but setting up path for all the different AIs is going to be difficult as i also have to set up a conversion system to make it work with DOTS.

mkrebser commented 1 year ago

This library is thread safe, does it help if you set the positions in multiple threads?

Although, it will still have to push 10k transform updates to the GPU every frame which is a lot.

Another area that may be worth investigating is seeing if you can put your DOTS simulation at a slower fixed time step and then allowing instances to get interpolated to positions via paths. You could at least try this for entities that are far away! 10k entities doing physics and ai every frame is quite heavy!

Seems you figured out your issue, so I will close this!