# Vector Math? Coding?! HLSL! (Cubemap Blur)

I’m working on a material where I need to blur a cube map in unreal. The spiral blur function only provides U and V peturbation. I thought I could just make it vec3 and call it a day…seems I was wrong.

I’ve also had thoughts about convoluting to a polar map and then back again…but i don’t see those functions handy yet. Another idea was to neutralize Z and just append a 0.

Ouch on formatting!

Here’s the original code:

float3 CurColor;
float2 NewUV = UV; [float3]
int i;
float StepSize = Distance / (int) DistanceSteps;
float CurDistance;
float3 CurOffset;
float SubOffset = 0;
float TwoPi = 6.283185;
float accumdist=0;

if (DistanceSteps < 1)

{
return Texture2DSample(Tex,TexSampler,UV); [Not sure how texcube lookup works or sampler name.]
}
else
{
while ( i < (int) DistanceSteps)
{
CurDistance += StepSize;
for (int j = 0; j < (int) RadialSteps; j++)
{
SubOffset +=1;
[CurOffset.z = sin(TwoPi*(SubOffset / RadialSteps));] This is the one I know has no appropriate parallel.
NewUV.x = UV.x + CurOffset.x * CurDistance;
NewUV.y = UV.y + CurOffset.y * CurDistance;
[NewUV.z = UV.z + CurOffset.y * CurDistance;]
float distpow = pow(CurDistance, KernelPower);
CurColor += Texture2DSample(Tex,TexSampler,NewUV)*distpow;
accumdist += distpow;
}
i++;
}
CurColor = CurColor;
CurColor /=accumdist;
return CurColor;
}

1 Like

Have you tried Sampling lower mipmaps? You could use SampleLevel() instead of Sample and specify the mip you want by an exposed variable. (Sampling lower mips on pupose would give you a cheap alternative to a blur… Its not perfect but it works, and its cheaper than most options.

3 Likes

I would highly recommend @Mederic’s suggestion first. Using precomputed mips will always be faster than using many samples to create a blur. That said, the quality level for what you are doing may not be enough using just mips.

So `texCUBE(s, t)` does take a 3d vector for the lookup. Although I personally prefer to use the `MyTextureCube.Sample(float3)` way to write it… Though there may be reasons why one way is better than the other that I don’t know about.

Spiral is made for 2d coordinates. Since the texture lookup into a cube map is normalized you can, if you want, do things in polar coordinates then convert it back to Cartesian and it will probably work.

Although you should be careful to minimize the amount of times you transform it from one to the other as you can easily bloat this type of loop, making it very expensive.

I’ve always relied on mipmapping for this so I don’t know the best equation for a blurred texcube. Gaussian may be better…

One thing I have done is used a noise based low sample blur on the already mipped version. .Sample() takes an optional mip level clamp. Check the msdn documentation for more. You can also use texCUBEbias and put the mip bias in the .w of the location.

Also since we are talking about unreal specifically, an important question is whether you are writing this stuff in MaterialTemplate.usf or are trying to do this in a custom node, or are just trying to convert it in nodes. All of these are viable, but they change the methodology.

To do it best you should probably make a new node in c++ and write the code in MaterialTemplate.usf. Using custom nodes with texture samplers is doable, but super hacky. If you are interested I can share that technique too… But I hate it. If not you can always do it in nodes, you just can’t do loops.

Also you can format your code by indenting it with 4 spaces.

``````Example(of formatting)
{
Return awesome;
}
``````

Or by using ` for single lines.

`test of formatting for single line stuff`

2 Likes

As an aside, I think it may be better to use different topics for different questions. Makes it easier to search for later?

3 Likes

For some reason adding spaces didn’t work. I haven’t done html since 2002.

Also, This is for a semi-realtime situation. So a little more expense is okay.
I’m thinking that using either sine or cosine for z is just going to give me an artifact that leans in a particular direction. Fortunately the surfaces doing the reflecting are fairly complex.

If anyone is wondering why on earth I would cobble together my own reflection in unreal instead of using either the spherecaps or planar reflectors, it’s because we’re doing Spherical renders and anything that uses a screenspace buffer is garbled or at least has nasty artifacts.

Each line needs to have the four spaces. I just do everything in notepad++ and then make sure I use the edit>blank operations>convert tab to space.

So again, i would highly recommend if possible just doing the blur with either lower mips or just blurring it offline first. Blurring cubemaps correctly is very difficult actually (I did some more research) and converting to Spherical Coordinates and doing the pertubation there isn’t easy either. With that in mind I am going to produce a little example which may work for you and upload it here. It will be hacky, but it is what it is.

But seriouslythough, if possible do the blur offline in a utility.

1 Like

The cube map is dynamic. We’re rendering a “real time” cinematic as a 360 spherecap.
So our workflow is to preview everything in real time. And then render it for the capture.
Because there are so many artifacts in most reflection schemes, I’m replacing reflections with a cube map captured from the camera location. So it’s updated every frame during the capture.

Mips does look like it will work. Maybe not quite as blurry as I’d like, but good enough.

Ah I see. That makes sense. Well I have a zip for you with a texture cube, although it won’t let you do it with a dynamically set one in an instance. I have a hacky way to make that work that if you really need I can show.

www.ryandowlingsoka.com/share/rtvfx/SpiralBlur-TextureCube.zip

The code is:

``````float TwoPi = 6.283185;

//So pseudo code modifications. This is the principle, if not the exact code.
//Take the Reflection vector, or the CameraVector, whichever is more appropriate for your code.
//Convert it into to Spherical Coordinates.
//Z is unimportant once it is in Spherical Coordinates the radius is unimportant. Infact because you know
//the camera vectors or the reflection vectors are normalized you know the the radius is 1, so you can save some caluclations there.

//The conversion from normalized cartesian vector to spherical is found here: https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions
//Input CameraVector as float3 (or float4, doesn't matter.)
//float radius = 1; //Unneeded because we know it will be 1. If you want you can use it.

float theta = atan2( CameraVector.y, CameraVector.x );
float phi = acos( CameraVector.z );
//Then almost everything is the same.

float3 CurColor;
float2 UV = float2( theta, phi ); //So now we are perturbing the spherical coordinates (excluding radius).
float2 NewUV = UV; //So now we are perturbing the spherical coordinates (excluding radius).
float3 NewCameraVector = 0; //We will use this to store the resultant cameravector for each sample.

int i;
float StepSize = Distance / (int)DistanceSteps;
float CurDistance;
float2 CurOffset;
float SubOffset = 0;

float accumdist = 0;

if (DistanceSteps < 1)
{
return ProcessMaterialColorTextureLookup(TextureCubeSample(Tex, TexSampler, CameraVector)); //Just sample the texCUBE with the camera vector.
}
else
{
while (i < (int)DistanceSteps)
{
CurDistance += StepSize;
for (int j = 0; j < (int)RadialSteps; j++)
{
SubOffset += 1;
CurOffset.x = cos(TwoPi * (SubOffset / RadialSteps));
CurOffset.y = sin(TwoPi * (SubOffset / RadialSteps));

NewUV.x = UV.x + CurOffset.x * CurDistance;
NewUV.y = UV.y + CurOffset.y * CurDistance;

float distpow = pow(CurDistance, KernelPower);

//Convert back before sampling.
//The conversion can be found here: https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions
//Like before since we know the radius is always 1, no need to include it.
//NewUV.x stores the offsetted theta, and NewUV.y stores the offsetted phi.
NewCameraVector = float3( cos(NewUV.x) * sin(NewUV.y), sin(NewUV.x) * sin(NewUV.y), cos(NewUV.y) );

CurColor += ProcessMaterialColorTextureLookup(TextureCubeSample(Tex, TexSampler, NewCameraVector)) * distpow;
accumdist += distpow;
}
i++;
}
CurColor = CurColor;
CurColor /= accumdist;
return CurColor;
}
``````

The spiral blur definitely does cause pinching near the poles. There may be ways to fix this. Or you may find that not even converting is actually better, and just adding a random vector offset before normalizing.

1 Like

Wow, thanks dude! That’s so much more than I was expecting. I was mostly hoping for some syntax help.
I owe ya!

1 Like

I am unable to open these in 4.13

Copypasta nodes?

Ah, engine version, we are on a different engine number cause of custom custom stuff which will make the assets not show up. If I were a smarter person I would’ve found those bytes and stripped them out so it wouldn’t matter. Yeah that makes sense.

This is the copypasta for the SpiralBlur-TextureCube:

`````` Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_25"
Begin Object Class=MaterialExpressionCustom Name="MaterialExpressionCustom_3"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7173"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7174"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7175"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7176"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7177"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7178"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7179"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7180"
End Object
Begin Object Name="MaterialExpressionCustom_3"
Inputs(0)=(InputName="Tex",Input=(Expression=MaterialExpressionFunctionInput'MaterialGraphNode_26.MaterialExpressionFunctionInput_0'))
Inputs(1)=(InputName="CameraVector",Input=(Expression=MaterialExpressionFunctionInput'MaterialGraphNode_28.MaterialExpressionFunctionInput_1'))
Inputs(2)=(InputName="Distance",Input=(Expression=MaterialExpressionFunctionInput'MaterialGraphNode_30.MaterialExpressionFunctionInput_3'))
Inputs(3)=(InputName="DistanceSteps",Input=(Expression=MaterialExpressionFunctionInput'MaterialGraphNode_29.MaterialExpressionFunctionInput_2'))
Inputs(6)=(InputName="KernelPower",Input=(Expression=MaterialExpressionFunctionInput'MaterialGraphNode_34.MaterialExpressionFunctionInput_6'))
MaterialExpressionEditorX=-128
MaterialExpressionEditorY=240
MaterialExpressionGuid=94228BE74CEC205A083E1082B0E2A6C5
Material=Material'/Engine/Transient.Material_3'
End Object
Begin Object Name="EdGraphPin_7173"
PinName="Tex"
PinType=(PinCategory="required")
End Object
Begin Object Name="EdGraphPin_7174"
PinName="CameraVector"
PinType=(PinCategory="required")
End Object
Begin Object Name="EdGraphPin_7175"
PinName="Distance"
PinType=(PinCategory="required")
End Object
Begin Object Name="EdGraphPin_7176"
PinName="DistanceSteps"
PinType=(PinCategory="required")
End Object
Begin Object Name="EdGraphPin_7177"
PinType=(PinCategory="required")
End Object
Begin Object Name="EdGraphPin_7178"
PinType=(PinCategory="required")
End Object
Begin Object Name="EdGraphPin_7179"
PinName="KernelPower"
PinType=(PinCategory="required")
End Object
Begin Object Name="EdGraphPin_7180"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionCustom'MaterialExpressionCustom_3'
Pins(0)=EdGraphPin'EdGraphPin_7173'
Pins(1)=EdGraphPin'EdGraphPin_7174'
Pins(2)=EdGraphPin'EdGraphPin_7175'
Pins(3)=EdGraphPin'EdGraphPin_7176'
Pins(4)=EdGraphPin'EdGraphPin_7177'
Pins(5)=EdGraphPin'EdGraphPin_7178'
Pins(6)=EdGraphPin'EdGraphPin_7179'
Pins(7)=EdGraphPin'EdGraphPin_7180'
NodePosX=-128
NodePosY=240
NodeGuid=D2BE346A410278E756F691966724F978
End Object
Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_26"
Begin Object Class=MaterialExpressionFunctionInput Name="MaterialExpressionFunctionInput_0"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7138"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7139"
End Object
Begin Object Name="MaterialExpressionFunctionInput_0"
Preview=(Expression=MaterialExpressionTextureObject'MaterialGraphNode_20.MaterialExpressionTextureObject_5')
InputName="TextureObject"
Description="Supply the Texture to Blur as a TextureObject node"
Id=4BF03A9043B9EDCA764E998BB287F5B3
InputType=FunctionInput_TextureCube
MaterialExpressionEditorX=-576
MaterialExpressionEditorY=144
MaterialExpressionGuid=10A9F7E64637D29E818AB3AC5F0A8FA5
Material=Material'/Engine/Transient.Material_3'
bCollapsed=True
End Object
Begin Object Name="EdGraphPin_7138"
PinName="Preview"
PinType=(PinCategory="optional")
End Object
Begin Object Name="EdGraphPin_7139"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionFunctionInput'MaterialExpressionFunctionInput_0'
Pins(0)=EdGraphPin'EdGraphPin_7138'
Pins(1)=EdGraphPin'EdGraphPin_7139'
NodePosX=-576
NodePosY=144
NodeGuid=035B776F4EC6D3334A4C99BB9F1F2BE4
End Object
Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_28"
Begin Object Class=MaterialExpressionFunctionInput Name="MaterialExpressionFunctionInput_1"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7141"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7142"
End Object
Begin Object Name="MaterialExpressionFunctionInput_1"
Preview=(Expression=MaterialExpressionCameraVectorWS'MaterialGraphNode_36.MaterialExpressionCameraVectorWS_7')
InputName="CameraVector"
Description="UVs for blurring"
Id=7A92718048B8283B141C7E995006F0F9
bUsePreviewValueAsDefault=True
SortPriority=1
MaterialExpressionEditorX=-496
MaterialExpressionEditorY=272
MaterialExpressionGuid=10A9F7E64637D29E818AB3AC5F0A8FA5
Material=Material'/Engine/Transient.Material_3'
bCollapsed=True
End Object
Begin Object Name="EdGraphPin_7141"
PinName="Preview"
PinType=(PinCategory="optional")
End Object
Begin Object Name="EdGraphPin_7142"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionFunctionInput'MaterialExpressionFunctionInput_1'
Pins(0)=EdGraphPin'EdGraphPin_7141'
Pins(1)=EdGraphPin'EdGraphPin_7142'
NodePosX=-496
NodePosY=272
NodeGuid=75C9417E4195819D18487688DC3755A7
End Object
Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_29"
Begin Object Class=MaterialExpressionFunctionInput Name="MaterialExpressionFunctionInput_2"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7143"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7144"
End Object
Begin Object Name="MaterialExpressionFunctionInput_2"
InputName="Distance Steps"
Description="Number of steps along distance"
Id=999268474CE8F923FC5CA297555C451B
InputType=FunctionInput_Scalar
PreviewValue=(X=16.000000,Y=0.000000,Z=0.000000,W=1.000000)
bUsePreviewValueAsDefault=True
SortPriority=4
MaterialExpressionEditorX=-512
MaterialExpressionEditorY=432
MaterialExpressionGuid=10A9F7E64637D29E818AB3AC5F0A8FA5
Material=Material'/Engine/Transient.Material_3'
bCollapsed=True
End Object
Begin Object Name="EdGraphPin_7143"
PinName="Preview"
PinType=(PinCategory="optional")
End Object
Begin Object Name="EdGraphPin_7144"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionFunctionInput'MaterialExpressionFunctionInput_2'
Pins(0)=EdGraphPin'EdGraphPin_7143'
Pins(1)=EdGraphPin'EdGraphPin_7144'
NodePosX=-512
NodePosY=432
NodeGuid=BE348AB94684D317D76C72A3C4225A16
End Object
Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_30"
Begin Object Class=MaterialExpressionFunctionInput Name="MaterialExpressionFunctionInput_3"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7145"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7146"
End Object
Begin Object Name="MaterialExpressionFunctionInput_3"
InputName="Distance"
Description="Total Distance of Blur in UV Space"
Id=7CC6063741354B194A27C5BFBF5AEFC6
InputType=FunctionInput_Scalar
PreviewValue=(X=0.050000,Y=0.000000,Z=0.000000,W=1.000000)
bUsePreviewValueAsDefault=True
SortPriority=3
MaterialExpressionEditorX=-528
MaterialExpressionEditorY=352
MaterialExpressionGuid=10A9F7E64637D29E818AB3AC5F0A8FA5
Material=Material'/Engine/Transient.Material_3'
bCollapsed=True
End Object
Begin Object Name="EdGraphPin_7145"
PinName="Preview"
PinType=(PinCategory="optional")
End Object
Begin Object Name="EdGraphPin_7146"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionFunctionInput'MaterialExpressionFunctionInput_3'
Pins(0)=EdGraphPin'EdGraphPin_7145'
Pins(1)=EdGraphPin'EdGraphPin_7146'
NodePosX=-528
NodePosY=352
End Object
Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_31"
Begin Object Class=MaterialExpressionFunctionInput Name="MaterialExpressionFunctionInput_4"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7147"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7148"
End Object
Begin Object Name="MaterialExpressionFunctionInput_4"
Description="Number of radial steps to perform"
Id=2D450737453F92D15333EDA2A8A9C9FB
InputType=FunctionInput_Scalar
PreviewValue=(X=8.000000,Y=0.000000,Z=0.000000,W=1.000000)
bUsePreviewValueAsDefault=True
SortPriority=5
MaterialExpressionEditorX=-512
MaterialExpressionEditorY=512
MaterialExpressionGuid=10A9F7E64637D29E818AB3AC5F0A8FA5
Material=Material'/Engine/Transient.Material_3'
bCollapsed=True
End Object
Begin Object Name="EdGraphPin_7147"
PinName="Preview"
PinType=(PinCategory="optional")
End Object
Begin Object Name="EdGraphPin_7148"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionFunctionInput'MaterialExpressionFunctionInput_4'
Pins(0)=EdGraphPin'EdGraphPin_7147'
Pins(1)=EdGraphPin'EdGraphPin_7148'
NodePosX=-512
NodePosY=512
NodeGuid=CAB0C3E64110715CB2068A8C7D08BF33
End Object
Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_33"
Begin Object Class=MaterialExpressionFunctionInput Name="MaterialExpressionFunctionInput_5"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7150"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7151"
End Object
Begin Object Name="MaterialExpressionFunctionInput_5"
Description="Number of radial steps to perform"
Id=E0C339BD412802ACF8D1CFA66E382F99
InputType=FunctionInput_Scalar
PreviewValue=(X=0.618000,Y=0.000000,Z=0.000000,W=1.000000)
bUsePreviewValueAsDefault=True
SortPriority=6
MaterialExpressionEditorX=-512
MaterialExpressionEditorY=592
MaterialExpressionGuid=10A9F7E64637D29E818AB3AC5F0A8FA5
Material=Material'/Engine/Transient.Material_3'
bCollapsed=True
End Object
Begin Object Name="EdGraphPin_7150"
PinName="Preview"
PinType=(PinCategory="optional")
End Object
Begin Object Name="EdGraphPin_7151"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionFunctionInput'MaterialExpressionFunctionInput_5'
Pins(0)=EdGraphPin'EdGraphPin_7150'
Pins(1)=EdGraphPin'EdGraphPin_7151'
NodePosX=-512
NodePosY=592
NodeGuid=E3C67254492CCE7E60C741B27BD3ABCF
End Object
Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_34"
Begin Object Class=MaterialExpressionFunctionInput Name="MaterialExpressionFunctionInput_6"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7152"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7153"
End Object
Begin Object Name="MaterialExpressionFunctionInput_6"
InputName="Kernel Power"
Description="Number of radial steps to perform"
Id=729AEDD6469F6A91D595A0B2471F510C
InputType=FunctionInput_Scalar
PreviewValue=(X=1.000000,Y=0.000000,Z=0.000000,W=1.000000)
bUsePreviewValueAsDefault=True
SortPriority=7
MaterialExpressionEditorX=-512
MaterialExpressionEditorY=720
MaterialExpressionGuid=10A9F7E64637D29E818AB3AC5F0A8FA5
Material=Material'/Engine/Transient.Material_3'
bCollapsed=True
End Object
Begin Object Name="EdGraphPin_7152"
PinName="Preview"
PinType=(PinCategory="optional")
End Object
Begin Object Name="EdGraphPin_7153"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionFunctionInput'MaterialExpressionFunctionInput_6'
Pins(0)=EdGraphPin'EdGraphPin_7152'
Pins(1)=EdGraphPin'EdGraphPin_7153'
NodePosX=-512
NodePosY=720
NodeGuid=70399450445EA1BA82EDA59755E5C329
End Object
Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_20"
Begin Object Class=MaterialExpressionTextureObject Name="MaterialExpressionTextureObject_5"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7154"
End Object
Begin Object Name="MaterialExpressionTextureObject_5"
Texture=TextureCube'/Engine/EngineResources/DefaultTextureCube.DefaultTextureCube'
MaterialExpressionEditorX=-816
MaterialExpressionEditorY=144
MaterialExpressionGuid=EC349EE74E50EDCB78A9F885113E7777
Material=Material'/Engine/Transient.Material_3'
End Object
Begin Object Name="EdGraphPin_7154"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionTextureObject'MaterialExpressionTextureObject_5'
Pins(0)=EdGraphPin'EdGraphPin_7154'
NodePosX=-816
NodePosY=144
NodeGuid=24CDE51744BA3F504A362DB64A06B0C9
End Object
Begin Object Class=MaterialGraphNode Name="MaterialGraphNode_36"
Begin Object Class=MaterialExpressionCameraVectorWS Name="MaterialExpressionCameraVectorWS_7"
End Object
Begin Object Class=EdGraphPin Name="EdGraphPin_7189"
End Object
Begin Object Name="MaterialExpressionCameraVectorWS_7"
MaterialExpressionEditorX=-752
MaterialExpressionEditorY=304
MaterialExpressionGuid=C8CDFED04C5AFB10B221B59807C2A892
Material=Material'/Engine/Transient.Material_3'
End Object
Begin Object Name="EdGraphPin_7189"
PinName="Output"
PinFriendlyName=" "
Direction=EGPD_Output
End Object
MaterialExpression=MaterialExpressionCameraVectorWS'MaterialExpressionCameraVectorWS_7'
Pins(0)=EdGraphPin'EdGraphPin_7189'
NodePosX=-752
NodePosY=304
NodeGuid=6BA921BC4171DFF6B47171AC3D6BA3BE
End Object
``````

This should go into a material function so it can be used in a material seperately.

2 Likes

I double heart this.