거의 알고리즘 일기장
react native skia를 이용한 불 이펙트 만들기 본문
정말 오랜만의 글이다!.. 일도 정신없었고 바쁘기도 했어서 정말 간단하게 뭐했는지 정도로 써보겠다.!..
그냥 skia를 이용해서 이런것도 할수있다~ 정도로 이해해주면 좋겠다.
이번에 가져온 주제는 조금 재미있는 주제이다!
바로바로
react native skia의 runtime shader를 이용한 불 이펙트를 만들어 보는것이다! 이게 완료되면 여러가지에 적용해볼수 있다 (outline effect)
(예시들은 다음과 같다.)
자 그럼 ㄱㄱㄱ~
사전지식
아무래도 이런 구현은 shader를 다루기 때문에 sksl을 알고 있거나 혹은 glsl 같은 쉐이더 언어를 알고 있다면, 꽤나 쉬운내용이다. 만약에 모르겠다면, 아래의 문서를 조금 읽으면 이해가 될것이다.
구현
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
이런식으로 unity shader graph로 구현한 graph를 잘보고 그대로 구현하는것도 방법이겠다.
이 기능을 추가한 사이드 프로젝트인 그림일기 링크를 남기며 이만 줄이겠다.
android: https://play.google.com/store/apps/details?id=com.kunwookwon.TodaysPictureDiary
'react-native' 카테고리의 다른 글
react native screen에서 발견한 재미있는 부분 (react native의 native component에서 ui view controller 사용하는 테크닉) (0) | 2024.05.19 |
---|---|
RCTView, RCTText를 직접적으로 사용하면 더 빠르다? (1) | 2024.05.19 |
fastlane ci/cd 환경상에서 실행시 주의할 사항 (react native) (0) | 2023.11.28 |
Monorepo 환경에 react native 추가하기(with turborepo) (0) | 2023.09.20 |
react native에서 android target sdk를 33이상으로 올릴경우 주의할점 (권한 정책 변경으로 인한 문제 해결) (2) | 2023.09.06 |