거의 알고리즘 일기장

react native skia를 이용한 불 이펙트 만들기 본문

react-native

react native skia를 이용한 불 이펙트 만들기

건우권 2025. 1. 5. 20:59

정말 오랜만의 글이다!.. 일도 정신없었고 바쁘기도 했어서 정말 간단하게 뭐했는지 정도로 써보겠다.!..

그냥 skia를 이용해서 이런것도 할수있다~ 정도로 이해해주면 좋겠다.

 

이번에 가져온 주제는 조금 재미있는 주제이다!

바로바로

 

react native skia의 runtime shader를 이용한 불 이펙트를 만들어 보는것이다! 이게 완료되면 여러가지에 적용해볼수 있다 (outline effect)

 

(예시들은 다음과 같다.)

 

불 이펙트

 

오늘의 그림일기에 들어간 Outline 불 이펙트

자 그럼 ㄱㄱㄱ~


사전지식

아무래도 이런 구현은 shader를 다루기 때문에 sksl을 알고 있거나 혹은 glsl 같은 쉐이더 언어를 알고 있다면, 꽤나 쉬운내용이다. 만약에 모르겠다면, 아래의 문서를 조금 읽으면 이해가 될것이다.

https://thebookofshaders.com/

 

The Book of Shaders

Gentle step-by-step guide through the abstract and complex universe of Fragment Shaders.

thebookofshaders.com

 

구현

1. 불이펙트 구현

 

불 이펙트는 어떻게 구현할수 있을까?? 사실 너무 여러가지 구현방법이 있다.. 그 중에서 그냥 내가 구현한 방식을 설명하겠다.

 

순서를 나눈다면 다음과 같다.

 

1. 불효과에 쓸만한 texture를 구한다. (혹은 함수로 구현도 가능하다.. 하지만 그냥 texture 구하는게 편하다)

2. 하나의 texture를 두가지 종류로 tiling한다. (texture 하나로 여러가지 텍스쳐를 사용하는 것처럼 만들기 위해서 사용) rn skia에서 구현하기 까다로워서 안함. 그리고 안해도 그러저럭 괜찮아 보임.

3. 각각 scrolling 한다. (이때, 2번에서 만든 여러가지 noise를 서로 다른 방향으로 (나같은 경우는 불이 좌하단에서 우상단, 우하단에서 좌상단 방향으로 설정했다. 이거는 그냥 노가다로 값바꿔가면서 그럴듯한 효과를 만듬)

4. 각각의 픽셀값을 뽑는다.

5. 결합한다. (multiply)

 

아래는 해당 내용을 구하는 쉐이더이다.

const testShader = Skia.RuntimeEffect.Make(`
  uniform shader fireTexture;
  uniform float u_outline_distance;
  uniform float u_imageResolution;
  uniform float u_time;
  uniform vec2 u_tileScale_1;        // 텍스처 타일링 스케일 1
  uniform vec2 u_tileScale_2;     // 텍스처 타일링 스케일 2
  uniform float u_intensity;
  uniform float u_threshold; // 임계값, 이 값이상 올라오면 smooth step 함수 적용
  uniform float u_threshold_intensity; // 임계값 관련 강도 조절
  
  vec4 main(vec2 coord) {
    // 1. 이 친구는 texture의 좌표를 벗어나지 않는 한에서의 좌표
    vec2 noiseCoord_1 = coord + vec2(u_time * 0.5, u_time * 1);
    vec2 noiseCoord_2 = coord + vec2(u_time * 0.3, u_time * 0.5);
    
    // 2. mod 함수를 사용해서 텍스처 좌표를 벗어나지 않는 한에서의 좌표로 변환
    float noiseCoordX_1 = mod(noiseCoord_1.x, u_imageResolution);
    float noiseCoordY_1 = mod(noiseCoord_1.y, u_imageResolution);
    float noiseCoordX_2 = mod(noiseCoord_2.x, u_imageResolution);
    float noiseCoordY_2 = mod(noiseCoord_2.y, u_imageResolution);
    noiseCoord_1 = vec2(noiseCoordX_1, noiseCoordY_1);
    noiseCoord_2 = vec2(noiseCoordX_2, noiseCoordY_2);

    // 3. 텍스처 샘플링
    vec4 val1 = fireTexture.eval(noiseCoord_1);
    vec4 val2 = fireTexture.eval(noiseCoord_2);

    // 4. Multiply로 두 노이즈 결합
    vec4 combined = mix(val1, val2, u_intensity);

    // 결과 조합
    return combined;
  }
`)!;

//... in skia canvas 
        <Fill>
          <Shader source={testShader} uniforms={uniforms}>
            <ImageShader image={fireTexture} />
          </Shader>
        </Fill>
//...

 

이 쉐이더를 넣으면 위에 첫번째로 첨부했던 영상처럼 불효과가 나타난다.

 

2. 불의 경계를 만드려면?

불의 경계를 만들고 싶을수 있다. 이때는 정말 쉬운방법이 하나 있는데, sksl에서 기본제공하는 함수인 smoothstep을 이용하는 방법이다.

 

smooth step은 말그대로 min, max 사이를 부드럽게 보간하는 방법이다.

위키에서 퍼옴

 

코드로는 다음과 같다. 이 코드를 위에 있는 shader 코드에 4~ 결과조합에 적절히 붙여넣으면 된다.

    // y가 임계값 이상이면 서서히 없어지는 효과
    float threshold = u_threshold * u_imageResolution;
    float edgeValue = smoothstep(threshold, u_imageResolution, coord.y);

    // 결과 조합
    return combined * edgeValue;

 

---


주말동안에 Poc하고 이 기능을 내 그림일기앱에 적용해보았다.

 

이 기능 넣으려고 키우기류 요소까지 넣느라 피똥 쌀뻔했다.. (생각보다 구현이 많더라~)

 

새벽이라 조금 다 생략하고 적었는데, 찬찬히 보면 별거없다~ 만약에 정말 모르겠다면,

https://realtimevfx.com/t/simple-fire-shader-breakdown/11213

 

Simple Fire Shader Breakdown

Hey everyone! I’m Aka and this is my very first post here. I was playing around with this simple fire shader and was very happy with the result, so I figured I should share my process to get some feedback and hopefully help someone who’s starting out.

realtimevfx.com

이런식으로 unity shader graph로 구현한 graph를 잘보고 그대로 구현하는것도 방법이겠다.

 

이 기능을 추가한 사이드 프로젝트인 그림일기 링크를 남기며 이만 줄이겠다.

 

ios: https://apps.apple.com/kr/app/%EC%98%A4%EB%8A%98%EC%9D%98-%EA%B7%B8%EB%A6%BC%EC%9D%BC%EA%B8%B0/id1603506813

 

‎오늘의 그림일기: 그림으로 표현하는 하루

‎오늘의 그림일기는 그림일기 작성, 관리 및 공유를 위한 어플리케이션입니다. 직관적이고 사용하기 쉬운 UI로 구성되어, 누구나 손쉽게 그림일기를 만들고 관리할 수 있습니다. 1. 그림일기 작

apps.apple.com

android: https://play.google.com/store/apps/details?id=com.kunwookwon.TodaysPictureDiary

 

오늘의 그림일기: 그림으로 표현하는 하루 - Google Play 앱

간편하게 그림일기를 작성, 관리 및 공유할 수 있는 일기앱!

play.google.com

 

 

반응형
Comments