Skip to content

Commit f7843c1

Browse files
committed
Merge branch 'master' of github.com:Phyronnaz/HLSLMaterial
2 parents c812527 + 51b14fd commit f7843c1

File tree

2 files changed

+81
-4
lines changed

2 files changed

+81
-4
lines changed

README.md

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,75 @@
1-
# HLSLMaterial
1+
# HLSL Material for Unreal Engine
2+
3+
Ever wanted to write complex material functions directly in HLSL? Now you can!
4+
5+
Unreal Engine 4.26, 4.27 and 5.0 are supported. 4.25 cannot be supported as custom nodes have a single output in that version.
6+
7+
Demo: https://twitter.com/phyronnaz/status/1452553917204733953
8+
9+
## Features
10+
* HLSL support: write all your functions in a single hlsl file and use any of them in regular materials
11+
* Team-friendly: regular material functions are generated, so your team members don't need the plugin to use them!
12+
* Live updates: material functions & opened material editors are refreshed when saving the hlsl file (Windows only)
13+
* Comment support: comments are parsed & pin tooltips are set accordingly
14+
15+
## Installing from source
16+
Download the repo as a zip, and extract it under your project Plugins folder so you have `YourProject/Plugins/HLSLMaterial/HLSLMaterial.uplugin`
17+
18+
## How to
19+
* Create a new `HLSL Material Function Library` (right click Content Browser -> Material & Textures). This asset will be the link between your hlsl file and all the generated material functions.
20+
* Set the `File` on it to point to your HLSL file
21+
* Add functions to the file
22+
* Material functions will be created when you save the HLSL file
23+
* You can also disable the automatic updates and manually right click the asset -> `Update from HLSL`
24+
25+
## Syntax
26+
* All return types must be `void` to ensure the pins are all properly named
27+
* To mark a parameter as an output, use `out`: eg, `out float3 MyOutput`
28+
* Comments must use the `//` syntax, `/*` is not supported
29+
* `@param` in comments will be parsed & put into the pin tooltips
30+
31+
```hlsl
32+
// Ray-sphere intersection
33+
// @param RayOrigin The origin of the ray
34+
// @param RayDirection The direction of the ray
35+
// @param SphereCenter The center of the sphere
36+
// @param SphereRadius The radius of the sphere
37+
// @param Distance The distance from the ray origin to the hit on the sphere
38+
void RaySphereIntersect(float3 RayOrigin, float3 RayDirection, float3 SphereCenter, float SphereRadius, out float Distance)
39+
{
40+
float a = dot(RayDirection, RayDirection);
41+
float3 SphereCenterToRayOrigin = RayOrigin - SphereCenter;
42+
float b = 2.0 * dot(RayDirection, SphereCenterToRayOrigin);
43+
float c = dot(SphereCenterToRayOrigin, SphereCenterToRayOrigin) - (SphereRadius * SphereRadius);
44+
float Discriminant = b * b - 4.0 * a* c;
45+
46+
if (Discriminant < 0.0)
47+
{
48+
Distance = -1.0;
49+
}
50+
else
51+
{
52+
Distance = (-b - sqrt(Discriminant)) / 2 * a;
53+
}
54+
}
55+
```
56+
57+
## How it works
58+
59+
The plugin manually parses the functions in the HLSL file. From there, it creates new material functions with a Custom node holding the function body.
60+
61+
The logic is pretty simple & straightforward, so it should be relatively robust.
62+
63+
## Project management
64+
### Moving functions
65+
Material functions are generated next to your library asset, under `YourFunctionLibraryAsset_Generated/`.
66+
Once they are generated, you should be able to move them anywhere - the library keeps a ref to them.
67+
68+
### Renaming functions
69+
If you rename a function in your HLSL file, you need to manually rename the corresponding material function in Unreal, ideally before saving the HLSL. Otherwise, a new one will be created with the new name.
70+
71+
### Deleting functions
72+
The plugin will never delete any asset. If you remove a function from the HLSL, it is up to you to remove it from Unreal.
73+
74+
### Source Control
75+
You don't need to check in the HLSL file or the library - simply checking in the generated functions should be enough. However, if your teammates are also using the plugin it might be best to check in everything.

Source/HLSLMaterialEditor/Private/HLSLMaterialFunctionLibraryEditor.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,17 @@ void FVoxelMaterialExpressionLibraryEditor::Generate(UHLSLMaterialFunctionLibrar
259259
}
260260
}
261261

262-
Library.MaterialFunctions.Remove(nullptr);
262+
Library.MaterialFunctions.RemoveAll([&](TSoftObjectPtr<UMaterialFunction> InFunction)
263+
{
264+
return !InFunction.IsValid();
265+
});
263266

264267
FMaterialUpdateContext UpdateContext;
265268
for (FFunction Function : Functions)
266269
{
267270
TSoftObjectPtr<UMaterialFunction>* MaterialFunctionPtr = Library.MaterialFunctions.FindByPredicate([&](TSoftObjectPtr<UMaterialFunction> InFunction)
268271
{
269-
return InFunction->GetFName() == *Function.Name;
272+
return ensure(InFunction) && InFunction->GetFName() == *Function.Name;
270273
});
271274
if (!MaterialFunctionPtr)
272275
{
@@ -288,7 +291,7 @@ void FVoxelMaterialExpressionLibraryEditor::Generate(UHLSLMaterialFunctionLibrar
288291

289292
TMap<FName, FGuid> FunctionInputGuids;
290293
TMap<FName, FGuid> FunctionOutputGuids;
291-
for (auto* Expression : MaterialFunction->FunctionExpressions)
294+
for (UMaterialExpression* Expression : MaterialFunction->FunctionExpressions)
292295
{
293296
if (UMaterialExpressionFunctionInput* FunctionInput = Cast<UMaterialExpressionFunctionInput>(Expression))
294297
{

0 commit comments

Comments
 (0)