Search Unity

Crest [Advanced Ocean Renderer][OPEN SOURCE]

Discussion in 'Shaders' started by RealmLord, Aug 28, 2018.

  1. RealmLord

    RealmLord

    Joined:
    Aug 25, 2018
    Posts:
    5
    CREST
    Crest is a technically advanced ocean renderer implemented in Unity3D 2018.2+.


    https://github.com/huwb/crest-oceanrender

    The Tech
    Some of the core ideas were described at SIGGRAPH 2017 in the Advances in Real-Time Rendering course (course page link). Since this initial publication we have been actively working to extend the feature set, which includes innovations in the following areas.

    Shape
    It is well known that ocean shape can be well approximated by summing Gerstner waves. Dozens of these are required to obtain an interesting shape. In previous implementations this has been prohibitively expensive and shape is either generated using an online FFT, or precomputed and baked into textures.

    We generate shape from Gerstner waves efficiently at runtime by rendering at multiple scales, and ensure that waves are never over-sampled (inefficient) or under-sampled (bad quality, aliasing). This is highly performant and gives detail close to the viewer, and shape to the horizon. This gives considerable flexibility in shape and opens possibilities such as attenuating waves based on ocean depth around shorelines.

    To control the ocean shape, we introduce an intuitive and fun shape authoring interface - an equalizer style editor which makes it fast and easy to achieve surface shape. Art direction such as small choppy waves with longer waves rolling in from a storm at the horizon is simple to achieve in this framework. We also support empirical ocean spectra from the literature (Phillips, JONSWAP, etc) which can be used directly or as a comparison.

    For interactivity we add a dynamic wave simulation on top of the ocean waves. The simulation is computed on a heightfield and then converted into displacements, which trigger foam generation and enable boat wakes to be generated. This is demonstrated in the boat and threeboats example scenes.

    The final shape is asynchronously read back to the CPU for gameplay/physics use. This gives access to the full, rich shape without requiring expensive CPU calculations or pipeline stalls.

    Mesh
    We implement a 100% pop-free meshing solution, which follows the same unified multi-scale structure/layout as the shape data. The vertex densities and locations match the shape texels 1:1. This ensures that the shape is never over-sampled or under-sampled, giving the same guarantees as described above.

    Our meshing approach requires only simple shader instructions in a vertex shader, and does not rely on tessellation or compute shaders or any other advanced shader model features. The geometry is composed of tiles which have strictly no overlap, and support frustum culling. These tiles are generated quickly on startup.

    The multi-resolution representation (shape textures and geometry) is scaled horizontally when the camera changes altitude to ensure appropriate level of detail and good visual range for all viewpoints. To further extend the surface to the horizon we also add a strip of triangles at the mesh boundary.

    Shading / VFX
    Normal maps are elegantly incorporated into our multi-scale framework. Normal map textures are treated as a slightly different form of shape that is too detailed to be efficiently sampled by geometry, and are sampled at a scale just below the shape textures. This combats typical normal map sampling issues such as lack of detail in the foreground, or a glassy flat appearance in the background.

    The ocean colour comes from a subsurface scattering approximation based on view and normal vectors, and primary light direction.

    Foam is shaded in two layers. Underwater bubbles have parallax and refraction offsets to give an impression of depth. White foam on top of the water is shaded with a simple 3D lighting model using procedurally generated normals.

    Transparency and refraction are also supported, and Schlick's fresnel approximation selects between the refracted colour and a reflected colour. There is an option on the material to boost specular highlights by adding directional lighting if needed.

    All shading features are on static switches and can be disabled if not required.

    As an area of future work, the branch fx_test explores dynamically generating spray particle effects by randomly sampling points on the surface to detect wave peaks.

    P.S: Please check the github for author information. I am just posting this here
     
    Last edited: Aug 30, 2018
  2. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    hmm.. not 5.6 friendly. shame. Ah well, if you will use GPU readback... ;)
     
  3. RealmLord

    RealmLord

    Joined:
    Aug 25, 2018
    Posts:
    5
    Hi sorry, that just went over my head. Could you please elaborate whether this is good or bad?
     
    twobob likes this.
  4. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    well it's only bad for people who use the older version of unity :)
    "GPU readback" is the commit where you switch across to a later version of unity "and no going back"
    Yes, I was trawling your commits to see if I could use it in 5.6.

    @RealmLord thanks anyway though. nice project
     
  5. RealmLord

    RealmLord

    Joined:
    Aug 25, 2018
    Posts:
    5
    Apologies,op
    This isn't my project, I just came across it and thought might interest everyone here.
     
    twobob likes this.
  6. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Hah sure man.
    It did. I'll make a few notes on the repo and see if it gets tidied up

    It is 2018.x minimum anyway :)

    Appreciate it :)
     
    Last edited: Aug 28, 2018
  7. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    5,685
    I like this, but it should go in its own thread, instead of in the Community Ocean Shader thread.
     
    erenaydin and twobob like this.
  8. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    My thoughts exactly
     
  9. ceebeee

    ceebeee

    Joined:
    Mar 7, 2017
    Posts:
    395
    if you go back far enough in the commits, there's a 2017 version. It just lacks a few of the newer features.
     
    twobob likes this.
  10. Liminal-Ridges

    Liminal-Ridges

    Joined:
    Oct 21, 2015
    Posts:
    256
    Just tested it, easy to setup, realistic waves but:

    1) You need to make a realistic shader/textures
    2) Expose the visual settings to the main menu so the user doesnt have to edit the material itself
    3) The system should automatically add the required layers

    Keep up!
     
  11. Dekata

    Dekata

    Joined:
    May 20, 2016
    Posts:
    47
    ocean is very nice, maybe the best for unity atm, but foam isn't clear, how to add more to boat?
     
  12. John-G

    John-G

    Joined:
    Mar 21, 2013
    Posts:
    1,122
    Looks great. Does it support wakes and reflections? A good ocean system seems to be a holy grail for Unity.
     
    Bartolomeus755 likes this.
  13. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    You should be aware there is no active development on this as the author does not have time. If you have to ask if something is supported, then it is best to change the question to how you can do it yourself.
     
  14. ekergraphics

    ekergraphics

    Joined:
    Feb 22, 2017
    Posts:
    257
    This is amazing. I completely missed this. As for the development, I see on Github that a pull request was just merged 3 days ago, so it does seem to have some life!

    EDIT: Should this thread be merged with this one, perhaps?

    https://forum.unity.com/threads/crest-open-source-unity-ocean-renderer.548212/
     
    Last edited: Oct 30, 2018
  15. christal-gary

    christal-gary

    Joined:
    Aug 28, 2013
    Posts:
    3
    Thank you Crest! This is rendered using crest!
     
    huwb, ceebeee and erenaydin like this.
  16. Parallel_

    Parallel_

    Joined:
    Dec 9, 2012
    Posts:
    90
    How would one best get the foam coordinates for adding particles in those areas?
    I'm not really C# litterate but trying to understand the process to reverse engineer to playmaker. I see a float4 for vertex position in UpdateFoam.shader but is this where you'd get the final calculations after sim-settings have been taken into account? I would have tried this option out but the relevant action doesn't exist for PM yet.
     
  17. creat327

    creat327

    Joined:
    Mar 19, 2009
    Posts:
    1,756
    anyone knows how well this runs on mobile?
     
  18. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I would err on the side of "it doesn't run". More like hobble or sink.
     
    ceebeee likes this.
  19. dimitris_baud

    dimitris_baud

    Joined:
    Jan 15, 2018
    Posts:
    31
    Hi, first of all Crest is amazing, thank you for sharing!

    I am trying it out and have several objects deforming the water which after some time gets out of control. Is there a way to gracefully "flatten" the water to its original state, removing all information added on top by objects registering waves?

    `OceanRenderer.RegenMesh()` didn't seem intended for that purpose.

    Thank you.
     
  20. Tony-Lovell

    Tony-Lovell

    Joined:
    Jul 14, 2014
    Posts:
    127
    Looks great. Constructive criticism: you're going to need a bigger boat

    tone
     
  21. FirstTimeCreator

    FirstTimeCreator

    Joined:
    Sep 28, 2016
    Posts:
    768
    Any plans for supporting point and spot lights anytime soon?
     
  22. FirstTimeCreator

    FirstTimeCreator

    Joined:
    Sep 28, 2016
    Posts:
    768
    I am looking into limiting the size of the ocean so that it is not infinite but instead limited to a length/width of quads.

    For performance reasons and the fact that I won't always be needing an infinite ocean but just a water plane that fits within a certain area.
     
  23. FirstTimeCreator

    FirstTimeCreator

    Joined:
    Sep 28, 2016
    Posts:
    768
    Hrmph it appears I would need to basically strip out this Lod system and rewrite the whole section entirely to be able to set a set width and length of the ocean quads.

    From what I can tell messing around with the LOD system, this seems possible to do.
     
  24. FirstTimeCreator

    FirstTimeCreator

    Joined:
    Sep 28, 2016
    Posts:
    768
    Oh and by the way ive just done an underwater shader with Fog and perfect clipping with wave height as the character controller traverses the waves normal height.

    Ill see if i cant show that in the video as well by making some large wave clip the player so you can see the underwater view and above water view perfectly transition. ;)

    Ill go ahead and post a few pics without revealing my scene yet, dont want to show you guys what im working on until its .. abit more ready.
     
  25. FirstTimeCreator

    FirstTimeCreator

    Joined:
    Sep 28, 2016
    Posts:
    768
    Ok here is my underwater shader.

    Still a work in progress and there is only one drawback, cant have transparent objects under the surface yet.

    For my purposes i may not need to have transparency on other objects under the water. Like i said still working on it so I may find a solution to that.

    Going to add underwater debrees as well as a transition FX screen shader for splashes.

    I noticed doing a search alot of people were trying to figure out how to do exactly what I've just done ;)

    To make it look better a blur effect would need to be added where the seam meets. I think that is doable as well but will have an impact on performance.
     

    Attached Files:

  26. blogsabout

    blogsabout

    Joined:
    Aug 20, 2014
    Posts:
    50
    Have anyone experienced that your ocean turns pink when opening the file after it has been closed down?
    It was looking so gorgeous and I can see the settings are the same and enabled...but now pink?

    PS. For those wanting to use the planer reflections and can't get it to work, remember to add the Planer reflection script to the camera.

    EDIT: I noticed that in the material editor all settings are disabled and therefore the pink color.
    The material doesn't exist in the list ("Crest>Ocean")
    When opening the full package and opening one of the projects, playing around the materials is in the shaderlist (Crest>Ocean).

    When closing the project down and opening again it's all pink and this error:
    Shader error in 'Crest/Ocean': 'SkyProceduralDP': no matching 2 parameter function at Assets/Crest/Crest/Shaders/OceanReflection.hlsl(74) (on metal)"

    ...so weird? Reflections worked perfectly before closing the project down. (using MacBook Pro mid 2018)
     
    Last edited: May 22, 2019
    felixIksz likes this.
  27. rafayel_zealous

    rafayel_zealous

    Joined:
    Nov 21, 2018
    Posts:
    11
    Is there a way to change size of the LOD for wave/fom for spectrums, the tiling can be seen even if the waves are relatively small and little or no foam is generated.
    Basically we would want to get rid of the square shaped area of single spectrum.

    upload_2019-8-23_17-25-59.png
     
  28. Rayeloy

    Rayeloy

    Joined:
    Feb 12, 2017
    Posts:
    45
    Hi, I'm using this incredible asset, but I need the player to float on the sea waves realistically. To do this, I know I could just add a SimpleFloatingObject and a rigidbody, but I'm using my own custom character controller, physics and collisions, so I wanted to get the current water height at the player position to move the character to that y position. I don't need x and z displacement. Does anyone know where can I get this water height from?
     
  29. Deleted User

    Deleted User

    Guest

    Hi there.

    We're going to use this awesome asset in our project, but we've faces with an issue. Seems lifetime of the boat tail foam in general is the same as the ocean waves'. Have anyone tried to create longer tail waves (e.g. for tankers, cargos).

    Thanks in advance.
     
  30. patrickk2

    patrickk2

    Joined:
    Dec 8, 2019
    Posts:
    92
    Hello there!

    This really looks like a very promising asset for some ideas I wanted to play around with. Do any of you guys know, if you can also create really big breaking waves with this? In the video from the islans demo scene we see some more or less rough waters, and it talks about "Foam simulated from waves and shorelines" in the description, but I haven't found something definite about breaking waves (the kind you see when do do an image search for "surfing hawaii" for example :)).

    Although I think this doesn't affect the ocean renderer all that much, I want to add that the shore line will most likely be generated by MapMagic (just in case anyone has experience with using both assets together and knows about any pitfalls to avoid).

    Any info on this would be greatly appreciated!

    Another question of mine is about performance when you have lots of big waves with foam. Is there anything one has to be careful about, or any optimisations one can do? Like creating several "wave animations" and reusing them instead of calculating everything all the time? Appologies if this is a very noobie question, I only just started looking for possibilities concerning oceans. From what I've seen in the videos, the ocean renderer has to take care of everything, but I didn't want to miss out on any options by not asking.

    Thanks in advance for any feedback on this.

    Best regards,
    Patrick
     
  31. Vincent454

    Vincent454

    Joined:
    Oct 26, 2014
    Posts:
    167
    I dont think you can do breaking waves, as water vertices cannot vertically overlap, if you understand what I mean. Performance wise, I am not sure if bigger waves mean less performance, but you can try it out for yourself as the standard render pipeline version of crest is 100% free. Only lwrp costs money :)
     
  32. patrickk2

    patrickk2

    Joined:
    Dec 8, 2019
    Posts:
    92
    Hello!

    Thank you for the answer! And also the tip about the standard render pipeline version being free. I will definitely look into that.

    Best regards,
    Patrick
     
  33. Chris_Payne_QS

    Chris_Payne_QS

    Joined:
    Jul 16, 2016
    Posts:
    84
    I've not tried it myself TBH, but I would trail some foam inputs behind the boat to keep the wake alive.
     
  34. JDrem1

    JDrem1

    Joined:
    Jun 24, 2017
    Posts:
    199
    HI, just installed Crest. (the purchased version.) And am getting 13 red warnings in the console.
    This is one of them.

    Assets\Crest\Crest\Scripts\LodData\Shadows\LodDataMgrShadow.cs(7,29): error CS0234: The type or namespace name 'Universal' does not exist in the namespace 'UnityEngine.Rendering' (are you missing an assembly reference?)

    I am a none coder. Any help appreciated please.
    Thanks.
     
  35. OP3NGL

    OP3NGL

    Joined:
    Dec 10, 2013
    Posts:
    267
    i got 2 question...
    1. will this work with oculus quest?
    2. how do i make a tidal/tsunami wave since u can make a vacumn funnel shape?
     
  36. pantang

    pantang

    Joined:
    Sep 1, 2016
    Posts:
    219
    I really love the look great work and will more than likely be putting you in my credits if I get their. Once question if you have time, is there anyway to limit the ocean to the boundaries and shape of a plane or obejct??
     
  37. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    864
    Hello, I just started to try out crest. Checked the examples but still don't know how to add surface decals. Any suggestions?
     
  38. ajmal005

    ajmal005

    Joined:
    Dec 5, 2018
    Posts:
    2
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Decal/Decal.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Decal/DecalPrepassBuffer.hlsl"

    DECLARE_DBUFFER_TEXTURE(_DBufferTexture);

    // In order that the lod for with transpartent decal better match the lod for opaque decal
    // We use ComputeTextureLOD with bias == 0.5
    void EvalDecalMask( PositionInputs posInput, float3 vtxNormal, float3 positionRWSDdx, float3 positionRWSDdy, DecalData decalData,
    inout float4 DBuffer0, inout float4 DBuffer1, inout float4 DBuffer2, inout float2 DBuffer3, inout float alpha)
    {
    // Get the relative world camera to decal matrix
    float4x4 worldToDecal = ApplyCameraTranslationToInverseMatrix(decalData.worldToDecal);
    float3 positionDS = mul(worldToDecal, float4(posInput.positionWS, 1.0)).xyz;
    positionDS = positionDS * float3(1.0, -1.0, 1.0) + float3(0.5, 0.5, 0.5); // decal clip space
    if ((all(positionDS.xyz > 0.0) && all(1.0 - positionDS.xyz > 0.0)))
    {
    float2 uvScale = float2(decalData.normalToWorld[3][0], decalData.normalToWorld[3][1]);
    float2 uvBias = float2(decalData.normalToWorld[3][2], decalData.normalToWorld[3][3]);
    positionDS.xz = positionDS.xz * uvScale + uvBias;
    positionDS.xz = frac(positionDS.xz);

    // clamp by half a texel to avoid sampling neighboring textures in the atlas
    float2 clampAmount = float2(0.5 / _DecalAtlasResolution.x, 0.5 / _DecalAtlasResolution.y);

    // need to compute the mipmap LOD manually because we are sampling inside a loop
    float3 positionDSDdx = mul(worldToDecal, float4(positionRWSDdx, 0.0)).xyz; // transform the derivatives to decal space, any translation is irrelevant
    float3 positionDSDdy = mul(worldToDecal, float4(positionRWSDdy, 0.0)).xyz;

    // Following code match the code in DecalData.hlsl used for DBuffer. It have the same kind of condition and similar code structure
    uint affectFlags = (int)(decalData.blendParams.z + 0.5f); // 1 albedo, 2 normal, 4 metal, 8 AO, 16 smoothness
    float fadeFactor = decalData.normalToWorld[0][3];
    // Check if this decal projector require angle fading
    float2 angleFade = float2(decalData.normalToWorld[1][3], decalData.normalToWorld[2][3]);

    // Angle fade is disabled if decal layers isn't enabled for consistency with DBuffer Decal
    // The test against _EnableDecalLayers is done here to refresh realtime as AngleFade is cached data and need a decal refresh to be updated.
    if (angleFade.y < 0.0f && _EnableDecalLayers) // if angle fade is enabled
    {
    float3 decalNormal = float3(decalData.normalToWorld[0].z, decalData.normalToWorld[1].z, decalData.normalToWorld[2].z);
    float dotAngle = dot(vtxNormal, decalNormal);
    // See equation in DecalSystem.cs - simplified to a madd mul add here
    float angleFadeFactor = saturate(angleFade.x + angleFade.y * (dotAngle * (dotAngle - 2.0)));
    fadeFactor *= angleFadeFactor;
    }

    float albedoMapBlend = fadeFactor;
    float maskMapBlend = fadeFactor;

    // Albedo
    // We must always sample diffuse texture due to opacity that can affect everything)
    {
    float4 src = decalData.baseColor;

    // We use scaleBias value to now if we have init a texture. 0 mean a texture is bound
    bool diffuseTextureBound = (decalData.diffuseScaleBias.x > 0) && (decalData.diffuseScaleBias.y > 0);
    if (diffuseTextureBound)
    {
    // Caution: We can't compute LOD inside a dynamic loop. The gradient are not accessible.
    float2 diffuseMin = decalData.diffuseScaleBias.zw + clampAmount; // offset into atlas is in .zw
    float2 diffuseMax = decalData.diffuseScaleBias.zw + decalData.diffuseScaleBias.xy - clampAmount; // scale relative to full atlas size is in .xy so total texture extent in atlas is (1,1) * scale

    float2 sampleDiffuse = clamp(positionDS.xz * decalData.diffuseScaleBias.xy + decalData.diffuseScaleBias.zw, diffuseMin, diffuseMax);
    float2 sampleDiffuseDdx = positionDSDdx.xz * decalData.diffuseScaleBias.xy; // factor in the atlas scale
    float2 sampleDiffuseDdy = positionDSDdy.xz * decalData.diffuseScaleBias.xy;
    float lodDiffuse = ComputeTextureLOD(sampleDiffuseDdx, sampleDiffuseDdy, _DecalAtlasResolution, 0.5);

    src *= SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, _trilinear_clamp_sampler_DecalAtlas2D, sampleDiffuse, lodDiffuse);
    }

    src.w *= fadeFactor;
    albedoMapBlend = src.w; // diffuse texture alpha affects all other channels

    // Accumulate in dbuffer (mimic what ROP are doing)
    DBuffer0.xyz = (affectFlags & 1) ? src.xyz * src.w + DBuffer0.xyz * (1.0 - src.w) : DBuffer0.xyz; // Albedo
    DBuffer0.w = (affectFlags & 1) ? DBuffer0.w * (1.0 - src.w) : DBuffer0.w; // Albedo alpha

    // Specific to transparent and requested by the artist: use decal alpha if it is higher than transparent alpha
    alpha = max(alpha, albedoMapBlend);
    }

    // Metal/ao/smoothness - 28 -> 1C
    #ifdef DECALS_4RT
    if (affectFlags & 0x1C)
    #else // only smoothness in 3RT mode
    if (affectFlags & 0x10)
    #endif
    {
    float4 src;

    // We use scaleBias value to now if we have init a texture. 0 mean a texture is bound
    bool maskTextureBound = (decalData.maskScaleBias.x > 0) && (decalData.maskScaleBias.y > 0);
    if (maskTextureBound)
    {
    // Caution: We can't compute LOD inside a dynamic loop. The gradient are not accessible.
    float2 maskMin = decalData.maskScaleBias.zw + clampAmount;
    float2 maskMax = decalData.maskScaleBias.zw + decalData.maskScaleBias.xy - clampAmount;

    float2 sampleMask = clamp(positionDS.xz * decalData.maskScaleBias.xy + decalData.maskScaleBias.zw, maskMin, maskMax);

    float2 sampleMaskDdx = positionDSDdx.xz * decalData.maskScaleBias.xy;
    float2 sampleMaskDdy = positionDSDdy.xz * decalData.maskScaleBias.xy;
    float lodMask = ComputeTextureLOD(sampleMaskDdx, sampleMaskDdy, _DecalAtlasResolution, 0.5);

    src = SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, _trilinear_clamp_sampler_DecalAtlas2D, sampleMask, lodMask);
    src.z *= decalData.scalingBAndRemappingM.y; // Blue channel (opacity)
    maskMapBlend *= src.z; // store before overwriting with smoothness
    #ifdef DECALS_4RT
    src.x = lerp(decalData.scalingBAndRemappingM.z, decalData.scalingBAndRemappingM.w, src.x); // Remap Metal
    src.y = lerp(decalData.remappingAOS.x, decalData.remappingAOS.y, src.y); // Remap AO
    #endif
    src.z = lerp(decalData.remappingAOS.z, decalData.remappingAOS.w, src.w); // Remap Smoothness
    }
    else
    {
    src.z = decalData.scalingBAndRemappingM.y; // Blue channel (opacity)
    maskMapBlend *= src.z; // store before overwriting with smoothness
    #ifdef DECALS_4RT
    src.x = decalData.scalingBAndRemappingM.z; // Metal
    src.y = decalData.remappingAOS.x; // AO
    #endif
    src.z = decalData.remappingAOS.z; // Smoothness
    }

    src.w = (decalData.blendParams.y == 1.0) ? maskMapBlend : albedoMapBlend;

    // Accumulate in dbuffer (mimic what ROP are doing)
    #ifdef DECALS_4RT
    DBuffer2.x = (affectFlags & 4) ? src.x * src.w + DBuffer2.x * (1.0 - src.w) : DBuffer2.x; // Metal
    DBuffer3.x = (affectFlags & 4) ? DBuffer3.x * (1.0 - src.w) : DBuffer3.x; // Metal alpha

    DBuffer2.y = (affectFlags & 8) ? src.y * src.w + DBuffer2.y * (1.0 - src.w) : DBuffer2.y; // AO
    DBuffer3.y = (affectFlags & 8) ? DBuffer3.y * (1.0 - src.w) : DBuffer3.y; // AO alpha
    #endif
    DBuffer2.z = (affectFlags & 16) ? src.z * src.w + DBuffer2.z * (1.0 - src.w) : DBuffer2.z; // Smoothness
    DBuffer2.w = (affectFlags & 16) ? DBuffer2.w * (1.0 - src.w) : DBuffer2.w; // Smoothness alpha
    }

    // Normal
    if (affectFlags & 2)
    {
    float3 normalTS;

    // We use scaleBias value to now if we have init a texture. 0 mean a texture is bound
    bool normalTextureBound = (decalData.normalScaleBias.x > 0) && (decalData.normalScaleBias.y > 0);
    if (normalTextureBound)
    {
    // Caution: We can't compute LOD inside a dynamic loop. The gradient are not accessible.
    float2 normalMin = decalData.normalScaleBias.zw + clampAmount;
    float2 normalMax = decalData.normalScaleBias.zw + decalData.normalScaleBias.xy - clampAmount;
    float2 sampleNormal = clamp(positionDS.xz * decalData.normalScaleBias.xy + decalData.normalScaleBias.zw, normalMin, normalMax);
    float2 sampleNormalDdx = positionDSDdx.xz * decalData.normalScaleBias.xy;
    float2 sampleNormalDdy = positionDSDdy.xz * decalData.normalScaleBias.xy;
    float lodNormal = ComputeTextureLOD(sampleNormalDdx, sampleNormalDdy, _DecalAtlasResolution, 0.5);
    normalTS = UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D_LOD(_DecalAtlas2D, _trilinear_clamp_sampler_DecalAtlas2D, sampleNormal, lodNormal));
    }
    else
    {
    normalTS = float3(0.0, 0.0, 1.0);
    }

    float4 src;
    src.xyz = mul((float3x3)decalData.normalToWorld, normalTS) * 0.5 + 0.5; // The " * 0.5 + 0.5" mimic what is happening when calling EncodeIntoDBuffer()
    src.w = (decalData.blendParams.x == 1.0) ? maskMapBlend : albedoMapBlend;

    // Accumulate in dbuffer (mimic what ROP are doing)
    DBuffer1.xyz = src.xyz * src.w + DBuffer1.xyz * (1.0 - src.w);
    DBuffer1.w = DBuffer1.w * (1.0 - src.w);
    }
    }
    }

    #if defined(_SURFACE_TYPE_TRANSPARENT) && defined(HAS_LIGHTLOOP) // forward transparent using clustered decals
    DecalData FetchDecal(uint start, uint i)
    {
    #ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
    int j = FetchIndex(start, i);
    #else
    int j = start + i;
    #endif
    return _DecalDatas[j];
    }

    DecalData FetchDecal(uint index)
    {
    return _DecalDatas[index];
    }
    #endif

    DecalSurfaceData GetDecalSurfaceData(PositionInputs posInput, float3 vtxNormal, inout float alpha)
    {
    #if defined(_SURFACE_TYPE_TRANSPARENT) && defined(HAS_LIGHTLOOP) // forward transparent using clustered decals
    uint decalCount, decalStart;
    DBufferType0 DBuffer0 = float4(0.0, 0.0, 0.0, 1.0);
    DBufferType1 DBuffer1 = float4(0.5, 0.5, 0.5, 1.0);
    DBufferType2 DBuffer2 = float4(0.0, 0.0, 0.0, 1.0);
    #ifdef DECALS_4RT
    DBufferType3 DBuffer3 = float2(1.0, 1.0);
    #else
    float2 DBuffer3 = float2(1.0, 1.0);
    #endif

    #ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
    GetCountAndStart(posInput, LIGHTCATEGORY_DECAL, decalStart, decalCount);

    // Fast path is when we all pixels in a wave are accessing same tile or cluster.
    uint decalStartLane0;
    bool fastPath = IsFastPath(decalStart, decalStartLane0);

    #else // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
    decalCount = _DecalCount;
    decalStart = 0;
    #endif

    float3 positionRWS = posInput.positionWS;

    // get world space ddx/ddy for adjacent pixels to be used later in mipmap lod calculation
    float3 positionRWSDdx = ddx(positionRWS);
    float3 positionRWSDdy = ddy(positionRWS);

    uint decalLayerMask = GetMeshRenderingDecalLayer();

    // Scalarized loop. All decals that are in a tile/cluster touched by any pixel in the wave are loaded (scalar load), only the ones relevant to current thread/pixel are processed.
    // For clarity, the following code will follow the convention: variables starting with s_ are wave uniform (meant for scalar register),
    // v_ are variables that might have different value for each thread in the wave (meant for vector registers).
    // This will perform more loads than it is supposed to, however, the benefits should offset the downside, especially given that decal data accessed should be largely coherent
    // Note that the above is valid only if wave intriniscs are supported.
    uint v_decalListOffset = 0;
    uint v_decalIdx = decalStart;
    while (v_decalListOffset < decalCount)
    {
    #ifndef LIGHTLOOP_DISABLE_TILE_AND_CLUSTER
    v_decalIdx = FetchIndex(decalStart, v_decalListOffset);
    #else
    v_decalIdx = decalStart + v_decalListOffset;
    #endif // LIGHTLOOP_DISABLE_TILE_AND_CLUSTER

    uint s_decalIdx = ScalarizeElementIndex(v_decalIdx, fastPath);
    if (s_decalIdx == -1)
    break;

    DecalData s_decalData = FetchDecal(s_decalIdx);
    bool isRejected = (s_decalData.decalLayerMask & decalLayerMask) == 0;

    // If current scalar and vector decal index match, we process the decal. The v_decalListOffset for current thread is increased.
    // Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
    // end up with a unique v_decalIdx value that is smaller than s_decalIdx hence being stuck in a loop. All the active lanes will not have this problem.
    if (s_decalIdx >= v_decalIdx)
    {
    v_decalListOffset++;
    if (!isRejected)
    EvalDecalMask(posInput, vtxNormal, positionRWSDdx, positionRWSDdy, s_decalData, DBuffer0, DBuffer1, DBuffer2, DBuffer3, alpha);
    }

    }
    #else // Opaque - used DBuffer
    FETCH_DBUFFER(DBuffer, _DBufferTexture, int2(posInput.positionSS.xy));
    #endif

    DecalSurfaceData decalSurfaceData;
    DECODE_FROM_DBUFFER(DBuffer, decalSurfaceData);

    return decalSurfaceData;
    }

    DecalSurfaceData GetDecalSurfaceData(PositionInputs posInput, FragInputs input, inout float alpha)
    {
    float3 vtxNormal = input.tangentToWorld[2];
    DecalSurfaceData decalSurfaceData = GetDecalSurfaceData(posInput, vtxNormal, alpha);

    #ifdef _DOUBLESIDED_ON
    // 'doubleSidedConstants' is float3(-1, -1, -1) in flip mode and float3(1, 1, -1) in mirror mode.
    // It's float3(1, 1, 1) in the none mode.
    float3 flipSign = input.isFrontFace ? float3(1.0, 1.0, 1.0) : _DoubleSidedConstants.xyz;
    decalSurfaceData.normalWS.xyz *= flipSign;
    #endif // _DOUBLESIDED_ON

    return decalSurfaceData;
    }
     
  39. ajmal005

    ajmal005

    Joined:
    Dec 5, 2018
    Posts:
    2
    Shader error in 'Crest/Ocean': undeclared identifier '_DoubleSidedConstants' at hdrp
     
  40. astanid

    astanid

    Joined:
    Apr 5, 2021
    Posts:
    145
    I like this asset but is there any way to combine it with Atmos sky ? i.e I can change daytime/lighting/clouds in atmos dynamically, but ocean always stays the same and ignores ambient lihgting :( upload_2021-7-4_22-36-37.png
     
  41. drsalvation

    drsalvation

    Joined:
    May 2, 2014
    Posts:
    48
    It's a great asset, but I'm wondering how fog works with it, I'm trying to combine it with Unistorm, but the water doesn't seem to be affected by UniStorm's fog at all, so I don't know if this is something I should look into from Crest's shader, or from UniStorm's fog shader