- 목차
Shader
구문
공통 프로퍼티
https://docs.unity3d.com/kr/2019.4/Manual/SL-Properties.html
Shader Property Id 값 예시 (이 값은 기기마다 다르다)
- MainTex : 5
- EnvironmentDepth : 208
- CurrentDepthTexture : 312
- UnityDisplayTransform : 372
- DisplayTransform : 373
- UnityCameraForwardScale : 376
- OcclusionBlendingScale : 377
키워드
Rendering Mode
- Opaque : Default, (불투명) 투명한 영역이 없는 일반 솔리드 오브젝트
- Cutout :
- Transparent : 투명한
- Fade :
Forward rendering
Deferred rendering
-
Albedo : 반사계수
- 일반적인 색상.
- 그림자 연산을 하기 때문에 그림자가 생긴다. (Emission과 반대)
- base (diffuse or specular) color
-
Normal
- tangent space normal, if written
-
HeightMap
+ -
Emission, Emissive : 방사, 방출
- 자체 발광 (조명)
- 그림자 연산을 하지 않는다. (Albedo와 반대)
-
Smoothness : 부드러움, 평탄, 평활도
- 0 : rough (거칠다, 빛 난반사, Diffuse)
- 1 : smooth (부드럽다, 빛 정반사, Specular)
- Metallic, Specular 모두 사용가능 (텍스처 맵이 할당되지 않았을 경우)
-
Ambient Occulusion
- 빛의 차폐로 인한 감쇠 근사치를 구하는 이펙트
- 볼록한 입체는 밝게, 오목하거나 골 파인 곳은 어둡게
(현실에서도 방 구석이 제일 어둡듯이 구석이나 틈 같은 곳에 효과를 줌) - Ambient : 대기, 환경, 주위에, 둘러쌓인
- Metallic, Specular에도 영향
- 어두운 부분의 색을 결정
- Occlusion : 차폐, 폐색
- default 1
-
Alpha : 투명도
- 0 : 투명 / 1 : 불투명
-
Metallic : 금속의
- 0 : 비금속성 / 1 : 금속성
-
Specular : 반사하는, 거울의
- 광원 직접 반사 (Reflection : 광원 간접 반사)
- Highlight와 비슷한 의미
-
Diffuse : 확산하다, 퍼지다
- 물체의 고유색상, 전체적 색상 결정
-
Unlit : 빛이 없는, (전등, 불 등) 켜지지 않은
참고
Shader
Shader type
SurfaceShader
https://docs.unity3d.com/kr/2019.4/Manual/SL-SurfaceShaders.html
광원, 그림자에 큰 영향. Unity에만 있는 녀석(?)이며, Vertex & Fragment Shader를 간략화한 Shader
Vertex & Fragment Shader
광원, 그림자에 영향은 거의 없음
Fixed function Shader
Lagacy shader
Compute Shader
Geometry Shader
Shader code 예시
- 가운데 사각형 그리기
Shader "너님이 원하는 경로/이름"
{
Properties
{
_MainTex ("Mask Texture", 2D) = "black" {}
_TexWidthHalfRatio ("texture width half ratio", Float) = 0.10
_TexHeightHalfRatio ("texture height half ratio", Float) = 0.15
}
// SubShader는 여러개 정의 가능
// 단, 지원되는 SubShader 중 가장 위의 것이 선택된다.
SubShader
{
// Tags
// {
// "RenderType"="Opaque"
// }
Pass
{
Cull Off
ZWrite Off
CGPROGRAM
#pragma target 3.5
#pragma vertex vert // Vertex shader
#pragma fragment frag // Fragment shader
#include "UnityCG.cginc"
//UnityCG.cginc 내부에 선언된 것을 사용해도 된다.
//중요한 것은 뒷부분에 있는 콜른 뒤에 있는 키워드
struct appdata
{
float2 uv : TEXCOORD0;
float4 vertex : POSITION;
};
//Vertex to Fragment
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
//유니티의 머터리얼은 "float4 {텍스쳐이름}_ST" 라는 프로퍼티명으로 Tiling 및 Offset 값을 쉐이더에 전달해준다. 사용하지 않아도 된다.
//float4 _MainTex_ST;
//Vertex shader 함수
v2f vert(appdata input)
{
v2f output;
output.vertex = UnityObjectToClipPos(input.vertex);
//output.uv = TRANSFORM_TEX(input.uv, _MainTex);
output.uv = input.uv;
//Fragment 함수로 간다.
return output;
}
float _TexWidthHalfRatio;
float _TexHeightHalfRatio;
float4 rectangle(v2f IN, float x, float y)
{
//float _RectangleSize = 0.02;
// actual rectangle
float minXOuter = x - _TexWidthHalfRatio;
float maxXOuter = x + _TexWidthHalfRatio;
float minYOuter = y - _TexHeightHalfRatio;
float maxYOuter = y + _TexHeightHalfRatio;
float uvx = IN.uv.x;
float uvy = IN.uv.y;
float4 col = (minXOuter <= uvx && uvx <= maxXOuter && minYOuter <= uvy && uvy <= maxYOuter)
? float4(1, 1, 1, 1) // 흰색
: float4(0, 0, 0, 1);// 검은색
return col;
}
// Fragment shader 함수
float4 frag(v2f i) : SV_Target
{
//fixed4 col = tex2D(_MainTex, i.uv);
float4 col = rectangle(i, 0.5, 0.5);
// 최종 출력(?)
return col;
}
ENDCG
}
}
FallBack Off
}
참고
Unity documentation
RenderTexture
CCTV나 게임 미니맵을 생각하면 된다.
Camera.targetTexture
null인 경우, 카메라가 화면에 렌더링.
null이 아닌 경우, 카메라는 항상 전체 texture로 렌더링을 한다… (사실상 rect, pixelRect는 무시된다.)
https://docs.unity3d.com/ScriptReference/Camera-targetTexture.html
Texture
- Texture2D를 생성한다.
- 캡쳐할 영역 지정한 후, ReadPixel 함수를 호출하여 픽셀을 저장한다.
- 사용한 텍스처를 메모리에서 해제한다.
//
Texture2D screenTex = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
Rect area = new Rect(0f, 0f, Screen.width, Screen.height);
screenTex.ReadPixels(area, 0, 0);
Destroy(screenTex);
// //////////////////////////////////////
// 카메라 화면을 텍스쳐에 렌더링
//렌더 텍스쳐 생성
var renderTextureWidth = Screen.width;
var renderTextureHeight = Screen.height;
RenderTexture cameraRenderTexture = new RenderTexture(renderTextureWidth, renderTextureHeight, 0, RenderTextureFormat.RFloat);
// RenderTexture active는 하나만 가능하다고 하니까 이전 것을 백업
var oldActiveRenderTexture = RenderTexture.active;
RenderTexture.active = cameraRenderTexture;
targetCamera.Render();
// 텍스쳐 생성
var outputTexture2D = new Texture2D(renderTextureWidth, renderTextureHeight, TextureFormat.RFloat, false);
outputTexture2D.ReadPixels(new Rect(0, 0, renderTextureWidth, renderTextureHeight), 0, 0);
outputTexture2D.Apply();
//렌더 텍스쳐 활성화 상태 복원
RenderTexture.active = oldActiveRenderTexture;
- 안드로이드에서 텍스처 포맷 중 R16은 지원하지 않음. 따라서 Android에 빌드를 해야되는 경우 R16은 제외해야됨.
Error Unity Texture creation failed. ‘R16’ is not supported on this platform. Use ‘SystemInfo.SupportsTextureFormat’ C# API to check format support.
반전 (상하)
- 방법 (1) : 배열 (검증 필요…)
/// <summary>
/// 이미지의 위, 아래를 Swap하는 구조
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="data">이미지 byte 배열, Input 및 Output</param>
/// <param name="bytePixel">GrayScale = 1, RGBA32 = 4</param>
public static void ImageFlipY(int width, int height, byte[] data, int bytePixel = 4)
{
int rowSize = width * bytePixel;
byte[] buf = new byte[rowSize];
int heightHalf = height / 2;
for (int y = 0; y < heightHalf; y++)
{
int y2 = height - y - 1;
int p1 = y * rowSize;
int p2 = y2 * rowSize;
Buffer.BlockCopy(data, p1, buf, 0, rowSize);
Buffer.BlockCopy(data, p2, data, p1, rowSize);
Buffer.BlockCopy(buf, 0, data, p2, rowSize);
}
}
- 방법 (2)
카메라의 Projection Matrix에 Matrix4x4.Scale(new Vector3(1, -1, 1))을 곱하면, 카메라는 위아래 반전되어 렌더링된다. 이 상태에서 텍스쳐에 렌더링하면, 위아래 반전된 화면이 텍스쳐로 나온다.
// Projection matrix 변경
camera.projectionMatrix = camera.projectionMatrix * Matrix4x4.Scale(new Vector3(1, -1, 1))
반전 (좌우)
검증 필요…
/// <summary>
/// 이미지의 좌,우 반전
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="src"></param>
/// <returns></returns>
public static Color32[] RawImageReverseFlip(byte[] src)
{
var srcLength = src.Length;
var resultArrayLength = srcLength / 4;
var resultArray = new Color32[resultArrayLength];
for (int i = 0, k = resultArrayLength - 1; i < resultArrayLength; i++, k--)
{
var j = i * 4;
resultArray[k] = new Color32(src[j], src[j + 1], src[j + 2], src[j + 3]);
}
return resultArray;
}
변환 (RGBA32 → RGB24)
// byte array는 texture에서 GetRawTextureData로 가져오면 된다.
// 방법 1 : 알파에 해당되는 부분만 제외하고 다른 배열에 저장
int frameRgba32ByteArrayLength = frameRgba32ByteArray.Length;
var rgb24ByteArray = new byte[frameRgba32ByteArrayLength * 3 / 4];
for (int i = 0, j = 0; i < frameRgba32ByteArrayLength; i += 4, j += 3)
{
rgb24ByteArray[j] = frameRgba32ByteArray[i];
rgb24ByteArray[j + 1] = frameRgba32ByteArray[i + 1];
rgb24ByteArray[j + 2] = frameRgba32ByteArray[i + 2];
}
// 방법 2 : Parallel (필요 없는 작업도 해서 속도는 그닥...)
// 4배수 인덱스를 찾아서 알파에 해당되는 부분만 제외하고 다른 배열에 저장
Parallel.ForEach(Frame_RGBA32_ByteArray, (element, state, i) =>
{
if (i % 4 != 0)
return;
var j = i * 3 / 4;
rgb24ByteArray[j] = Frame_RGBA32_ByteArray[i]; // 0
rgb24ByteArray[j + 1] = Frame_RGBA32_ByteArray[i + 1]; // 1
rgb24ByteArray[j + 2] = Frame_RGBA32_ByteArray[i + 2]; // 2
});
//작업이 끝난후 LoadRawTextureData 함수를 부르면 된다.
// 방법 3 : Pixel 데이터를 가져와 복사
Texture2D resultRGB24Texture = new Texture2D(width, height, TextureFormat.RGB24, false);
var colorArray = RGBA32Texture.GetPixels();
resultRGB24Texture.SetPixels(colorArray);
resultRGB24Texture.Apply();
댓글
댓글 쓰기