CSS에서의 광원 효과

DOM 구성은 다음과 같다.

CSS는 다음과 같다.

body {
  background: #bdcddb;
}

.loader {
  position: relative;
  width: 300px;
  height: 300px;
}

.circle {
  position: absolute;
  inset: 35px;
  background-color: #acbaca;
  border-radius: 50%;
  box-shadow: 5px 5px 15px 0 #152b4a66,
    inset 5px 5px 5px rgba(255,255,255,0.55),
    -6px -6px 10px rgba(255,255,255,1);
}

.circle::before {
  content: '';
  position: absolute;
  inset: 4px;
  background: linear-gradient(#2196f3, #e91e63);
  border-radius: 50%;
  animation: animate 2s linear infinite;
}

@keyframes animate {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(350deg);
  }
}

.circle::after {
  content: '';
  position: absolute;
  inset: 35px;
  background: #acbaca;
  border-radius: 50%;
}

.circle span {
  position: absolute;
  inset: 4px;
  background: linear-gradient(#2196f3, #e91e63);
  border-radius: 50%;
  animation: animate 2s linear infinite;
  filter: blur(20px);
  z-index: 1000;
  /* mix-blend-mode: color-dodge; */
  mix-blend-mode: plus-lighter;
}

.circle span::before {
  content: '';
  position: absolute;
  inset: 40px;
  background: #bdcbdb;
  border-radius: 50%;
  animation: animate 2s linear infinite;
  z-index: 1000;
}

결과는 다음과 같다.

CSS의 67번째 줄이 핵심인데, 만약 해당 코드를 제거하면 결과는 다음과 같다.

mix-blend-mode의 값인 plus-lighter는 아직 공식적으로 문서화가 되지 않았고 만약 작동하지 않는다면 color-dodge를 사용하기 바란다. 참고로 color-dodge보다 plus-lighter가 광원의 표현에 더욱 적합하다.

2개의 모양 함수를 smooth하게 섞는 방법(smooth min/max)

위에서 a와 b는 모양 함수(Shape Function)인데, a와 b의 값에 대한 min 또는 max 값을 취하면 a와 b를 하나로 섞을 수 있다. 그런데 a와 b의 교차점에서 매우 날카롭게 섞이게 되는데, 이를 부드럽게 섞은 것이 세번째 함수의 결과이다. 세번째 함수를 보면 k, h, m으로 구성되는데 이 중 k의 값에 따라 얼마나 부드럽게 섞을 것인지 결정한다. k 값이 음수일때 max 값으로 섞고 양수일때 min 값으로 섞는다.

float smin(float a, float b, float k) {
  float h = clamp(.5 + .5 * (b - a) / k, 0., 1.);
  return mix(b, a, h) - k * h * (1. - h);
}