본문 바로가기

DX

fresnel 효과

fresnel 효과?
빛이 물체 표면에 닿을 때, 시야각(=입사각)에 따라 반사되는 빛의 양이 달라지는 현상
 
 
 
아래 사진을보면 멀리 있는 수면 위에는 나무가 그려진다. 가까이 있는 수면 그러니까 시선과 수직에 가까운 수면에는 물고기가 그려진다. 이것이 fresnel 효과이다.

 
이 효과를 적용할 때 일단은 빛의 굴절은 적용하지 않는 것으로 한다.
fresnel 함수를 보면 물질의 고유 특성과 노멀 값, eye pos 로 구현한다. 픽셀로 시선과 노멀을 내적으로 해서 가까운지 멀리있는지에 따라 값을 바꾸도록 f0 를 만든다.
return 에서 내적의 결과에 따라 가까울수록 물체의 고유 성질 fresnelR0 만 적용하고 멀리 있으면 f0 값이 더욱 많이 적용되도록 한다. 

float3 SchlickFresnel(float3 fresnelR0, float3 normal, float3 toEye)
{
    // 참고 자료들
    // THE SCHLICK FRESNEL APPROXIMATION by Zander Majercik, NVIDIA
    // http://psgraphics.blogspot.com/2020/03/fresnel-equations-schlick-approximation.html
    
    float normalDotView = saturate(dot(normal, toEye));

    float f0 = 1.0f - normalDotView; // 90도이면 f0 = 1, 0도이면 f0 = 0

    // 1.0 보다 작은 값은 여러 번 곱하면 더 작은 값이 됩니다.
    // 0도 -> f0 = 0 -> fresnelR0 반환
    // 90도 -> f0 = 1.0 -> float3(1.0) 반환
    // 0도에 가까운 가장자리는 Specular 색상, 90도에 가까운 안쪽은 고유 색상(fresnelR0)
    return fresnelR0 + (1.0f - fresnelR0) * pow(f0, 5.0);
}

 
위의 fresnel 값을 specular 에 곱해주면 0~1 사이로 나오게 되고 더해주면 끝.

  float4 diffuse = g_diffuseCube.Sample(g_sampler, input.normalWorld);
  float4 specular = g_specularCube.Sample(g_sampler, reflect(-toEye, input.normalWorld));
  
  diffuse *= float4(material.diffuse, 1.0);
  specular *= pow((specular.r + specular.g + specular.b)/3.0, material.shininess);
  specular *= float4(material.specular, 1.0);
  
  // 참고: https://www.shadertoy.com/view/lscBW4
  float3 f = SchlickFresnel(material.fresnelR0, input.normalWorld, toEye);
  specular.xyz *= f;
  
  if (useTexture) {
      diffuse *= g_texture0.Sample(g_sampler, input.texcoord);
      // Specular texture를 별도로 사용할 수도 있습니다.
  }
  
  return diffuse + specular;

 
 
결과를 보면 배경의 흰색 조명이 구체의 주변 그러니까 시선의 먼 부분에는 더 많이 적용되고 가장 중심부 가까운 부분은 거의 IBL 이 적용되지 않는다.

 
 
 
 
 
 
 
 
 
 
 
 
 
 

'DX' 카테고리의 다른 글

Bloom Filter 와 Post-Processing 정리  (0) 2025.07.13
Post Processing  (0) 2025.07.13
이미지 기반 라이팅  (0) 2025.07.13
환경 매핑(반사 매핑)  (0) 2025.07.13
큐브 매핑  (0) 2025.07.13