페이지

2013년 1월 23일 수요일

Generic Tuple in C# without .NET 4.0

Unity3D에서 Tuple을 사용해보려니 .Net 2.0 에서는 지원이 안된다.

그래서 직접 만들어보기로 함..

namespace를 내 이름으로 하고 사용하니 왠지 기분이 좋아졌다~ (이런 뵨태기질;;)

어쨋든~! Tuple은 여러가지 데이터형을 순열로 사용할때 정말 유용한거 같다.

앞으로 자주 사용할 듯~ (아래 코드의 안전성은 보장 못함...)



// Generic Tuple

using System;
using System.Collections.Generic;

namespace Claire
{  
    public class Tuple<T1, T2>
    {
        public T1 First { get; private set; }
        public T2 Second { get; private set; }
        internal Tuple(T1 first, T2 second)
        {
            First = first;
            Second = second;
        }
    }

    public class Tuple<T1, T2, T3>
    {
        public T1 First { get; private set; }
        public T2 Second { get; private set; }
        public T3 Third { get; private set; }
        internal Tuple(T1 first, T2 second, T3 third)
        {
            First = first;
            Second = second;
            Third = third;
        }
    }

    public static class Tuple
    {
        public static Tuple<T1, T2> Create<T1, T2>(T1 first, T2 second)
        {
            var tuple = new Tuple<T1, T2>(first, second);
            return tuple;
        }

        public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 first, T2 second, T3 third)
        {
            var tuple = new Tuple<T1, T2, T3>(first, second, third);
            return tuple;
        }
    }
}


// how to use

using Claire;

Tuple<int , float , string > doSomthing()
{
     Tuple< int, float, string> tuple = new Tuple< int, float, string>(8, 0.5f, "hello");
     return tuple;
}

void Example () {

        Tuple< int, float, string> tuple = doSomthing();

        var item1 = tuple.First;
        var item2 = tuple.Second;
        var item3 = tuple.Third;
}

2013년 1월 2일 수요일

Unity3D: Texture를 돌리고 돌리고~

이 글은 제 전 티스토리 블로그에서 옮겨 왔습니다.


2D 텍스쳐를 어떻게 돌릴까?
현재 Unity3D의 기본 GUI는  GUIUtility.RotateAroundPivot 함수로 GUI를 회전시킬수가 있다. 하지만 OnGUI()함수 자체가 이벤트 발생시에만 호출되기 때문에 실시간 Rotation Animation을 표현하기엔 부족하다.

그래서 직접 2D Texture Mesh를 생성해서 Texture을 회전 시켜봤다.
Material 회전 시키는 코드는 완전 초간단하다. Unity Documents 에서 Material.SetMatrix() 함수에 대한 예제를 참고하면 된다. 여기

위에 링크에서 부족한 부분은 Texture의 Alpha처리 부분이 없다는 것이다. 이 부분은 Unity3D 내장 쉐이더인 Unlit-Alpha.shader 코드를 참고하면 된다. Light의 적용을 받을 필요없는 2D Texture를 위한 것이다.

이제 남은 문제는 회전이 되는 Texture의 Pivot이 맞지 않는다는 것이다. 내가 원하는 것은 중점을 기준으로 돌고 도는 텍스처이기 때문... 원점을 기준으로 도는 텍스쳐를 원한다면 위에 코드로 충분할지도...

여기서 먼저 Unity엔진의 UV좌표를 이해해야 한다. 일반적으로 다른 엔진에서의 UV좌표는 아래와 같다.



하지만 Unity3D의 UV좌표는 좀 다르다. (왜 그런지는 나도 모르겠음;;;)
그래서 텍스쳐의 좌표계를 생각해 UV를 맞춘다면 낭패다. Unity의 UV좌표계는 아래와 같기 때문이다.



여튼 좌표계가 저따위니 적절하게 UV를 이동한 후 Material에서 position을 offset 만큼 이동시켜 회전시키면 된다.
(일단 다른 방법은 잘 몰라 이렇게 했음..-_-;;)


보통 Sprite Animation을 할때 기준점으로 부터 이미지 사이즈만큼 Frame별로 그려주면서 Animation을 하는데 그걸 이용하면 간단하게 이동시킬 수 있다.

여기서 Mesh에 직접 접근하기 위해 MeshFilter와 MeshRenderer를 생성하고 몇가지 설정을 한다.
view source
print?
1.mesh_renderer.castShadows = false;
2.mesh_renderer.receiveShadows = false;
3.mesh_renderer.sharedMaterial = material; // 회전시킬 material 설정

그리고 2D 텍스쳐를 찍어줄 카메라로 부터 해상도 값을 계산해 온다. (화면 높이값 적용)
view source
print?
1.float pixelPerWorldUnit = Camera.mainCamera.orthographicSize * 2 / defCameraPixels;




생성한 mesh의 vertices값에 이를 곱해 해상도를 적용시켜 줄 수 있다. 마지막으로 offset이 적용된 uv값을 아까 좌표계에 맞게 설정해주면 끝!! 이 아니고;;; 생성한 최종 메쉬를 Mesh Filter에 적용시켜줘야 끝난다.
view source
print?
01.mesh.vertices = new Vector3[] {
02.new Vector3(0, -texHeight) * pixelPerWorldUnit,
03.new Vector3(0, 0) * pixelPerWorldUnit,
04.new Vector3(texWidth, -texHeight) * pixelPerWorldUnit,
05.new Vector3(texWidth, 0) * pixelPerWorldUnit
06.};
07. 
08.mesh.triangles = new int[] { 0, 1, 3, 0, 3, 2 };
09. 
10.// Assign the basis of the uv coordinate to the uv of texture
11.mesh.uv = new Vector2[] {
12.new Vector2(topLeft.x, topLeft.y),
13.new Vector2(topLeft.x, topLeft.y + 1f),
14.new Vector2(topLeft.x + 1f, topLeft.y),
15.new Vector2(topLeft.x + 1f, topLeft.y + 1f)
16.};
17. 
18.mesh.Optimize();
19.mesh.RecalculateNormals();
20.mesh.RecalculateBounds();
21.meshFilter.sharedMesh = mesh;





Unity Editor에서의 설정 모습은 아래와 같다.




offset 을 (-0.5, -0.5) 로 설정한 이유는 아까 Unity의 UV좌표계가 왼쪽 아래부터 (0, 0) 좌표이기 때문이다. 더 간단한 방법이 있는지는 나도 모르겠지만 일단은 이렇게 하는걸로~-_-ㅋ