Reflections in the wrong position

Good afternoon.
I have a GI system using Enlighten, however the reflexes are getting into the wrong positions in relation to the world. I believe it is a problem with some position matrix I am using.

GI:

float3 SampleEnvironment (Surface surfaceWS, BRDF brdf) {
    float3 uvw = reflect(-surfaceWS.viewDirection, surfaceWS.normal);
    float mip = PerceptualRoughnessToMipmapLevel(brdf.perceptualRoughness);
    float4 environment = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, uvw, mip);
    return DecodeHDREnvironment(environment, unity_SpecCube0_HDR);
}

Shader:

struct Attributes {
    float3 positionOS : POSITION;
    float3 normalOS : NORMAL;
    float4 tangentOS : TANGENT;
    float2 baseUV : TEXCOORD0;
    float2 lightmapUV: TEXCOORD1;
    float2 dynamicLightmapUV : TEXCOORD2;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct Varyings {
    float4 positionCS : SV_POSITION;
    float3 positionWS : VAR_POSITION;
    float3 normalWS : VAR_NORMAL;
    float4 tangentWS : VAR_TANGENT;
    float2 baseUV : VAR_BASE_UV;
    //#if defined(LIGHTMAP_ON)
    float2 lightmapUV : TEXCOORD4;
    //#endif
    //#if defined(DYNAMICLIGHTMAP_ON)
        float2 dynamicLightmapUV : TEXCOORD5;
    //#endif
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

Varyings LitPassVertex (Attributes input) {
UNITY_SETUP_INSTANCE_ID(input);
    Varyings output;

    output.lightmapUV = input.lightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;

    output.dynamicLightmapUV = input.dynamicLightmapUV * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;

    output.positionWS = TransformObjectToWorld(input.positionOS);
    output.positionCS = TransformWorldToHClip(output.positionWS);
    output.normalWS = TransformObjectToWorldNormal(input.normalOS);
    output.tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w);
    output.baseUV = input.baseUV;
    return output;
}

Pixel Shader:

float4 NmapSec = SAMPLE_TEXTURE2D(_NormalSecond, sampler_NormalSecond, NormalSecUV);
    float scaleSec = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _NormalSecondStrength);
    float3 normalSec = DecodeNormal(NmapSec, scaleSec);

    water.metallic = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _Metallic);
    water.smoothness = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _Smoothness);

    float3 normal = BlendNormalRNM(normalMain, normalSec);

    water.normal = NormalTangentToWorld(normal, input.normalWS, input.tangentWS);

    water.fresnelStrength = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _Fresnel);
    water.color = lerp(UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _WaterDistanceColor),
        lerp(UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _WaterBaseColor), UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _WaterBlendColor),
            Fresnel(water.fresnelStrength, NormalTangentToWorld(water.normal, input.normalWS, input.tangentWS), normalize(_WorldSpaceCameraPos - input.positionWS))),
            input.baseUV.y);

    water.interpolatedNormal = input.normalWS;
    water.viewDirection = normalize(_WorldSpaceCameraPos - input.positionWS);

I am also having a similar problem with Fresnel.

Those reflections are working as expected. Reflection probe and cube map based reflections are a rough approximation. It’s capturing the world from a specific point in space and using point single point of view that as all of the reflections’ point of view. If the surface doing the reflecting isn’t aligned to the center of the reflection probe it won’t be correct. So basically nothing is going to be showing the correct reflection with reflection probes. It’s usually only good enough that people don’t notice if they aren’t paying attention.

Planar reflections can more accurate handle reflections on a flat surface, like a floor, and are often used to fake reflections on water, but they’re still just an approximation. Even more advanced screen space reflections are just an approximation since it’s common for reflections to see things the main view can’t, but that’s all screen space reflections can show.

The solution is true raytracing, but that’s still expensive, and not supported by Unity outside of the HDRP.

1 Like

OK! Thank you! But what about the fresnel?
6165462--674418--asdf.PNG

float Fresnel(float fresnelStrength, float3 normal,float viewDirection){
return fresnelStrength * Pow4(1.0 - saturate(dot(normal, viewDirection)));
}

What’s the issue with them? Looks about right to me.

I want it like this:

The fresnel effect of the URP adjusts in relation to the camera position.

Okay. What are you currently seeing in your shader? If you’re not seeing something like the above fresnel (or the 1-fresnel) then something your feeding into is wrong. Either the world space normal isn’t correct, or the view direction isn’t, or the view direction needs to be negated. I don’t know what the rest of your code looks like so it’s not like I can debug it.

1 Like

Properties:

    Properties {
     
        _WaterBaseColor("Water Color",Color) = (0, 0, 1, 1)
        _WaterBlendColor("Water Blend Color",Color) = (0, 0, 1, 1)
        _WaterDistanceColor("Water Blend Color",Color) = (0, 0, 1, 1)

        _Normal("Main Wave Normal",2D) = "bump" {}

        _NormalStrength("Normal Strength",Range(0, 1)) = 1
        _NormalSpeed("Normal Speed",Vector) = (0,0,0,0)

        _Metallic("Metallic",Range(0, 1)) = 1
        _Smoothness("Smoothness",Range(0, 1)) = 0.97

        _Fresnel("Fresnel",Range(0, 1)) = 1

        _NormalSecond("Second Wave Normal",2D) = "bump" {}

        _NormalSecondStrength("Second Normal Strength",Range(0, 1)) = 1
        _NormalSecondSpeed("Second Normal Speed",Vector) = (0,0,0,0)


        _Emission("Emission",2D) = "white" {}
  [HDR] _EmissionColor("Emission Color",Color) = (0, 0, 1, 1)

          [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend", Float) = 1
        [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend", Float) = 0
        [Enum(Off, 0, On, 1)] _ZWrite ("Z Write", Float) = 1
UNITY_INSTANCING_BUFFER_START(UnityPerMaterial)
    UNITY_DEFINE_INSTANCED_PROP(float4, _WaterBaseColor)
    UNITY_DEFINE_INSTANCED_PROP(float4, _WaterBlendColor)
    UNITY_DEFINE_INSTANCED_PROP(float4, _WaterDistanceColor)
    UNITY_DEFINE_INSTANCED_PROP(float4, _EmissionColor)
    UNITY_DEFINE_INSTANCED_PROP(float, _NormalStrength)
    UNITY_DEFINE_INSTANCED_PROP(float2, _NormalSpeed)
    UNITY_DEFINE_INSTANCED_PROP(float, _NormalSecondStrength)
    UNITY_DEFINE_INSTANCED_PROP(float2, _NormalSecondSpeed)
    UNITY_DEFINE_INSTANCED_PROP(float, _Metallic)
    UNITY_DEFINE_INSTANCED_PROP(float, _Smoothness)
    UNITY_DEFINE_INSTANCED_PROP(float, _Fresnel)
UNITY_INSTANCING_BUFFER_END(UnityPerMaterial)

struct Water{
    float3 baseColor;
    float3 position;
    float3 normal;
    float3 interpolatedNormal;
    float3 viewDirection;
    float depth;
    float3 tangent;
    float3 binormal;
};

struct Attributes {
    float3 positionOS : POSITION;
    float3 normalOS : NORMAL;
    float4 tangentOS : TANGENT;
    float2 baseUV : TEXCOORD0;
    float2 lightmapUV: TEXCOORD1;
    float2 dynamicLightmapUV : TEXCOORD2;
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct Varyings {
    float4 positionCS : SV_POSITION;
    float3 positionWS : VAR_POSITION;
    float3 normalWS : VAR_NORMAL;
    float4 tangentWS : VAR_TANGENT;
    float2 baseUV : VAR_BASE_UV;
    //#if defined(LIGHTMAP_ON)
    float2 lightmapUV : TEXCOORD4;
    //#endif
    //#if defined(DYNAMICLIGHTMAP_ON)
        float2 dynamicLightmapUV : TEXCOORD5;
    //#endif
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

Vertex Shader:

Varyings LitPassVertex (Attributes input) {
UNITY_SETUP_INSTANCE_ID(input);
    Varyings output;

    output.lightmapUV = input.lightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;

    output.dynamicLightmapUV = input.dynamicLightmapUV * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;

    output.positionWS = TransformObjectToWorld(input.positionOS);
    output.positionCS = TransformWorldToHClip(output.positionWS);
    output.normalWS = TransformObjectToWorldNormal(input.normalOS);
    output.tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w);
    output.baseUV = input.baseUV;
    return output;
}

Pixel Shader:

ViewDir:

water.viewDirection =  normalize(_WorldSpaceCameraPos.xyz - input.positionWS.xyz);

Normal (Pixel Shader):

water.normal = NormalTangentToWorld (normal, input.normalWS, input.tangentWS);

Fresnel + BaseColor:

water.fresnelStrength = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _Fresnel);
    water.color = lerp(UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _WaterDistanceColor),
        lerp(UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _WaterBaseColor), UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _WaterBlendColor),
            Fresnel(water.fresnelStrength, water.normal, water.viewDirection)),
            input.baseUV.y);

Fresnel Function:

float Fresnel(float fresnelStrength, float3 normal,float viewDirection){
return fresnelStrength * Pow4(1.0 - saturate(dot(normal, viewDirection)));
}

The shader is a bit messy, so I just sent the parts of the fresnel .:face_with_spiral_eyes:

6176742--676212--DNS.PNG 6176742--676215--sdfg.PNG

Unfortunately, there’s still not really anything obvious in that code, though I agree the reflections look weird on that plane. That might not be caused by the fresnel itself though. I’d go the route of having your shader explicitly output the fresnel to double check it looks wrong. Then check the world normal; output the world space normal and see if it looks correct and roughly aligns with the world axis.

1 Like

Thank you for your help!
I just discovered the problem.
I put float in ViewDir instead of float3 :face_with_spiral_eyes: kkkkkkkkkkkkkk.

In that Line:

float Fresnel(float fresnelStrength, float3 normal,float <-- viewDirection)
{

6177447--676362--asdf.PNG

Oh, hah! Yeah. It was right there the whole time. I was looking at the code and not the function declaration!