Hmmm, I’m sure it’s possible, but I’m not seeing much on it- it looks like updating the texture and then running a scan is how it would work, but that may also be expensive to run.
I do want to provide a methodology of thinking, just in case that it does work like how I said; if you do have to rescan the graph for every texture change, you can mitigate the performance hit by only scanning once every handful of seconds or so. Maybe every 5. But for the situations where the agents will move onto freshly changed paint and would need their penalties updated, you could have a temp object take the place where the paint is and set a pathfinding tag for a lower penalty on that object’s Unity tag. Then, every 5 seconds you can take all those newly added zones, apply them to a texture, use that texture in the Grid Graph Rule, remove all the temp spots, rescan and done!
On paper that would save a lot of performance, and I’d imagine would work well to keep the game functioning as if it were just a texture.
That idea said, I’ll tag @aron_granberg to see what he thinks would be best here, because I most likely have come up with a roundabout solution to something that already has a proper way of doing it. I’m good at doing that 
Hi
What you’d have to do is:
- Update the texture in whatever way you want
- Update the graph in the region you changed using
AstarPath.active.UpdateGraphs(bounding box...)
.
The RuleTexture class will automatically detect that the texture has changed using the Texture.imageContentsHash
property. As long as that changes, it will pick it up. Check that PAINTZ actually updates this property, otherwise you’ll have to do it yourself. Even just incrementing it by 1 every time you paint into the texture is fine.
This will be decently fast, but the rule will have to re-read the whole texture to get the new data. This may be expensive, depending on how large the texture is.
I think this should work for your use case, and be performant enough, but I don’t know exactly how expensive it would be.
Wow, thanks for this detailed answer. The AI is primary for small bots that have to cross the map. So they don’t have to be very precisely.
I’ve seen the texture rule is a pro feature. Is there a chance to test this for an amount of time?
The asset store doesn’t really have a way to do trials, I’m afraid.
But if you try it, and it turns out that it doesn’t suit your game, then I can arrange a refund for you.
This is exactly what I meant by me overengineering things that are probably supported better out of the box 
Yeah but who should support edge cases like this?
@aron_granberg Hi, we implemented a GridGraph now but would linke to split it in multiple Graphs to reduce the Texture size and reduce the cost to update the graph.
We put 3 graphs in a row, and allow the Ai to use all these 3 graps, but it will only walk above one of the graps and will not generate paths that expand above 2 or more graphs if necessary.
We thought about using a single big Graph and just update the changed area, but its hard to get the area out of the texture. So using multiple graphs with own textures seems to be the easy solution in the first attempt.
Until now we used the AstarPath.active.Scan(Graph) method and update only the graph where the texture changed.
Hi
You could use a custom grid graph rule to be able to apply the texture data wherever you want.
The RuleTexture class is only 180 lines of code, so it’s not too bad to duplicate and modify to do what you want.
I strongly recommend using a single large graph, instead of 3 smaller graphs, if you want the agent to be able to pathfind over the whole area.
The cost to update a grid graph doesn’t increase that much with its size. It scales with the size of the update.
@aron_granberg ok, i will try. But we don´t get AstarPath.active.UpdateGraphs(bounding box…) to work. The graph will only update using AstarPath.active.Scan(Graph), but this is too expensive. Does UpdateGraphs update the rules
This is the code to set the new texture if it changes:
graphs = AstarPath.active.data.graphs;
foreach (GridGraph graph in graphs) //we need 2 graphs one for each team.
{
if (graph.name.Contains(this.gameObject.name))
{
var rules = graph.rules.GetRules();
(rules[0] as RuleTexture).texture = tex;
//AstarPath.active.Scan(graph); //using scan will work as expected but is slow
}
}
AstarPath.active.UpdateGraphs(bounds);
Hi
Hmm. Right now it only uses the update count of the texture to check if it’s changed. Two different texture objects may have the same update count.
Do you think you could change RuleTexture → Hash property to this:
public override int Hash {
get {
var h = base.Hash ^ (texture != null ? (31 * texture.GetInstanceID()) ^ (int)texture.updateCount : 0);
#if UNITY_EDITOR
if (texture != null) h ^= (int)texture.imageContentsHash.GetHashCode();
#endif
return h;
}
}
and see if that solves it.
To be clear, you are assigning different texture objects each time, right?
No does not fix the problem.
We are not sure about the texture is a bit magic for us.
Here the complete code with getting the texture:
private void MapPaintTarget_SplatsUpdated()
{
if (mapPaintTarget.m_Splats.Count > 0 || AstarPath.active.isScanning) return;
rt = mapPaintTarget.splatTex;
var tex = new Texture2D(rt.width, rt.height, TextureFormat.RGBA32, false, false);
if (!rt.IsCreated())
{
Debug.LogError("RenderTexture ist nicht erstellt!");
return;
}
var original = RenderTexture.active;
RenderTexture.active = rt;
// Asynchrones GPU-Readback für Performance
AsyncGPUReadback.Request(rt, 0, request =>
{
if (request.hasError || tex == null) return;
tex.LoadRawTextureData(request.GetData<byte>());
tex.Apply();
RenderTexture.active = original;
if (tex?.imageContentsHash != currentHash)
{
currentHash = tex.imageContentsHash;
foreach (GridGraph graph in graphs)
{
if (graph.name.Contains(this.gameObject.name))
{
var rules = graph.rules.GetRules();
(rules[0] as RuleTexture).texture = tex;
//AstarPath.active.Scan(graph);
}
}
AstarPath.active.UpdateGraphs(bounds);
}
Object.Destroy(tex);
});
}
This method will be called after the texture is written by paintz.
You are destroying the texture before the graph update runs. Graph updates do not run immediately unless your call AstarPath.active.FlushGraphUpdates.
Ha yeah true, “will update as soon as possible” 
In case scan will run “immediately” I missed that.
Ok check it later.
Thanks a lot.
Ok fixed it thanks a lot.
Now i am thinking about when will be the best time to call Update and flush.
How will the api scale with calling Update multiple times with smaller bounds, instead of one big one?
Would it be better calling Update every time a player paints (changes the texture) with a small bound of the area where the texture changed. And Call flush in the fixed update?
Generally it’s more efficient with a single large bounds. Up to a limit, of course. Two small updates on the opposite side of the map are more efficient than a single huge update covering both of them.
Profile to see what works best for you.
@aron_granberg
Yeah the splitting into smaller bounds costs me days now. An I still have a problem. Some times the texture rule will not be updated fast enough. I found the Rebild() method and noticed that sometimes it will be called too late. Can I call rebuild by myself? Or is there a better way to trigger it?
What do you mean by too late?
Are you changing the texture, and then the rule is not rebuilt?
Or is it rebuilt, but with a time delay?
@aron_granberg it’s rebuild with an delay
That’s strange. There are no delays that should be going on at all.
The graph updates are applied after a delay, but if you use AstarPath.active.FlushGraphUpdates();
then they should be applied instantly.
Only the hash of the RuleTexture class affects if it is rebuilt or not. You can force the rule to become dirty by calling RuleTexture.SetDirty()
, if you need to.