Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Catlike Coding's C# and Shader Text Tutorials

Discussion in 'Community Learning & Teaching' started by Jasper-Flick, Jul 31, 2011.

  1. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    eclipse130300 and dimmduh1 like this.
  2. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  3. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  4. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    Lurking-Ninja likes this.
  5. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    Lurking-Ninja likes this.
  6. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    UV Sphere
    Wrapping a Grid Around a Sphere

     
  7. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  8. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  9. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  10. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  11. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    Icosphere
    From Octahedron to Icosahedron

     
    flashframe likes this.
  12. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    fomafomitch likes this.
  13. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  14. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  15. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  16. MolochZ

    MolochZ

    Joined:
    May 5, 2016
    Posts:
    3
    Hi Jasper,

    Wondering if you could help me if you have the time?
    I'm trying to get your Hex Grid Tutorial to work with URP.
    Been bashing my head against it for a few weeks now but can't get it to work.

    Any tips on setting up the shader graph, for the "Custom/VertexColors", in the first tutorial?

    Or any other method you might know of.

    Edit: This is the closest thing I've got to work.
    https://forum.unity.com/threads/custom-mesh-uv-mapping.1060721/
    The graph at the bottom. But it's in grey scale.
     
    Last edited: Nov 3, 2022
  17. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    Last edited: Nov 4, 2022
    MolochZ likes this.
  18. MolochZ

    MolochZ

    Joined:
    May 5, 2016
    Posts:
    3
    No way! Man that's gonna be awesome. Thanks for all your hard work. Learned so much from you.
     
  19. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    You can find the Hex Map project here. I just released version 2.0.0, which does the switch to URP.
     
    MolochZ likes this.
  20. MolochZ

    MolochZ

    Joined:
    May 5, 2016
    Posts:
    3
    Thanks again!
     
  21. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  22. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  23. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  24. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  25. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  26. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    Maze 2
    Building and Navigating Passages

     
    Lurking-Ninja likes this.
  27. eclipse130300

    eclipse130300

    Joined:
    Dec 6, 2019
    Posts:
    33
    Dear Jasper!
    I am stumble a bit with shadow map tutorial, namely with conversion from clip space coordinates to texture coords. Could you explain please a little bit more, why have you added corresponding 4 row VP matrix components to to the original matrix and how it helps converting from -1 - 1 to 0 - 1?
    You wrote that we are going to offset and scale by half, that seems fine (basic remap) but as offset you are adding those
    m.m3X component.
    P.S. According to the openGL explanation about orthographic projection matrix,
    https://www.songho.ca/opengl/gl_projectionmatrix.html
    the 4 row always shoud be 0,0,0,1. Why woudn't you just eliminate every m.m3x except m.m33 in your tutorial?

    Thanks in advance :)

    upload_2023-5-1_4-16-8.png
     
  28. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    @eclipse130300 The fourth row is only 0,0,0,1 for standard transformation and orthographic projection matrices. It's true for directional lights, but not for point a spotlight shadow matrices that will come in a later tutorial. That OpenGL page already shows you a fourth row that's 0,0,-1,0. You can verify this by logging the matrix for those light types.
     
    eclipse130300 likes this.
  29. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    Last edited: Jun 30, 2023
  30. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  31. FYI: this link is wrong. The proper link is here.
     
  32. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    Lurking-Ninja likes this.
  33. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  34. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    Custom SRP 1.0.0
    Modernization


    The Custom SRP tutorial series has seen some changes!

    First, I upgraded the entire series to Unity 2022. These are minimal changes that I point out throughout the series, so you'll see them if you work through the series now.

    Second, I have created a Custom SRP project that has the latest FXAA tutorial as a starting point, but modernized with improved C# code style and project layout.

    Third, I will release incremental updates to the project, each of which will be accompanied by a tutorial that goes through all the changes so you can follow along. The first tutorial is for version 1.0.0. That's just a short one describing the changes and fixes required for the upgrade.

    Fourth, the next version will jump to 2.0.0 and introduce the Render Graph API. This upgrade will be rolled out incrementally over multiple releases, each remaining fully functional and with its own tutorial.

    So what you're getting it both a project and tutorials, combined.
     
  35. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  36. carlos_truong

    carlos_truong

    Joined:
    May 9, 2023
    Posts:
    64
    Hi Jasper,
    Thanks for your hard work.

    I've tried your Rendering tutorial, but it is using the built-in render pipeline. How do I make it work in URP?
     
  37. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    @carlos_truong You don't. The Rendering series is old and specifically for Built-in. SRPs didn't exist back then. If you're not interested in Built-in then the series is of no value, besides the general lighting principles it contains.

    I do not have a series dedicated to URP, but do have a Custom SRP series/project.
     
    carlos_truong likes this.
  38. carlos_truong

    carlos_truong

    Joined:
    May 9, 2023
    Posts:
    64
    Okay, I got it.
    Will you make a series about shader fundamentals in URP in the future?
     
  39. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    @carlos_truong Well, Custom SRP does have that, starting with the second tutorial Draw Calls. But of course it's built from the ground up for the custom SRP.

    For URP there's shader graph. The shaders generated by those aren't made for handwriting and their shader API changes too much to make dedicated tutorials for.
     
  40. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    There is now also a webpage for the Hex Map project. It already had three 2.X releases, but they now also each have an accompanying tutorial. Version 2.2.0 is a good starting point as it is the first to introduce new functionality while the other two were about upgrading the old project.

    Hex Map 2.0.0
    URP


    Hex Map 2.1.0
    Code Cleanup


    Hex Map 2.2.0
    Cell Visuals Upgrade
     
    Lurking-Ninja likes this.
  41. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  42. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  43. dot_entity

    dot_entity

    Joined:
    Nov 2, 2012
    Posts:
    86
    With my trivial understanding I tried to apply parallax mapping in the Custom SRP shaders corresponding the instructions from the tutorial about the built-in shader. I managed to achieve the effect, but I strongly doubt that I've done it right (apart of making the code ugly). I am mostly skeptical with how I retrieve the necessary vectors.
    I thereby present the changes in the code asking for help to correct it if possible. I omit the Lit.shader code where just adding the shaders's properties is straightforward (I think), so it's probably ok.
    LitPass.hlsl:
    Code (CSharp):
    1. #ifndef CUSTOM_LIT_PASS_INCLUDED
    2. #define CUSTOM_LIT_PASS_INCLUDED
    3.  
    4. #include "../ShaderLibrary/Surface.hlsl"
    5. #include "../ShaderLibrary/Shadows.hlsl"
    6. #include "../ShaderLibrary/Light.hlsl"
    7. #include "../ShaderLibrary/BRDF.hlsl"
    8. #include "../ShaderLibrary/GI.hlsl"
    9. #include "../ShaderLibrary/Lighting.hlsl"
    10.  
    11. struct Attributes {
    12. // ... //Omitted code that was not edited
    13.     float2 baseUV : TEXCOORD0;
    14.  
    15.     GI_ATTRIBUTE_DATA
    16.     UNITY_VERTEX_INPUT_INSTANCE_ID
    17. };
    18.  
    19. struct Varyings {
    20.   // ... //
    21.     #if defined(_DETAIL_MAP)
    22.         float2 detailUV : VAR_DETAIL_UV;
    23.     #endif
    24.  
    25.     //*****Trying Parallax inserted block
    26.     #if defined(_PARALLAX_MAP)
    27.         float3 viewDirTS : VAR_VIEWDIR;
    28.     #endif
    29.     //*****End of block
    30.  
    31.     GI_VARYINGS_DATA
    32.     UNITY_VERTEX_INPUT_INSTANCE_ID
    33. };
    34.  
    35. Varyings LitPassVertex (Attributes input) {
    36.     Varyings output;
    37. // ... //
    38.     #if defined(_NORMAL_MAP)
    39.         output.tangentWS = float4(
    40.             TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w
    41.         );
    42.     #endif
    43.     output.baseUV = TransformBaseUV(input.baseUV);
    44.     #if defined(_DETAIL_MAP)
    45.         output.detailUV = TransformDetailUV(input.baseUV);
    46.     #endif
    47.  
    48.     //****Trying Parallax inserted block
    49.     #if defined (_PARALLAX_MAP)
    50.         #if defined(PARALLAX_SUPPORT_SCALED_DYNAMIC_BATCHING)
    51.             input.tangentOS.xyz = normalize(input.tangentOS.xyz);
    52.             input.normalOS = normalize(input.normalOS);
    53.         #endif
    54.         float3x3 objectToTangent = float3x3(
    55.             input.tangentOS.xyz,
    56.             cross(input.normalOS, input.tangentOS.xyz) * input.tangentOS.w,
    57.             input.normalOS
    58.         );
    59.         output.viewDirTS = mul(objectToTangent, TransformObjectToViewDir(input.positionOS));
    60.     #endif
    61.     //*****End of block
    62.  
    63.     return output;
    64. }
    65.  
    66. float4 LitPassFragment (Varyings input) : SV_TARGET {
    67.     UNITY_SETUP_INSTANCE_ID(input);
    68. // ... //
    69.     #if defined(_DETAIL_MAP)
    70.         config.detailUV = input.detailUV;
    71.         config.useDetail = true;
    72.     #endif
    73.  
    74.     //******Trying Parallax inserted block
    75.     #if defined(_PARALLAX_MAP)
    76.         input.viewDirTS = normalize(input.viewDirTS);
    77.         #if !defined(PARALLAX_OFFSET_LIMITING)
    78.             #if !defined(PARALLAX_BIAS)
    79.                 #define PARALLAX_BIAS 0.42
    80.             #endif
    81.             input.viewDirTS.xy /= (input.viewDirTS.z + PARALLAX_BIAS);
    82.         #endif
    83.  
    84.         #if !defined(PARALLAX_FUNCTION)
    85.             #define PARALLAX_FUNCTION ParallaxOffset
    86.         #endif
    87.         float2 uvOffset = PARALLAX_FUNCTION(config, input.viewDirTS.xy);
    88.         config.baseUV.xy += uvOffset;
    89.         config.detailUV.xy += uvOffset * (config.detailUV.xy / config.baseUV.xy);
    90.     #endif
    91.     //******End of block
    92.  
    93.     float4 base = GetBase(config);
    94.  
    95.     #if defined(_CLIPPING)
    96.      // ... //
    97.     return float4(color, GetFinalAlpha(surface.alpha));
    98. }
    99.  
    100. #endif
    LitInput.hlsl:
    Code (CSharp):
    1. #ifndef CUSTOM_LIT_INPUT_INCLUDED
    2. #define CUSTOM_LIT_INPUT_INCLUDED
    3.  
    4. TEXTURE2D(_BaseMap);
    5. TEXTURE2D(_MaskMap);
    6. TEXTURE2D(_NormalMap);
    7. //Trying Parallax*****
    8. TEXTURE2D(_ParallaxMap);
    9. //*****
    10. TEXTURE2D(_EmissionMap);
    11. SAMPLER(sampler_BaseMap);
    12.  
    13. // ... //
    14.  
    15. UNITY_INSTANCING_BUFFER_START(UnityPerMaterial)
    16. // ... //
    17.     UNITY_DEFINE_INSTANCED_PROP(float, _NormalScale)
    18. //Trying Parallax*****
    19.     UNITY_DEFINE_INSTANCED_PROP(float, _ParallaxStrength)
    20. //*****
    21. UNITY_INSTANCING_BUFFER_END(UnityPerMaterial)
    22.  
    23. #define INPUT_PROP(name) UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, name)
    24.  
    25. //********Trying Parallax inserted block
    26.     #define PARALLAX_BIAS 0
    27. //    #define PARALLAX_OFFSET_LIMITING
    28.     #define PARALLAX_RAYMARCHING_STEPS 10
    29.     #define PARALLAX_RAYMARCHING_INTERPOLATE
    30.     #define PARALLAX_RAYMARCHING_SEARCH_STEPS 3
    31.     #define PARALLAX_FUNCTION ParallaxRaymarching
    32.     #define PARALLAX_SUPPORT_SCALED_DYNAMIC_BATCHING
    33. // *******End of block
    34.  
    35. struct InputConfig {
    36.     Fragment fragment;
    37.     float2 baseUV;
    38.     float2 detailUV;
    39.     bool useMask;
    40.     bool useDetail;
    41. };
    42.  
    43. InputConfig GetInputConfig (float4 positionSS, float2 baseUV, float2 detailUV = 0.0) {
    44.     InputConfig c;
    45.     c.fragment = GetFragment(positionSS);
    46.     c.baseUV = baseUV;
    47.     c.detailUV = detailUV;
    48.     c.useMask = false;
    49.     c.useDetail = false;
    50.     return c;
    51. }
    52.  
    53. float2 TransformBaseUV (float2 baseUV) {
    54.   // ... //
    55.     return normal;
    56. }
    57.  
    58. //*****Trying Parallax inserted block
    59. float GetParallaxHeight (float2 uv) {
    60.     float4 map = SAMPLE_TEXTURE2D(_ParallaxMap, sampler_BaseMap, uv);
    61.     return map.g;
    62. }
    63.  
    64. float2 GetParallaxOffset (InputConfig c, float2 viewDir) {
    65.     float strength = INPUT_PROP(_ParallaxStrength);
    66.     float height = GetParallaxHeight(c.baseUV);
    67.     height -= 0.5;
    68.     height *= strength;
    69.     return viewDir * height;
    70. }
    71.  
    72. float2 ParallaxRaymarching (InputConfig c, float2 viewDir) {
    73.     #if !defined(PARALLAX_RAYMARCHING_STEPS)
    74.         #define PARALLAX_RAYMARCHING_STEPS 10
    75.     #endif
    76.     float strength = INPUT_PROP(_ParallaxStrength);
    77.     float2 uvOffset = 0;
    78.     float stepSize = 1.0 / PARALLAX_RAYMARCHING_STEPS;
    79.     float2 uvDelta = viewDir * (stepSize * strength);
    80.  
    81.     float stepHeight = 1;
    82.     float surfaceHeight = GetParallaxHeight(c.baseUV);
    83.     float2 prevUVOffset = uvOffset;
    84.     float prevStepHeight = stepHeight;
    85.     float prevSurfaceHeight = surfaceHeight;
    86.  
    87.     for (
    88.         int i = 1;
    89.         i < PARALLAX_RAYMARCHING_STEPS && stepHeight > surfaceHeight;
    90.         i++
    91.     ) {
    92.         prevUVOffset = uvOffset;
    93.         prevStepHeight = stepHeight;
    94.         prevSurfaceHeight = surfaceHeight;
    95.         uvOffset -= uvDelta;
    96.         stepHeight -= stepSize;
    97.         surfaceHeight = GetParallaxHeight(c.baseUV + uvOffset);
    98.     }
    99.     #if !defined(PARALLAX_RAYMARCHING_SEARCH_STEPS)
    100.         #define PARALLAX_RAYMARCHING_SEARCH_STEPS 0
    101.     #endif
    102.  
    103.     #if PARALLAX_RAYMARCHING_SEARCH_STEPS > 0
    104.         for (int j = 0; j < PARALLAX_RAYMARCHING_SEARCH_STEPS; j++) {
    105.             uvDelta *= 0.5;
    106.             stepSize *= 0.5;
    107.             if (stepHeight < surfaceHeight) {
    108.                 uvOffset += uvDelta;
    109.                 stepHeight += stepSize;
    110.             }
    111.             else {
    112.                 uvOffset -= uvDelta;
    113.                 stepHeight -= stepSize;
    114.             }
    115.             surfaceHeight = GetParallaxHeight(c.baseUV + uvOffset);
    116.         }
    117.     #elif defined(PARALLAX_RAYMARCHING_INTERPOLATE)
    118.         float prevDifference = prevStepHeight - prevSurfaceHeight;
    119.         float difference = surfaceHeight - stepHeight;
    120.         float t = prevDifference / (prevDifference + difference);
    121.         uvOffset = prevUVOffset - uvDelta * t;
    122.     #endif
    123.  
    124.     return uvOffset;
    125. }
    126. //****End of block
    127.  
    128.  
    129. float3 GetEmission (InputConfig c) {
    130. // ... //
    131. float GetFresnel (InputConfig c) {
    132.     return INPUT_PROP(_Fresnel);
    133. }
    134.  
    135. #endif
    I finally added the TransformObjectToViewDir function in the Common.hlsl, for no good reason, just because I thought it would be more appropriate there.
    Common.hlsl:
    Code (CSharp):
    1. #ifndef CUSTOM_COMMON_INCLUDED
    2. #define CUSTOM_COMMON_INCLUDED
    3.  
    4. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    5. // ... //
    6. float3 NormalTangentToWorld (float3 normalTS, float3 normalWS, float4 tangentWS) {
    7.     float3x3 tangentToWorld =
    8.         CreateTangentToWorld(normalWS, tangentWS.xyz, tangentWS.w);
    9.     return TransformTangentToWorld(normalTS, tangentToWorld);
    10. }
    11.  
    12. //******Trying Parallax inserted block
    13. float3 TransformObjectToViewDir (float3 positionOS) {
    14.     float3 objSpaceCameraPos =
    15.         mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
    16.     return objSpaceCameraPos - positionOS.xyz;
    17. }
    18. //*****End of Block
    19.  
    20. #endif
     
  44. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    @dot_entity On a cursory glance it appears that you have done everything right. I made a mental note to include the effect in a future update of the Custom SRP project.
     
  45. dot_entity

    dot_entity

    Joined:
    Nov 2, 2012
    Posts:
    86
    Thank you Jasper! I appreciate every piece of past and future effort and knowledge you offer to us! To be honest, I am not certain that I've done it wrong. On a simple sphere it looks fine, but on a slightly more complex object (a cloth basket) I get a different effect when amplifying the parallax strength, in comparison to the (standard I think) URP lit material that has parallax too. That's the only clue I have, I am not able to debug properly, I assume URP could use slightly different parallax method and I have not experimented enough to draw concrete conclusions, but I thought I might get the wrong tangent to view vector or something, or I just feed the data in the wrong place (yes I'm that amateur in programming and it took me three days, with the research included, to complete this relatively simple task). I show a couple of images to better present what I mean.
    Custom SRP Low and High Parallax value:
    CRP_Parallax_Scene_Low.png CRP_Parallax_Scene.png

    Exact same model and textures with URP High Parallax value:
    URP_Parallax_Scene.png URP_Parallax_Play.png

    The two pictures about the URP version are from the same instance. I just include the scene and the play mode view, to demonstrate that there is this cyan tinted overlay all over the scene view and material preview when I load the URP renderer. Which was actually the reason I turned to the Custom RP in the first place. Both this and that I knew I can really grasp a good understanding from your tutorials.

    Update: I think I figured out the issue. It was the parallax method that URP shaders use (it's more like the offset one). I disabled/commented the Raymarching function forcing the CustomRP shader to use the offset function and the effect between the two renderers is quite similar when amplifying the parallax strength.
     
    Last edited: Oct 1, 2023
  46. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    @dot_entity You are correct that the standard URP Lit material uses simple parallax mapping. You can get the raymarching technique in URP by creating a shader graph with a Parallax Occlusion Mapping node.

    The weirdness you're getting with the raymarching approach is because when the depth is set too large the ray misses the UV-mapped area and ends up in a different region of the texture unwrap. That's the unused striped area in the case of your basket top. For this reason the technique doesn't work well with texture unwraps. It's best used with tiling textures. That's why it typically only gets strongly applied to flat surfaces like cobblestone streets and brick walls.
     
    dot_entity likes this.
  47. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  48. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  49. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
  50. Jasper-Flick

    Jasper-Flick

    Joined:
    Jan 17, 2011
    Posts:
    957
    You can now also support me via Ko-fi!