Skip to main content
Participant
February 28, 2024
Question

How to get a 'UTexture2D*' from the output of a 'USubstanceGraphInstance*'?

  • February 28, 2024
  • 1 reply
  • 1130 views

Hello,

 

I am using the Substance Plugin with Unreal Engine 5.3.

 

I have a USubstanceGraphInstance* with some input parameters that I customize at runtime before rendering the graph instance. Since I only want to read the pixel data from the generated output textures, I don't need to save the textures to disk.

 

I have two questions:

  • How do I register a callback function, or is there another way to get notified when the async rendering of a graph instance has finished?

  • Once the rendering has finished, how can I access the generated output textures as a UTexture2D*?

 

Thanks!

This topic has been closed for replies.

1 reply

Adobe Employee
March 1, 2024

Hi Kontur,

 

You can access the textures using the USubstanceGraphInstance Pointer by the following codes below

 

for (const auto& output : USubstanceGraphInstancePointer->Instance->getOutputs())
{
	if (output->mUserData != 0)
	{
		UTexture2D* texture = Cast<UTexture2D>(reinterpret_cast<USubstanceOutputData*>(output->mUserData)->GetData());
		// Do something with the texture
	}
}

 

 Also, when the asynchronous rendering finishes for each texture, texture->PostEditChange() is called. Just listen to that event. That is the only event fired when the rendering is done from our own internal post render callback.

KonturAuthor
Participant
April 27, 2024

Thank you for your swift reply. I am just now getting around to following up.

 

Unfortunately, PostEditChange() is an editor-only function, and we need this to work in a shipping build.

 

To provide more context, the output textures are used as heightmaps for procedural terrain generation in a seed-based world. Currently, we extend the Substance plugin with a query manager that handles asynchronous render requests and calls back the game code when UpdateTexture() is eventually called in SubstanceCoreHelpers.cpp (which seems to occur in shipping builds too). However, this approach feels very hacky and fragile, so I wonder if there is an "official" or at least a better way of doing it.

 

Ideally, when a new level is generated in the game, we want to instantiate the Substance graph that represents the terrain type of the level (each terrain type is represented by a different Substance graph) and we want to asynchronously and simultaneously render the level's heightmap in multiple chunks. To do this, each Substance graph has X and Y input parameters, which are used in the graph to render the appropriate chunk of the global level heightmap. We would read the pixel data from the output textures and then discard them along with the graph instances. When a new level is needed, the cycle starts again.

 

However, we are generally unsure about the proper workflow for runtime generation, so any insights you could provide would be immensely helpful!

  • Instantiating graphs at runtime seems to work, but there is a noticeable hitch when USubstanceUtility::CreateGraphInstance() is called. Is this expected, or are there ways to mitigate this?
  • Can a single graph instance simultaneously render multiple sets of graph outputs all using different input parameters for the graph? It would be really convenient to use a single graph instance to asynchronously render all heightmap chunks at the same time.
  • If runtime graph instantiation is a bad idea, and/or a graph instance can only render one set of inputs/outputs at the same time, what are our options? Having to create a graph instance for each chunk of each terrain graph type (there are hundreds) in the editor would be really suboptimal, and also wasteful, as we would have to ship the game with thousands of extra offline textures sitting around (graphs instantiated in the editor create a default output texture which they update on each render), when in practice, only one graph type and its seed-based outputs would be relevant at any given time, and only until we read the pixel data.

 

Thank you!

Adobe Employee
April 30, 2024

Hi @Kontur, we need to know a few more things about this particular workflow to provide guidance here. Could you let us know:

  1. How many graphs are you working with?
  2. What is the average output size per graph?
  3. How many graphs do you need to create at runtime?

 

Best,
Aldo