Sloppy Unreal 02: Setting Up Raytracing & Generating Normal Maps In Houdini

comments 8
Unreal Engine

Part two of working sloppily in Unreal covers setting up raytracing and materials. Also we’ll tackle the generation of normal maps from a grayscale image in Houdini, talk a bit about different approximations for the Fresnel term and finally poke around in Unreal’s console in order to nudge it’s raytracer to where we want it.

Links

Download Assets (.zip)

Matthias Winckelmann’s UE quickstart workshop.

Lego model from Mecabricks

HDRI from Aixterior

Liked it? Take a second to support Moritz on Patreon!

8 Comments

  1. Lucca Troll

    Unreal materials excpect only the base reflection fraction as an input for specular, because unreal calculates the fresnel internally when rendering using this formula :
    vec3 fresnelSchlick(float cosTheta, vec3 f0) {
    return f0 + (1.0 – f0) * pow(1.0 – cosTheta, 5.0);
    }

    So you should not use your own fresnel term and instead play around with the base reflection fraction, the default value used by unreal is 0.5.
    Just thought i’d let you know, otherwise great video.

    • Lucca Troll

      Hello Moritz,
      i could not find too much information on the internal workings of unreals materials, so i tried to recreate unreals material preview in C4D using Redshift and found out something:
      First i converted the F0 value of 0.04 the the corresponding ior of 1.5 using this formula:
      ior = -(f0 + 1 + 2 * sqrt(f0)) / (f0 – 1)
      Doing this i found out, that unreal internally divides the specular value you give it by 2, to prevent unrealisticly reflective materials.
      I came to this conclusion after using a F0 = 0.02 to calculate an ior = 1.33.
      When i used this ior value in my redshift material i got this image:
      https://cdn.discordapp.com/attachments/209049190293045249/785623615278284830/RedshiftTest.PNG
      Wich looks very similar to the B-Image you provided above, so to me it would seem, that the more subtle specular without the custom ior node is more accurate.
      I have wrote some code for you, with wich you can convert an ior to the corresponding F0 value, wich is already multiplied by 2 to make it “unreal ready”, just copy and paste this code into your material and pipe in the ior you want:

      Begin Object Class=/Script/UnrealEd.MaterialGraphNode Name=”MaterialGraphNode_2″
      Begin Object Class=/Script/Engine.MaterialExpressionCustom Name=”MaterialExpressionCustom_0″
      End Object
      Begin Object Name=”MaterialExpressionCustom_0″
      Code=”float f0 = abs((1.0 – Ior) / (1.0 + Ior));\r\nreturn f0 * f0 * 2.0;”
      OutputType=CMOT_Float1
      Description=”IorToF0″
      Inputs(0)=(InputName=”Ior”,Input=(Expression=MaterialExpressionConstant'”MaterialExpressionConstant_2″‘))
      MaterialExpressionEditorX=-528
      MaterialExpressionEditorY=320
      MaterialExpressionGuid=46F9D2C74AD7AFF4C18A14A7FFBCC1D8
      Material=PreviewMaterial'”/Engine/Transient.NewMaterial”‘
      bCollapsed=True
      End Object
      MaterialExpression=MaterialExpressionCustom'”MaterialExpressionCustom_0″‘
      NodePosX=-528
      NodePosY=320
      NodeGuid=3DF03C524EDEE6DF5B4BB99DB39FEC78
      CustomProperties Pin (PinId=F3A1EF4449C6203278C5DC925F8E4890,PinName=”Ior”,PinType.PinCategory=”required”,PinType.PinSubCategory=””,PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=True,LinkedTo=(MaterialGraphNode_4 8B358BF2493237423B071B87BE8E60E6,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
      CustomProperties Pin (PinId=220B15F7400EC69FF4DEF8B2B9C39636,PinName=”Output”,PinFriendlyName=NSLOCTEXT(“MaterialGraphNode”, “Space”, ” “),Direction=”EGPD_Output”,PinType.PinCategory=””,PinType.PinSubCategory=””,PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=True,LinkedTo=(MaterialGraphNode_Root_0 48B7BAF244CF8B31082019AD3D2B51F5,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
      End Object

      I hope i could help, Lucca

      • Lucca Troll

        Just noticed, that the code is sent does not work when pasting it inside a material, this code should work now:

        Begin Object Class=/Script/UnrealEd.MaterialGraphNode Name=”MaterialGraphNode_6″
        Begin Object Class=/Script/Engine.MaterialExpressionCustom Name=”MaterialExpressionCustom_0″
        End Object
        Begin Object Name=”MaterialExpressionCustom_0″
        Code=”float f0 = abs((1.0 – Ior) / (1.0 + Ior));\r\nreturn f0 * f0 * 2.0;”
        OutputType=CMOT_Float1
        Description=”IorToF0″
        Inputs(0)=(InputName=”Ior”,Input=(Expression=MaterialExpressionConstant'”MaterialExpressionConstant_2″‘))
        MaterialExpressionEditorX=-528
        MaterialExpressionEditorY=320
        MaterialExpressionGuid=46F9D2C74AD7AFF4C18A14A7FFBCC1D8
        Material=PreviewMaterial'”/Engine/Transient.NewMaterial”‘
        bCollapsed=True
        End Object
        MaterialExpression=MaterialExpressionCustom'”MaterialExpressionCustom_0″‘
        NodePosX=-528
        NodePosY=320
        NodeGuid=3DF03C524EDEE6DF5B4BB99DB39FEC78
        CustomProperties Pin (PinId=F3A1EF4449C6203278C5DC925F8E4890,PinName=”Ior”,PinType.PinCategory=”required”,PinType.PinSubCategory=””,PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=True,LinkedTo=(MaterialGraphNode_4 8B358BF2493237423B071B87BE8E60E6,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
        CustomProperties Pin (PinId=220B15F7400EC69FF4DEF8B2B9C39636,PinName=”Output”,PinFriendlyName=NSLOCTEXT(“MaterialGraphNode”, “Space”, ” “),Direction=”EGPD_Output”,PinType.PinCategory=””,PinType.PinSubCategory=””,PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=True,LinkedTo=(MaterialGraphNode_Root_0 48B7BAF244CF8B31082019AD3D2B51F5,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
        End Object

  2. Thanks Lucca,

    indeed – I just ran your tests in Octane too and you’re absolutely right – thanks for pointing this out and thanks for the script!

    Cheers, Mo

  3. Really enjoying this series! Small hiccup, no matter how I import the lego model (as .obj) no materials assignments are included.

Leave a Reply to Lucca Troll Cancel reply