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.x = cos(TwoPi*(SubOffset / RadialSteps));
CurOffset.y = sin(TwoPi*(SubOffset / RadialSteps));
[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;
}
SubOffset +=RadialOffset;
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. :slight_smile:

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;
        }
        SubOffset += RadialOffset;
        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. :smiley:
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"
      Code="    \r\n    float TwoPi = 6.283185;\r\n    \r\n    //So pseudo code modifications. This is the principle, if not the exact code.\r\n    //Take the Reflection vector, or the CameraVector, whichever is more appropriate for your code.\r\n    //Convert it into to Spherical Coordinates.\r\n    //Z is unimportant once it is in Spherical Coordinates the radius is unimportant. Infact because you know\r\n    //the camera vectors or the reflection vectors are normalized you know the the radius is 1, so you can save some caluclations there.\r\n    \r\n    //The conversion from normalized cartesian vector to spherical is found here: https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions\r\n    //Input CameraVector as float3 (or float4, doesn\'t matter.)\r\n    //float radius = 1; //Unneeded because we know it will be 1. If you want you can use it.\r\n\r\n    float theta = atan2( CameraVector.y, CameraVector.x );\r\n    float phi = acos( CameraVector.z );\r\n    //Then almost everything is the same.\r\n    \r\n    float3 CurColor;\r\n    float2 UV = float2( theta, phi ); //So now we are perturbing the spherical coordinates (excluding radius).\r\n    float2 NewUV = UV; //So now we are perturbing the spherical coordinates (excluding radius).\r\n    float3 NewCameraVector = 0; //We will use this to store the resultant cameravector for each sample.\r\n    \r\n    int i;\r\n    float StepSize = Distance / (int)DistanceSteps;\r\n    float CurDistance;\r\n    float2 CurOffset;\r\n    float SubOffset = 0;\r\n\r\n    float accumdist = 0;\r\n\r\n    if (DistanceSteps < 1)\r\n    {\r\n        return ProcessMaterialColorTextureLookup(TextureCubeSample(Tex, TexSampler, CameraVector)); //Just sample the texCUBE with the camera vector.\r\n    } \r\n    else\r\n    {\r\n        while (i < (int)DistanceSteps) \r\n        {\r\n            CurDistance += StepSize;\r\n            for (int j = 0; j < (int)RadialSteps; j++) \r\n            {\r\n                SubOffset += 1;\r\n                CurOffset.x = cos(TwoPi * (SubOffset / RadialSteps));\r\n                CurOffset.y = sin(TwoPi * (SubOffset / RadialSteps));\r\n                \r\n                NewUV.x = UV.x + CurOffset.x * CurDistance;\r\n                NewUV.y = UV.y + CurOffset.y * CurDistance;\r\n                \r\n                float distpow = pow(CurDistance, KernelPower);\r\n                \r\n                //Convert back before sampling.\r\n                //The conversion can be found here: https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions\r\n                //Like before since we know the radius is always 1, no need to include it.\r\n                //NewUV.x stores the offsetted theta, and NewUV.y stores the offsetted phi.\r\n                NewCameraVector = float3( cos(NewUV.x) * sin(NewUV.y), sin(NewUV.x) * sin(NewUV.y), cos(NewUV.y) );\r\n                \r\n                \r\n                CurColor += ProcessMaterialColorTextureLookup(TextureCubeSample(Tex, TexSampler, NewCameraVector)) * distpow;\r\n                accumdist += distpow;\r\n            }\r\n            SubOffset += RadialOffset;\r\n            i++;\r\n        }\r\n        CurColor = CurColor;\r\n        CurColor /= accumdist;\r\n        return CurColor;\r\n    }"
      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(4)=(InputName="RadialSteps",Input=(Expression=MaterialExpressionFunctionInput'MaterialGraphNode_31.MaterialExpressionFunctionInput_4'))
      Inputs(5)=(InputName="RadialOffset",Input=(Expression=MaterialExpressionFunctionInput'MaterialGraphNode_33.MaterialExpressionFunctionInput_5'))
      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")
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_26.EdGraphPin_7139'
   End Object
   Begin Object Name="EdGraphPin_7174"
      PinName="CameraVector"
      PinType=(PinCategory="required")
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_28.EdGraphPin_7142'
   End Object
   Begin Object Name="EdGraphPin_7175"
      PinName="Distance"
      PinType=(PinCategory="required")
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_30.EdGraphPin_7146'
   End Object
   Begin Object Name="EdGraphPin_7176"
      PinName="DistanceSteps"
      PinType=(PinCategory="required")
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_29.EdGraphPin_7144'
   End Object
   Begin Object Name="EdGraphPin_7177"
      PinName="RadialSteps"
      PinType=(PinCategory="required")
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_31.EdGraphPin_7148'
   End Object
   Begin Object Name="EdGraphPin_7178"
      PinName="RadialOffset"
      PinType=(PinCategory="required")
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_33.EdGraphPin_7151'
   End Object
   Begin Object Name="EdGraphPin_7179"
      PinName="KernelPower"
      PinType=(PinCategory="required")
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_34.EdGraphPin_7153'
   End Object
   Begin Object Name="EdGraphPin_7180"
      PinName="Output"
      PinFriendlyName=" "
      Direction=EGPD_Output
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_24.EdGraphPin_7128'
   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")
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_20.EdGraphPin_7154'
   End Object
   Begin Object Name="EdGraphPin_7139"
      PinName="Output"
      PinFriendlyName=" "
      Direction=EGPD_Output
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_25.EdGraphPin_7173'
   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")
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_36.EdGraphPin_7189'
   End Object
   Begin Object Name="EdGraphPin_7142"
      PinName="Output"
      PinFriendlyName=" "
      Direction=EGPD_Output
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_25.EdGraphPin_7174'
   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
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_25.EdGraphPin_7176'
   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
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_25.EdGraphPin_7175'
   End Object
   MaterialExpression=MaterialExpressionFunctionInput'MaterialExpressionFunctionInput_3'
   Pins(0)=EdGraphPin'EdGraphPin_7145'
   Pins(1)=EdGraphPin'EdGraphPin_7146'
   NodePosX=-528
   NodePosY=352
   NodeGuid=7ADB6B31487703CB29E52AA68B257DE6
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"
      InputName="Radial Steps"
      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
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_25.EdGraphPin_7177'
   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"
      InputName="Radial Offset"
      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
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_25.EdGraphPin_7178'
   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
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_25.EdGraphPin_7179'
   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
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_26.EdGraphPin_7138'
   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
      LinkedTo(0)=EdGraphPin'MaterialGraphNode_28.EdGraphPin_7141'
   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.