Creating New Material Nodes in UE4

1649 篇文章 12 订阅
1623 篇文章 23 订阅

Today I worked out how to make a new node in the material editor of the Unreal 4 Engine. This is a quick introduction on how to do it, I’ll hopefully have more detailed tutorial once I work out more details on how the system works.

As part of my work to get the rendering system I want working in the Unreal engine I’ve been diving around in the renderer, shader and material code of the engine. Today I managed to make a new node appear in the material editor! I haven’t tested this out fully yet but I thought I’d detail what I did in case anyone else is trying to do the same. You’ll need to grab the source off github if you haven’t already to follow though.

Material Compilation

Material nodes in the editor map more or less directly to HLSL functions that are stored in various files of the Shaders sub directory. When a material is compiled it’s turned into HLSL code using the ‘MaterialTemplate.usf’ shader file. *.usf is just an Unreal extension for HLSL shaders, the unreal documentation on shaders is pretty lacking so there may be some differences but I haven’t found any yet. When you apply your changes to a material the FHLSLMaterialTranslator class creates code to fill in functions in this file, you can view this code by going Window->HLSL Code.

HLSL Window

 

Creating a New Node

First open up the Engine\Source\Runtime\Engine\Public\MaterialCompiler.h file, this contains functions for a lot of the basic nodes used in the material editor. If you go back to the Shaders folder and open ‘Common.usf’ you’ll see a lot of these functions map to HLSL functions in this file. The FHLSLMaterialTranslator class is actually a subclass of the MaterialCompiler. As far as I can tell translator is actually a better term since this class really generates code not compiles it.

The other place you’ll need to look is ‘Engine\Source\Runtime\Engine\Classes\Materials\’, in here you’ll see a bunch of files called MaterialExpression*.h. These each contain a UCLASS for the actual nodes that appear in the editor. The implementations are all in \Engine\Source\Runtime\Engine\Private\Materials\MaterialExpressions.cpp.

To make a new node I did the following:

  • Created a new HLSL function in Common.usf.
  • Created a corresponding function in MaterialCompiler.h in both the virtual base class as well as the proxy class below it.
  • Created an implementation for the new function in Engine\Source\Runtime\Engine\Private\Materials\HLSLMaterialTranslator.h.
  • Created a new MaterialExpression*.h file in the materials folder and filled in it’s implementation in MaterialExpressions.cpp.

And that’s all there is to it! I’m not including any code as an example since it all involves modifying engine code. But if you look in all of the files I mentioned you should be able to see the pattern. You can see the result below:

Test node

Why Bother?

That all probably seems like a lot of work just to get a new node. You can already do this by creating a material function so why even bother? Well some code is much simpler written in actual code than a material. For example here’s a sobel operator in a material:

Sobel

In actual code that’s only about 10 – 15  lines. The actual code is much easier to reason about, when doing so much wiring of nodes it’s hard to keep track of what’s what and easy to make a mistake. I’d like to be able to integrate HLSL code into materials more easily. There is a custom node function in which you can write HLSL code there’s no easy way to use it in multiple materials unless you wrap it in a material function.

The disadvantage of doing it this way is that you have to modify the engine, recompile it (only a couple modules need to compile so it’s actually pretty quick) and then wait for all the shaders to recompile (this is the slow part). It would be hard to have quick iteration using this system. This may also interfere with the optimisation that the material compiler performs but I haven’t done any profiling yet.

What Next?

I only created a basic test node today but I want to experiment with making more complex input and output nodes. In the long run I want to be able to write to a custom GBuffer for use in the post processing stage of the rendering.

I mentioned that iteration is pretty slow with this. If you modify Common.usf all shaders that use it need to re-compile, I’m going to experiment with seeing if I can place custom functions in another file to prevent this.

I’d also like to try and make it more modular. Having to edit so many engine files each time is kinda inconvenient. Since material expressions are a UCLASS is should be possible to make the expression class in a plugin or game module. I’m hoping I can put a base function in the compiler/translator that will call out to classes in other modules for compilation. It’s probably not possible to completely isolate the changes to a plugin but it can probably be minimised.

Interconnected multilayer networks are complex systems that consist of multiple layers of interconnected networks. These networks can represent various social, technological, and biological systems, and their analysis is essential for understanding the dynamics of these systems. Ranking the nodes in interconnected multilayer networks can reveal the most important nodes, which play a crucial role in the functioning of the system. The ranking of nodes in interconnected multilayer networks is a challenging problem because the nodes' importance in one layer may not necessarily correspond to their importance in another layer. Therefore, a comprehensive ranking method should consider the nodes' importance across all layers of the network. Recent research has proposed several ranking methods for interconnected multilayer networks. One of the most promising approaches is the multilayer PageRank algorithm, which extends the classic PageRank algorithm to multilayer networks. This algorithm considers the importance of nodes in all layers of the network and assigns a score to each node based on its influence on the entire system. The ranking of nodes in interconnected multilayer networks has various applications, such as identifying critical nodes in transportation networks, predicting the spread of diseases in social networks, and detecting influential users in online social networks. Furthermore, the ranking of nodes can reveal versatile nodes that play a crucial role in multiple layers of the network, indicating their importance in maintaining the system's functionality. In conclusion, ranking nodes in interconnected multilayer networks is a crucial task that can reveal the most important and versatile nodes in the system. This information can be used to optimize the network's performance, identify critical nodes, and predict the system's behavior under different conditions.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值