모름

튜토리얼 소개

튜토리얼 소개영상

*이 게시물은 튜토리얼을 따라하며 과정을 요약하고 정리한 글입니다.

 

이번에 작업할 유니티 프로젝트의 배경이 심해입니다. 심해를 어떻게 표현할 수 있을까요. 찾다보니, 위와같은 튜토리얼이 있어서 참고해보려고합니다.

 

Part1 [Noise Theory]

파트1에서는 기본적인 이론을 학습합니다.

 

튜토1 영상 캡처
튜토1 영상 캡처

기본적인 이론에 대해 설명해주고 있습니다. 제게는 너무 어려운 내용입니다. 대강 "'펄린노이즈'를 이용해서 뭔가를 하겠구나" 라고 이해하고 넘어가겠습니다. 또한 노이즈의 값이 -1~1값으로 출력되는데, 이를 계산하여 뭔가를 하겠구나 예상하겠습니다.

 

펄린 노이즈는 컴퓨터 그래픽에서 다양한 자연주의 텍스처를 만드는데 유용하다고합니다. 구름, 풀, 나무, 돌, 물, 불 등 무수한 다른 질감을 매우 사실적으로 흉내낼수있습니다.

 

그리고 설명 중 테셀레이션(tessellation)이란 용어가 나옵니다. 생소한 영어입니다. 검색해보니 쪽매맞춤이라는 용어로 이해면 될 듯 합니다. 조금 어려운 용어처럼 보이니 아래의 이미지를 참고하여 개념을 숙지해봅니다.

 

테셀레이션을 검색하면 나오는 이미지들

 

그리고 벌틱스(vertices)라는 용어도 종종 나오는데요. 유니티에서 많이 쓰는 용어입니다. 꼭지점들을 의미합니다.

 

Vertex 등등

이상입니다. 아래는 튜토리얼1 영상 자막을 파파고로 번역한 전문입니다.

...더보기

피어 플레이의 수중 세계 쉐이더 튜토리얼 1부에 오신 것을 환영한다.
이 튜토리얼 시리즈에서는 소음 기능을 많이 사용할 것이다.
유니티에서 코딩을 시작하기 전에 소음 기능이 무엇을 하는지 이해하는 것이 중요하다.
이 파트에서 나는 소음이 무엇인지 시각적으로 설명할 것이다.

1985년 켄 펄린은 펄린 노이즈를 발명하였고, 컴퓨터 그래픽과 움직임 모두에 사용되는 표준이 되었다.
Perlin 소음 및 파생 소음의 여러 변환 및 색상 층을 계층화하는 프로세스 
컴퓨터 그래픽에서 다양한 자연주의적이고 혼란스러운 텍스처를 만드는 데 사용된다.
그것은 구름, 풀, 나무, 돌, 물, 불 그리고 무수한 다른 질감을 매우 사실적으로 흉내내는 데 사용될 수 있다.

이것을 시각적으로 설명하기 위해, 이 2D 격자 모양의 정육면체를 봅시다.
큐브는 펄린 노이즈 함수의 출력 값으로 스케일링된다.

펄린 소음이란 이른바 구배 소음으로 의사 난수 구배를 설정한다는 뜻이다.
일정한 간격의 공간에, 그리고 그 지점들 사이에 매끄러운 기능을 보간한다.

즉, X축과 Y축에서 각 점이 주변의 점들과 약간 다르다는 것이다.
2D 펄린 소음을 발생시키는 사이비 코드를 살펴보자.
펄린(x,y) = 플로트

perlin 함수를 호출하고 x와 y 좌표를 입력한다.
송전망은, 그건 새로운 지점이 얼마나 축을 따라 여행하는 것을 지정하는 특정한 증가 값을 사용한다.
우리는 이 증가분을 증가시키거나 감소시킬 수 있으며, 다른 해상도를 볼 수 있다.
시간 경과에 따라 x값을 증가시켜 움직임을 만들 수 있다.

Mathf.Perlin(x + 오프셋X, y + 오프셋Y)
출력 = -1과 1 사이의 부동


노이즈의 출력은 -1과 1 사이에 있다.
Perlin 소음 값의 분포는 중심을 중심으로 집중된다.
따라서 출력 번호는 -1이 될 수 있다. 

이 그래프에서 가장 왼쪽 막대는 -1을, 오른쪽 막대는 +1을 나타낸다.
막대의 높이는 기능에 의해 얼마나 자주 이 숫자를 선택할 것인지를 나타낸다.
그래서 펄린 소음에서는 대부분의 값이 중심을 중심으로 하여 이 기능을 특히 부드럽게 한다.

펄린 소음을 크게 구현하면 이를 혁신에 적용할 수 있다.
자, 여기 큐브 게임 오브젝트가 있다. 이 큐브를 xy&z 축으로 이동시킬 수 있어. 펄린 소음에 근거해서.
3차원도 필요없어. 단순히 노이즈 계산에 더 높은 오프셋을 설정할 수 있으니까.
그리고 우주에서 시간을 따라 더 많은 숫자를 찾아라.

우리는 또한 큐브의 회전에도 적용할 수 있다.
물론 저울도.
그리고 우리가 그것들을 모두 결합할 때, 우리는 펄린 소음에 근거하여 움직이는, 회전하는, 그리고 스케일링 큐브를 할 수 있다.


다시 격자망으로 돌아가자 펄린 소음 외에도 소음의 구현이 더 많다.
이는 Simplex 노이즈로, 값의 균등 분포를 가지고 있어 차이를 보다 가시적으로 만든다.
소음의 또 다른 함축은 셀룰러 노이즈로, 값이 둥글게 되어 독특한 셀을 생성한다.

이제 잡음을 2차원으로 살펴봤지만, 3차원을 추가하면 정말 흥미로운 결과를 얻을 수 있을 겁니다.
정육면체 격자에 3차원을 추가하자.

그리드의 모든 정육면체는 이제 3축의 주변 정육면체의 값을 존중한다.
이제 소음을 X 또는 Y로 이동시키는 대신, 소음을 Z 방향으로 이동시킬 수 있다.

만약 우리가 3D 소음을 2차원 Z축으로 표현한다면, 우리는 물처럼 보이는 움직임들을 볼 수 있다!

 

Part2 [Noise Ground Shader]

이번 차례에선 Plane을 만들고 '물렁물렁(?)' 거리게 만드는 작업을 했습니다.

 

결과물

작업한 주 내용은 아래 코드입니다.

float noise = _NoiseScale * snoise(float3(v.vertex.x + _NoiseOffset.x, v.vertex.y + _NoiseOffset.y, v.vertex.z + _NoiseOffset.z) * _NoiseFrequency);
v.vertex.y += noise;Javascript 

튜토리얼에서 나온 코드를 스탠다드 쉐이더 파일을 만들고 그 안에 그대로 따라쳤습니다. 

 

Part3 [Recalculating Vertex Normals]

말그대로 Vertex Normals를 다시 계산하는 내용인듯합니다.

 

파트3 영상 캡쳐

파트2에서 했던 방식으로는 Vertex Normals 값이 계산이 안된건가? 추측해봅니다. 결과물은 파트2와 같습니다. 계산식이 약간 달라집니다.

 

void vert(inout appdate v)
{
	float3 v0 = v.vertex.xyz;
	float3 v1 = v0 + float3(0.01, 0, 0);
	float3 v2 = v0 + float3(0, 0, 0.01);

	float ns0 = _NoiseScale * snoise(float3(v0.x + _NoiseOffset.x, v0.y + _NoiseOffset.y, v0.z + _NoiseOffset.z) * _NoiseFrequency);
	v0.xyz += ((ns0 + 1) / 2) * v.normal;

	float ns1 = _NoiseScale * snoise(float3(v1.x + _NoiseOffset.x, v1.y + _NoiseOffset.y, v1.z + _NoiseOffset.z) * _NoiseFrequency);
	v1.xyz += ((ns1 + 1) / 2) * v.normal;

	float ns2 = _NoiseScale * snoise(float3(v2.x + _NoiseOffset.x, v2.y + _NoiseOffset.y, v2.z + _NoiseOffset.z) * _NoiseFrequency);
	v2.xyz += ((ns2 + 1) / 2) * v.normal;

	float3 vn = cross(v2 - v0, v1 - v0);

    v.normal = normalize(vn);
	v.vertex.xyz = v0;
}

위와 같은 내용이 추가됐습니다.

 

파트3 결과물

 

아마 이번 파트에선 normal값을 바꿔진 vertex에 맞춰서 다시계산해주고, 빛을 올바르게 반사해주는것까지 표현한듯합니다. 

 

이런 것도 가능합니다

스피어에다가 똑같은 셰이더를 적용하면 이런 표현도 가능합니다.

 

Part 4 - Directional Noise Image Effect

쉐이더 메터리얼에 노말맵을 넣을 공간을 추가합니다.

노말맵 추가
노말맵 추가2
메터리얼 인스펙터에 추가된 Normal Map

쉐이더 파일을 수정하여 Normal Map을 넣었습니다. 

 

텍스쳐와 노말맵을 입힌 모습

대강 에셋스토어에서 무료 에셋을 받아서 텍스쳐와 노말맵을 입혔습니다.

 

그리고 ImageShaderEffect를 추가하여, 메인카메라에 위와같이 이미지를 렌더링(?) 해줬습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode, ImageEffectAllowedInSceneView]
public class UnderwaterEffects : MonoBehaviour
{
    public Material m_Mat;

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        Graphics.Blit(source, destination, m_Mat);
    }
}

메인카메라에 추가한 스크립트입니다. m_Mat에 쉐이더 메터리얼이 추가로 들어갑니다.

 

파트4 결과물

카메라에 흔들리는 쉐이더 효과를 적용했습니다.

 

Part 5 - Camera Depth Fog

몇 가지 코드 수정을 통해 인스펙터 창에서 셰이더 메터리얼을 컨트롤할수있습니다.

셰이더파일

앞서 위와같이 셰이더 파일에 프로퍼티를 적어줬었습니다. 

 

UnderwaterEffects 스크립트

카메라 스크립트에 들어가는 메터리얼 속성의 이름과 동일한 변수를 선언하여 인스펙터 창에서 컨트로할수 있게됩니다. 여기서 처음보는 함수는 OnRenderImage() 입니다.

 

MonoBehaviour에 있는 함수이며, 모든 렌더링이 완료된 후에 호출되는 콜백함수입니다. 포스트 프로세싱 효과를 가집니다. 셰이더 기반의 필터로 처리하여 최종 이미지를 변경합니다.

 

Graphics.Blit()의 설명

그리고 또한 처음보는 함수인 Graphics.Blit()은 소스 텍스쳐를 쉐이더를 이용하여 렌더 텍스쳐야 복사해줍니다. 주로 이미지 이펙트를 구현하는데 사용됩니다.

 

[ExecuteInEditMode, ImageEffectAllowedInSceneView]

그리고 위와 같은 내용도 클래서 바깥에 적혀있는데요. ExecuteInEditMode는 스크립트가 에디터 모드에서 동작하도록 설정해줍니다. 콜백함수들도 마찬가지로 에디터 모드에서 수행됩니다.

 

ImageEffectAllowedInSceneView 이것은 이 속성이 포함된 모든 이미지 효과를 씬뷰 카메라에 렌더링할수있게합니다. 만약 이미지 효과를 씬 뷰 카메라에 적용하려면 이 속성을 추가해야합니다. 효과는 동일한 위치에서 적용되고 카메라에서 나오는 값과 동일한 값이 적용됩니다.

 

이상입니다.