블로그 이미지
자신의 단점을 메꾸는 것을 단(鍛)이라 하고 자신의 강점을 갈고 닦는 것을 련(鍊)이라 하여, 두가지를 합친 것을 단련이라고 부른다. 붕대마음

카테고리

전체목록 (628)
참고사이트 (9)
Goal (3)
Travel (10)
My Life (86)
Game (36)
Game Review (7)
Game Plan (0)
Books (5)
English (1)
Optimizing (11)
Study (209)
유용한 것들_etc (44)
유용한 것들_func (20)
Unity (48)
Unreal (87)
작업장 (45)
RenderMonkey (6)
정리요망 (1)
따라잡기 시리즈 (0)
링크용 (0)
Total288,464
Today21
Yesterday99

1. texture only

v2f vert (appdata_base v)

{

v2f o;

o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

float3 worldN = mul ((float3x3)unity_ObjectToWorld, v.normal);

o.uv = v.texcoord.xy;

o.color = _TintColor;

return o;

}

fixed4 frag (v2f i) : COLOR

{

fixed4 c;

fixed4 tex = tex2D(_MainTex, i.uv) * i.color;

return tex;

}


2. vertex normal

v2f vertn (appdata_base v)

{

v2f o;

o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

o.uv = v.texcoord.xy;


        // directional light이면 _WorldSpaceLightPos0 는 방향벡터(xyz),0(w) 이고 다른 light면 월드공간 위치(xyz), 1(w) 

        // ForwardBase 모드라면 항상 directional 이다. 

        float3 lightDir = UnityWorldSpaceLightDir(worldPosition); // 월드의 현재정점에서 라이트 방향 

        lightDir = normalize(lightDir); float3 worldNormal = mul((float3x3)unity_ObjectToWorld, v.normal); 

        float NdotN = dot(lightDir,worldNormal);

        o.color.rgb = dot(viewNormal, _WorldSpaceLightPos0);

o.color.rgb = o.color * _TintColor;

return o;

}

fixed4 fragn (v2f i) : COLOR

{

fixed4 c;

fixed4 tex = tex2D(_MainTex, i.uv) * i.color;

return tex;

}


3. normal map (월드 행렬에서 계산)

v2fnm vertnm (appdata_tan v)

{

v2fnm o;

o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

float3 worldN = mul ((float3x3)unity_ObjectToWorld, v.normal);

o.uv = v.texcoord.xy;

o.color = _TintColor;


// 월드공간에서 현재 정점으로 향하는 빛 방향 벡터 계산

float4 worldPosition = mul(unity_ObjectToWorld, v.vertex);

float3 lightDir = WorldSpaceLightDir(worldPosition);

o.lightdir = normalize(lightDir);  


// 월드공간 -> 탄젠트 공간

// 정점의 노멀값이 float3라서 전부 float3로 캐스팅

float3 worldNormal = mul((float3x3)unity_ObjectToWorld, v.normal);

float3 worldTangent = mul((float3x3)unity_ObjectToWorld, v.tangent);

float3 binormal = cross(v.normal, v.tangent.xyz); // *input.tangent.w;

float3 worldBinormal = mul((float3x3)unity_ObjectToWorld, binormal);


// and, set them

o.N = normalize(worldNormal);

o.T = normalize(worldTangent);

o.B = normalize(worldBinormal);

return o;

}


fixed4 fragnm (v2fnm input) : COLOR

{

// 탄젠트공간에서의 노멀 벡터.

float3 tangentNormal = tex2D(_NormalMap, input.uv).xyz;

// 텍스처 범위(0~1)을 -1~1로 변환

tangentNormal = normalize(tangentNormal * 2 - 1);


// 'TBN' transforms the world space into a tangent space

// we need its inverse matrix

// Tip : An inverse matrix of orthogonal matrix is its transpose matrix

// 월드 공간에서 탄젠트 공간으로 변환하는 TBN 행렬

// 우리는 탄젠트 공간에서 월드 공간으로 변환이 필요하다.

// 팁 : 직교행렬의 역행렬(inverse)은 그것의 전치행렬(transpose)이다.

float3x3 TBN = float3x3(normalize(input.T), normalize(input.B), normalize(input.N));

TBN = transpose(TBN);


// finally we got a normal vector from the normal map

// 탄젠트 공간 노멀벡터를 월드공간으로 변환.

float3 worldNormal = mul(TBN, tangentNormal);

// 렘버트 연산

float4 albedo = tex2D(_MainTex, input.uv);

float3 lightDir = normalize(input.lightdir);

// diffuse 연산

float3 diffuse = saturate(dot(worldNormal, lightDir));

diffuse = _TintColor * albedo.rgb * diffuse;


// make some ambient,

float3 ambient = float3(0.1f, 0.1f, 0.1f) * 3 * albedo;


// combine all of colors

return float4(ambient + diffuse , 1);

}


4. Local에서 계산

no macro


macro(TANGENT_SPACE_ROTATION)


v2fnm2 vertnm2 (appdata_tan v)

{

v2fnm2 o;

o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

float3 worldN = mul ((float3x3)unity_ObjectToWorld, v.normal);

o.uv = v.texcoord.xy;

o.color = _TintColor;


// 로컬간에서 현재 정점으로 향하는 빛 방향 벡터 계산

float3 lightDir = ObjSpaceLightDir(v.vertex);

// 로컬공간 -> 탄젠트

/* TBN을 계산하기 위해 사용한 정점이 로컬공간상의 값이므로 TBN도 모델공간상의 값.

float3 N = normalize(v.normal);

float3 T = normalize(v.tangent);

float3 B = cross(v.normal, v.tangent.xyz);

float3x3 TBN = float3x3(normalize(T), normalize(B), normalize(N));

o.lightdir = mul(TBN, lightDir);

*/

        // 로컬공간 -> 탄젠트 (매크로 사용)

TANGENT_SPACE_ROTATION;

o.lightdir = mul(rotation, lightDir);

return o;

}


fixed4 fragnm2 (v2fnm input) : COLOR

{

        /*

// 탄젠트공간에서의 노멀 벡터.

float3 tangentNormal = tex2D(_NormalMap, input.uv).xyz;

// 텍스처 범위(0~1)을 -1~1로 변환

tangentNormal = normalize(tangentNormal * 2 - 1);

*/


float3 tangentNormal = UnpackNormal(tex2D(_NormalMap, input.uv)).xyz;

tangentNormal = normalize(tangentNormal);


// 렘버트 연산

float4 albedo = tex2D(_MainTex, input.uv);

float3 lightDir = normalize(input.lightdir);

// diffuse 연산

float3 diffuse = saturate(dot(tangentNormal, lightDir));

diffuse = _TintColor * albedo.rgb * diffuse;


// make some ambient,

float3 ambient = float3(0.1f, 0.1f, 0.1f) * 3 * albedo;


// combine all of colors

return float4(ambient + diffuse , 1);

}


위에서 직접 계산한 결과와 매크로를 사용한 결과가 살짝 다른데 실제로 매크로 내용을 보면 아래와 같다. 

#define TANGENT_SPACE_ROTATION \

float3 binormal = cross( normalize(v.normal), normalize(v.tangent.xyz) ) * v.tangent.w; \

float3x3 rotation = float3x3( v.tangent.xyz, binormal, v.normal )

유니티는 normal과 tangent 사이의 외적 연산으로 다른 표면 벡터(binormal)을 계산하며, 

tangent.w값을 곱해주는데, tangent.w의 값은 항상 1 또는 -1로서 binormal의 방향이다.

(유니티의 uv 좌표 시스템상 dx랑 반대, gpu에 올릴 때 플랫폼에 맞게 -1 또는 1로 지정해서 맞춘다.)

자세한 내용은 아래의 What is tangent.w?를 참조하면 된다.


5. specular map


vertex 연산

float3 viewDir = ObjSpaceViewDir(v.vertex);

..

o.viewdir = mul(rotation, viewDir );


pixel 연산

// 반사, 인자는 입사 광선과 노멀

float3 reflection = reflect(-lightDir, tangentNormal);

float3 viewDir = normalize(input.viewdir);

float3 specular = saturate(dot(reflection, viewDir));

specular = pow(specular, _TintColor.a);

specular *= tex2D(_SpecularMap, input.uv);


처음 작업할 떄는 결과값이 이상하게 나왔는데 이는 reflect 인자의 부호를 잘못 넣은것!

reflect 함수의 인자는 입사광과 normal값이므로 방향에 유의하자.

그리고 만약 노멀맵을 사용하지 않고 정점의 노멀을 사용한다면 specular값 구하는 걸 굳이 

pixel에서 해 줄 필요는 없으며 texture sampling만 pixel에서 해 주면 된다.


6. occlusion map


occlusion map은 ambient의 차폐에 대한 정보를 담은 텍스쳐이다.

오목한 부분이나 옷의 주름은 ambient가 상대적으로 덜 받는데 그 부분을 표현하기 위한 것이다.

계산 방법도 간단한데 텍스쳐 샘플링 후 컬러값에 곱해 주기만 하면 된다.


fragment shader vs standard shader 비교.


혹시 잘못된 부분이 있다면 따끔한 지적 부탁드립니다. ^^a.


Reference Link

- tangent space, 접선공간

normalmap compression

- normal mapping (법선 매핑)

- specular mapping

- 기본적인 반사 벡터


- Tangent space matrix (TBN)

https://unitygem.wordpress.com/shader-part-5/

- unity doc, Mesh.tangents

- What is tangent.w?

- unity doc, Vertex and fragment shader examples

- cg, reflect

- unity doc, Metallic vs Specular 워크 플로우

- unity doc, Specular mode: Specular parameter

- unity doc, Occlusion Map

- bump maps, normal maps, spec maps, ao maps

- GPU Gems, Chapter 17. Ambient Occlusion


backup용.

Shaders.zip


저작자 표시 비영리 변경 금지
신고

'Unity > Unity Graphics' 카테고리의 다른 글

unity shader 30. normal map  (0) 2017.10.08
NGUI의 UIPanel의 속성에 따른 Shader File Name  (0) 2016.10.19
Shader LOD  (0) 2016.09.29
hdr texture를 위한 bc6h  (0) 2016.09.05
Depth and Normal Textures (Part 3)  (0) 2016.07.24
Depth and Normal Texture (Part 2)  (0) 2016.06.13
Posted by 붕대마음

unity의 awake

Unity/Unity Study / 2017.09.24 13:15

script 함수 실행 순서는 awake, onenable, start다. 

이건 알고있던 건데 작업을 하다가 자꾸 awake에 에러가 나서 에러를 찾다보니

하이라키에서 활성화 되어 있는오브젝트에 비활성화로 달려있는 컴포넌트였다.


여기에 붙어있는 컴포넌트의 내용은 아래와 같다.

public class TestAwake : MonoBehaviour 

{

    void Awake()    {        Debug.Log("Awake");    }

    void OnEnable() { Debug.Log("OnEnable"); }

    void Start () {    Debug.Log("Start"); }

    void Update () {  Debug.Log("Update"); }

}


똑같은 상태에서 TestAwake 컴포넌트의 active만 꺼 두면 어떻게 될까?

나의 예상과는 다르게 Awake는 무조건 호출이 된다.


Awake는 컴포넌트의 active 상태와 상관없이 호출이 되고 Start함수는 active 된 상태에서만 호출이 된다.

Awake 함수는 컴포넌트의 스크립트의 활성화 여부에 상관없이 컴포넌트의 오브젝트가 초기화 될 때 호출되기 때문이다.


그래서 위와 같이 컴포넌트의 오브젝트가 비활성화 되어 있으면 초기화가 안되어 컴포넌트 자체의 awake도 호출되지 않는다.





Reference Link

- MonoBehaviour.Awake()

-



저작자 표시 비영리 변경 금지
신고

'Unity > Unity Study' 카테고리의 다른 글

unity의 awake  (0) 2017.09.24
ExecuteInEditMode  (0) 2017.09.13
Inspector에서 AnimationCurve 버그  (0) 2017.07.21
unity에서 shader를 짤때..  (0) 2017.07.10
ARB_precision_hint_fastest  (0) 2017.07.10
RenderQueue  (0) 2017.06.21
Posted by 붕대마음
TAG AWAKE, Unity

작업할때 디자이너분들이 작업하기 편하게 "ExecuteInEditMode"를 자주 쓰는 편인데

어느날 에디터 실행후 종료시에 이상한 에러가 뜬다.

봤더니 에디터 실행 후 종료시에 ExecuteInEditMode 코드가 있는 스크립트의 start 함수가 호출된다.

누가 호출하는걸까..콜백도 없고...

그래서 디버그를 다 찍어서 editor을 실행하니 ExecuteInEditMode 코드가 있는 스크립트에서는


1. 에디터 실행 - script의 OnDestroy 실행, Start 실행

2. 에디터 종료 - script의 OnDestroy 실행, Start 실행


위와 같은 루틴을 탄다.



[ExecuteInEditMode]

public class ExecuteTest : MonoBehaviour {


// Use this for initialization

void Start () {

Debug.Log("Start");

}

// Update is called once per frame

void Update () {

Debug.Log("Update");

}


void OnDestroy()

{

Debug.Log("OnDestroy");

}

}


위 코드를 하이라키에 오브젝트 하나 만들어 add 시킨 후 테스트 해 보면 

아래와 같이 로그가 찍힌다.


에디터 실행..............................................에디터 종료.......................................

OnDestroy -> Start -> Update -> OnDestroy -> Start -> Update



에디터에서만 이렇게 동작하겠지만...

저작자 표시 비영리 변경 금지
신고

'Unity > Unity Study' 카테고리의 다른 글

unity의 awake  (0) 2017.09.24
ExecuteInEditMode  (0) 2017.09.13
Inspector에서 AnimationCurve 버그  (0) 2017.07.21
unity에서 shader를 짤때..  (0) 2017.07.10
ARB_precision_hint_fastest  (0) 2017.07.10
RenderQueue  (0) 2017.06.21
Posted by 붕대마음

최근에 달린 댓글

최근에 받은 트랙백

글 보관함