반응형

유니티 스크립트에서는 메터리얼에 담겨 있는 텍스쳐의 다양한 정보를 편집해서 사용할 수 있다.

MainTexture는 maintexture / mainTextureOffset / mainTextureScale  등을 활용하여 크기나 좌표를 편집할 수 있고,

SubTexture들은 String 값을 참조하여 편집할 수 있다.

아래의 코드를 참고하자.

 

m_Renderer.material.mainTextureOffset    = new Vector2(offset.x - ((int)offset.x), offset.y - ((int)offset.y));

m_Renderer.material.SetTextureOffset("_Alpha", offset)//_Alpha 에 담겨 있는 텍스쳐의 좌표를 편집할 수 있다.

m_Renderer.material.mainTextureScale    = m_size;

m_Renderer.material.SetTextureScale("_Alpha", m_size);

반응형
반응형

유니티에서 제공하는 안드로이드용 알파 채널 텍스쳐중 디바이스 호환성이 뛰어난 것은 3가지 밖에 없습니다.

RGBA32 BIT / RGBA 16BIT / ETC2 8BIT

 

ETC 2 8Bit는 아직 디바이스 점유율이 안좋아 사용이 불가한 상황입니다.. 현재 시장에 배포된 디바이스중 50프로는 사용 불가..

(점유율 현황 - https://developer.android.com/about/dashboards/index.html --- Open GL Version 이 2.0인 것들은 지원하지 않습니다.)

 

 

결론적으로 RGBA 16 Bit 와 RGBA 32 Bit 두 종류밖에 쓸 수 없다는 건데..

RGBA 32 Bit 는 무압축 포맷이라 메모리 이슈가 빵빵터져 앱이 계속 죽어 나갈 것이고..(특히 아이폰.. 6도 1기가라는..)

RGBA 16 Bit 는 쓰레기 품질에 압축률도 엉망이라 아트를 볼 줄 아는 사람이 한명이라도 있는 프로젝트에서는 거품 물고 반대할 것이 뻔합니다.

 

1024의 알파 채널이 있는 텍스쳐를 사용하게 될 경우

RGBA 32 Bit의 용량은 4MB

RGBA 16 Bit의 용량은 2MB

 

사이즈가 작은 캐주얼 게임이라면 별 상관없을거 같긴한데.. 대규모  RPG같은 알파 텍스쳐 사용량이 100개 이상 넘어가는 프로젝트라면

너무 큰 클라이언트 용량으로 출시가 힘든 상황이 올수도 있습니다. 특히 중국쪽은 더더욱..

 

 

이런 문제들을 해결하기 위해서 Etc1 4Bit 2장을 이용하면 간단히 해결이 됩니다. 한장은 오파큐텍스쳐로 쓰고 한장은 알파텍스쳐로 쓰면 되지요..

 

1024 텍스쳐의 Etc1 4bit의 용량은 고작 512 KB~~ 2장을 써도 1024 KB~~  쓰레기 품질의 RGBA 16Bit 한장을 쓸때보다도 1/2 용량이라는 어마어마한 이득을 취하면서도 괜찮은 품질을 얻을 수 있습니다.

 

이 방법을 쓰기 위해서는 셰이더를 새로 짜고 텍스쳐 분리 작업을 하고 여러가지 해야할 일거리가 여기저기 터지지만 메모리 이슈로 게임을 출시 못하는 거보다는 낫지 않을까?

 

이방법을 쓸 때 유의 사항.

1. 1드로우였던게 2드로우가 되므로 드로우콜에 유의하자.

2. 알파 채널이 필요한 경우도 반드시 생기므로 알파 채널에 대한 연산 부분도 포함하자.

 

 

아래는 etc1 2장으로 처리할 수 있는 간단한 알파 블렌드 셰이더 코드 입니다.

 

 

Properties    {
        _TintColor ("Tint Color"Color) = (0.5,0.5,0.5,0.5)
        _MainTex ("MainTex"2D) = "white" {}
        _Alpha ("Alpha"2D) = "white" {}
    }

    SubShader {

        Tags {"IgnoreProjector"="True" "Queue"="Transparent" "RenderType"="Transparent"}
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            Blend SrcAlpha OneMinusSrcAlpha
            Cull Off
            ZWrite Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

        uniform sampler2D _MainTex; 
        uniform fixed4 _MainTex_ST;

        uniform sampler2D _Alpha; 
        uniform fixed4 _Alpha_ST;

        uniform fixed4 _TintColor;

        struct v2f 
        {
            fixed4 pos : SV_POSITION;
            fixed2 uv : TEXCOORD0;
            fixed2 uv1 : TEXCOORD1;
            fixed4 color : COLOR;
        };


        v2f vert (appdata_full v) 
        {
            v2f o;

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

            o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
            o.uv1 = TRANSFORM_TEX(v.texcoord, _Alpha);

            return o;
        }

        fixed4 frag(v2f i) : COLOR {
                 fixed4 _MainTex_var =  tex2D(_MainTex,i.uv);
                fixed4 _Alpha_var = tex2D(_Alpha,i.uv1);

                  fixed3 emissive = _MainTex_var.rgb * i.color.rgb;
                  fixed node_9936 = _Alpha_var.r;     

                fixed3 finalColor = emissive * (_TintColor * 2);

                return fixed4(finalColor, (i.color.a * _MainTex_var.a * node_9936));
            }
            ENDCG
        }
    }//SubShader

반응형
반응형

셰이더 코드에서 완전히 빛 연산을 안하도록 만들었는데도

Point Light 연산이 들어가는 것을 보고 경악..

이유는 Albedo 때문이었다는..

Albedo가 아닌 Emmision을 사용하면 해결된다..

이상한 유니티..

반응형
반응형

간단한 서피스 커스텀 셰이더를 만들었는데 알파 값을 0으로 아무리 해도 알파가 안빠지는 현상이 계속됐다.

여러가지 테스트를 해보니 SurfaceOutputCustom 에 Normal 과 Emission 값을 넣어주지 않으면 알파 값이 계속 빠지지 않는 것이다..

#pragme에 keepalpha 문을 넣어주는 것은 당연하고..

 

서피스 셰이더 제작후 알파값이 빠지지 않으면 아래의 세 구문을 꼭 넣어주자.

 

Blend One OneMinusDstAlpha

 

#pragma surface surf keepalpha

 

struct SurfaceOutputCustom
{
      fixed3 Albedo;
      fixed3 Normal;
      fixed3 Emission;
      fixed Alpha;
};

 

반응형
반응형

유니티 서피스 셰이더를 UnLit으로 사용할 때 캐릭터가 하얗게 타는 현상이 발생했다.

Scene안에 라이트가 두개 이상 있을경우 UnLit 서피스 셰이더임에도 캐릭터가 하얗게 타는 것이다..(프라그 셰이더는 발생하지 않음)

해당 문제를 해결하기 위해서는 noforwardadd를 꼭 써줘야 한다.

 

 

#pragma surface surf NoLighting noambient noforwardadd

 

그런데 이렇게 하고나서도 또 타는 현상이 발생했는데, 이 역시 라이트가 두개 있을때 두 라이트가 같은 Layer Culling을 사용하면서

그 사용된 Culling Object가 또 하얗게 타는 것이다... 레이어를 수정해서 해결하긴 했는데.. 뭔가 이상하고 찜찜한 기분..

 

 

아래는 라이트에 영향받지 않는 저 사양 서피스 셰이더 코드이다. 딱 림컬러까지만 처리~

 

 

    SubShader
    {
        LOD 200
        Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
        Lighting off

            CGPROGRAM
            
            #pragma surface surf NoLighting noambient noforwardadd

            //================================================================
            // VARIABLES
            
            fixed4 _Color;
            sampler2D _MainTex;
  
            uniform fixed _IsRim;
            uniform fixed4 _RimColor;
            uniform fixed _RimPower;
   

            struct Input
            {
                half2 uv_MainTex;
                half3 viewDir;
            };
            

            half4 LightingNoLighting (SurfaceOutput s, half3 lightDir, half atten)
            {
               return half4(s.Albedo, s.Alpha);
            }
            
            
            //================================================================
            // SURFACE FUNCTION
            
            void surf (Input IN, inout SurfaceOutput o)
            {
                fixed4 mainTex = tex2D(_MainTex, IN.uv_MainTex);
                fixed rim = (1.0 - saturate(dot(normalize(IN.viewDir), o.Normal)));

                o.Albedo = mainTex.rgb; * Color.rgb;

                o.Alpha = mainTex.a * _Color.a;

                o.Emission = _RimColor.rgb * pow(rim, 1.5 - _RimPower) * _IsRim;

            }
            
            ENDCG

    }

반응형
반응형

유니티의 타임 스케일을 사용할 경우 파티클 애니메이션이 터지는 문제가 종종 발생한다.

이 문제를 해결하기 위해 Time.unscaledDeltaTime 함수를 사용하면 문제를 해결할 수 있다.

타임 스케일을 무시하고 출력되도록 하는 함수다.

 

 

public class UnscaledTimeParticle : MonoBehaviour

{

 // Update is called once per frame

    void Update()

{

if (Time.timeScale < 0.01f)

{

particleSystem.Simulate(Time.unscaledDeltaTime, true, false);

}

}

}

반응형
반응형

import pygame, sys
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((400,300))
pygame.display.set_caption('Hello World!')
while True: #main game loop
    for event in pygame.event.get():
        if even.type == QUIT:
            pygame.quit()
            sys.exit()
    pygame.display.update()

 

 

Python & Pygame 무료온라인북
http://inventwithpython.com/pygame/chapters/
반응형
반응형

프로젝트를 진행하면서 파티클 빌트인 셰이더들이 문제를 일으켜 일괄 변환해 줘야 하는 상황이 발생했습니다.

일일이 바꾸는 번거러움을 덜고자 제작한 스크립트 입니다.

 

 

1. 모바일 엔진 셰이더(바뀌어야할 셰이더 선택)

2. 바뀔 셰이더 선택

3. 대상 메터리얼들 선택(폴더 / 파일)

4. 대상 메터리얼중 1번과 동일 셰이더를 찾아 2번으로 바꿔줌~ 일괄 교체~

 

 

 

 

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;

public class MaterialControl : EditorWindow
{  
    public Shader shader1 = null;
    public Shader shader2 = null;

    public Color defaultColor;
    public Color tintColor = new Color(0.5F, 0.5F, 0.5F, 0.5F);

    Shader defaultShader = null;
    Shader changeShader = null;

    static float UIWidth = 500;
    static string OutputPath = string.Empty;
    
    bool IsError = false;
    List<string> tempPathList = new List<string>();
    List<string> InputPaths = new List<string>();
    
    string SearchPattern = "*.mat;*.*";


//    ShaderImporter texFormatSelected = ShaderImporter.GetAtPath;
//    TextureImporterFormat texFormatToChange = TextureImporterFormat.ETC2_RGBA8;

    [MenuItem("RK Tools/Art/MaterialControl")]
    static void InitWindow()
    {
        MaterialControl window = EditorWindow.GetWindow<MaterialControl>();
        window.position = new Rect(100f, 100f, UIWidth, 400f); //  초기 사이즈
        
        window.title = "Save Bundle";
        window.Show();        
    }
    
    void OnGUI()
    {
        FunctionManual();
        ShaderSetting();
        SelectOutPath();
        ClearSelectFolder();
        OutputSelectedFile();
        ConvertAtlasImage();
    }
    
    void FunctionManual()
    {
        GUILayout.Space(16);
        GUI.contentColor = Color.cyan;
        EditorGUILayout.LabelField("폴더를 선택해서 해당 폴더 내의 Shader를 변경합니다.");
        GUI.contentColor = Color.white;
        GUILayout.Space(8);
    }

    void ShaderSetting()
    {
        defaultShader = (Shader)EditorGUILayout.ObjectField("Original Shader", shader1, typeof(Shader));
        changeShader = (Shader)EditorGUILayout.ObjectField("Change Shader", shader2, typeof(Shader));

        defaultColor = EditorGUILayout.ColorField("Tint Color", tintColor);

        if (defaultShader != null)
        {
            shader1 = defaultShader;
            shader2 = changeShader;
            tintColor = defaultColor;
        }


    }

    string prevPath = Application.dataPath;


    void SelectOutPath()
    {
        if (GUILayout.Button("폴더 or 파일 선택"))
        {            
            GetAssetPath_Project();            
            Repaint();
        }
    }
    
    void GetAssetPath_Project()
    {        
        SelectionProcess();
        
        foreach (string path in tempPathList)
        {
            if (InputPaths.Exists(assetPath => (assetPath == path)))
                continue;
            InputPaths.Add(path);
        }        
        IsError = false;
    }
    
    bool SelectionProcess()
    {
        tempPathList.Clear();
        string AssetPath = string.Empty;
        foreach (UnityEngine.Object obj in Selection.objects)
        {
            AssetPath = AssetDatabase.GetAssetPath(obj);
            if (Directory.Exists(AssetPath))
            {
                tempPathList.AddRange(
                    AssetDatabase.FindAssets("t:Material", new string[] { AssetPath }));
                
                for (int i = 0; i < tempPathList.Count; ++i)
                {
                    tempPathList[i] = AssetDatabase.GUIDToAssetPath(tempPathList[i]);                    
                }
            }
            else if (File.Exists(AssetPath))
            {
                char[] separate = new char[] { ';', '*', '.' };
                foreach (string pattern in SearchPattern.Split(separate))
                {
                    if (AssetPath.ToLower().Contains(pattern))
                    {
                        tempPathList.Add(AssetPath.Replace(Application.dataPath, "Assets"));
                        break;
                    }
                }
            }
        }
        return true;
    }
    
    void ClearSelectFolder()
    {
        if (GUILayout.Button("선택 폴더 or 파일 해제"))
        {
            tempPathList.Clear();
            InputPaths.Clear();
        }
    }
    
    Vector2 scrollPos = new Vector2();
    void OutputSelectedFile()
    {
        EditorGUILayout.LabelField("선택 폴더");
        
        EditorGUILayout.BeginVertical("box", GUILayout.Width(UIWidth));
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Width(UIWidth));
        
        foreach (string path in InputPaths)
        {
            EditorGUILayout.LabelField(path);
        }
        EditorGUILayout.EndScrollView();
        EditorGUILayout.EndVertical();
    }
    
    
    void ConvertAtlasImage()
    {        
        EditorGUILayout.BeginHorizontal();

        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginVertical("box", GUILayout.Width(UIWidth));

        if(GUILayout.Button("선택된 메터리얼을 Change Shader로 변환"))
        {
            ChangeShaderToTargetMaterial();
        }
        EditorGUILayout.EndVertical ();
    }


    void ChangeShaderToTargetMaterial()
    {
        foreach (string path in InputPaths)
        {
            AssetDatabase.ImportAsset(path);

            Material material = (Material)AssetDatabase.LoadMainAssetAtPath(path);


            if (material.shader == shader1)
            {
                material.shader = shader2;

                material.SetColor("_TintColor", tintColor);
            }         
        }
    }
}

반응형
반응형

게임을 제작할때 메인 전투씬이 있고 그 곳에 배경씬을 로드되는 식으로 제작될 때가 있습니다.

이때의 문제점이 각각의 배경마다의 포그값이나 후처리 값을 가지고 갈 수 없는 문제점이 있습니다.

 

 

 

 

그럴 때 로드될 배경씬에 포그값 정보에 대한 것을 스크리트로 처리하게 되면 사용이 가능해 집니다.

 

 

1. 스크립트 제작

 

using UnityEngine;
using System.Collections;

public class RK_Fog : MonoBehaviour {

    public bool isFogOnOff = false;

    public Color RkFogColor;

    public enum RkFogMode : int
    {
        Linear = 0,
        Expotential = 1,
        ExpotentialSquared = 2,
    }

    public RkFogMode RkFogModeEnum;

    public float LinearStart = 0.0f;
    public float LinearEnd = 10.0f;

    public float ExpotentialDensity = 0.01f;


    // Use this for initialization
    void Start () {

        if (isFogOnOff == true) {
            RenderSettings.fog = true;
            RenderSettings.fogColor = RkFogColor;

            if ((int)RkFogModeEnum == 0) {
                RenderSettings.fogMode = FogMode.Linear;
                RenderSettings.fogStartDistance = LinearStart;
                RenderSettings.fogEndDistance = LinearEnd;
            }
            if ((int)RkFogModeEnum == 1) {
                RenderSettings.fogMode = FogMode.Exponential;
                RenderSettings.fogDensity = ExpotentialDensity;
            }
            if ((int)RkFogModeEnum == 2) {
                RenderSettings.fogMode = FogMode.ExponentialSquared;
                RenderSettings.fogDensity = ExpotentialDensity;
            }

        } else {
            RenderSettings.fog = false;
        }    
    }
    
    // Update is called once per frame
    void Update () {
    
    }
}

 

 

2. 제작 된 스크립트를 씬에 오브젝트를 만들어 배치합니다.

 

 

 

 

반응형
반응형

카메라에 사용된 후처리(Post Processor / Image Effect)를 키로 제어할 수 있게 되면 다양하게 활용이 가능합니다.

 

캐릭터가 강력한 스킬을 쓸때에 블룸효과를 강하게 준다던지, 컷씬을 제작할때 순간적으로 화면을 어둡게 한다던지.

막타연출에서 모션블러나 라디알 효과등을 원하는 타이밍에 쓰기 위해서 애니메이션으로 후처리를 제어하는 방식이

가장 편하고 좋습니다.

 

또한 씬 전환 트랜지션상황에서도 유용하게 사용이 가능합니다.

 

 

1. 카메라에 다양한 후처리 적용하기

- 먼저 카메라에 사용될 다양한 후처리들을 적용하고, 비활성화 시킵니다.

- 라디알블러, 비네팅, 블룸등을 적용시켰습니다.

 

 

 

2. 스크립트 제작하기

- 카메라에 적용된 후처리들을 파싱하여 사용할 수 있도록 스크립트를 제작합니다.

- 사용된 카메라와 카메라에 사용된 후처리 스크립트를 제어하는 코드입니다.

- Animated_PostProcessor 란 이름으로 제작했습니다.

 

using UnityEngine;
using System.Collections;

public class Animated_PostProcessor : MonoBehaviour
{
    public GameObject PostProcessorCtr;  
    public RK_RadialBlur RadialBlurScript;  
    public bool isRadialBlurScript = false;
    [Range(0.0f, 5.0f)]
    public float RadialBlurStrength = 2.2f;
    [Range(0.0f, 3.0f)]
    public float RadialBlurWidth = 0.5f;


    public RK_ScreenOverlay ScreenOverlayScript
    public bool isScreenOverlayScript = false;
    [Range(0.0f, 1.0f)]
    public float ScreenOverlayintensity = 1.0f;
    public enum OverlayBlendMode2 : int
    {
        Additive = 0,
        ScreenBlend = 1,
        Multiply = 2,
        Overlay = 3,
        AlphaBlend = 4,
    }
    public OverlayBlendMode2 ScreenOverlayblendMode;

    public RK_Vignette VignetteScript;
    public bool isVignetteScript = false;
    [Range(-1.0f, 1.0f)]
    public float Vignetteintensity = 0.25f; 


    public Rk_Bloom BloomScript;
    public bool isBloomScript = false;
    [Range(0.0f, 1.5f)]
    public float BloomScriptthreshold = 0.5f;
    [Range(0.0f, 2.5f)]
    public float BloomScriptintensity = 1.0f;


    void OnEnable ()
    {
        PostProcessorCtr = GameObject.Find("PostProcessorCam");
        RadialBlurScript = PostProcessorCtr.GetComponent<RK_RadialBlur>();
        ScreenOverlayScript = PostProcessorCtr.GetComponent<RK_ScreenOverlay>();
        VignetteScript = PostProcessorCtr.GetComponent<RK_Vignette>();
        BloomScript = PostProcessorCtr.GetComponent<Rk_Bloom>();

        LateUpdate();
    }

    void LateUpdate()
    {
        //라디알 블러 처리
        if (isRadialBlurScript == true) {
            RadialBlurScript.enabled = true;
        } 
        else {
            RadialBlurScript.enabled = false;
        }
        RadialBlurScript.blurStrength = RadialBlurStrength;
        RadialBlurScript.blurWidth = RadialBlurWidth;


        //스크린 오버 레이
        if (isScreenOverlayScript == true) {
            ScreenOverlayScript.enabled = true;
        } 
        else {
            ScreenOverlayScript.enabled = false;
        }
        ScreenOverlayScript.intensity = ScreenOverlayintensity;

        if ((int)ScreenOverlayblendMode == 0) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.Additive;
        }
        if ((int)ScreenOverlayblendMode == 1) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.ScreenBlend;
        }
        if ((int)ScreenOverlayblendMode == 2) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.Multiply;
        }
        if ((int)ScreenOverlayblendMode == 3) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.Overlay;
        }
        if ((int)ScreenOverlayblendMode == 4) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.AlphaBlend;
        }


        //비네팅 처리
        if (isVignetteScript == true) {
            VignetteScript.enabled = true;
        } 
        else {
            VignetteScript.enabled = false;
        }
        VignetteScript.intensity = Vignetteintensity;


        //블룸 처리
        if (isBloomScript == true) {
            BloomScript.enabled = true;
        } 
        else {
            BloomScript.enabled = false;
        }
        BloomScript.intensity = BloomScriptintensity;
        BloomScript.threshold = BloomScriptthreshold;

    }
}

 

 

 

3. 후처리를 제어할 오브젝트나 파티클에 스크립트와 애니메이션을 붙힙니다.

 

 

 

 

4. 애니메이션으로 후처리 효과들을 제어합니다.

 

 

 

 

5. 완료 테스트 영상

 

 

반응형
반응형

외적 연산(Cross Product)란?

- 임의의 두 벡터와 직교를 이루는 벡터

EX) Cross(A , B)란? A가 B 를 감싸는 형태가 될때 직교가 되는 벡터

- 오른손 손가락 두개를 피고 검지를 A라 하고 중지를 B라 했을때, 왼손 끝을 오른손 검지에 반대로 맞닿고 감싸쥐는 형태

 

EX) Cross(B, A)란? B가 A를 감싸는 형태가 될때 두 벡터와 직교가 되는 벡터

- 왼손을 중지에 맞닿고 감싸쥐는 형태 

 

- 문제 풀이

임의의 두 벡터 A[5,2,3] B[8,1,-4]의 외적을 구해보자. Cross A B를 구해보자.

A x B = [(a2b3 - a3b2) (a3b1 - a1b3) (a1b2 - a2b1)]

계산 순서가 헷갈릴땐 아래 그림을 참고하여 순서를 기억하자.

 

=[((2x -4) - (-3 x 1))  ((-3 x 8) - (5 x -4))  ((5 x 1) - (2 x 8))

= [-5 . -4  ,  -11]

Cross A B 의결과는 [-5 -4 -11] 이라는 새로운 벡터이다. 

 

- 외적의 결과로 두 벡터 사이의 각도도 알 수 있게 된다.

내적으로 코사인을 알수 있게 됬다면 외적으로는 사인 각도를 알 수 있다.

||A X B|| = ||A|| ||B|| sin

먼저 A X B 의 크기와 ||A||  ||B||를 각각 구합니다. 다시 말해 Cross A B 의 크기를 구한다.

||A X B|| =

 ||A|| =

||B|| =

위에서 구한 값을 공식에 대입한다.

||A X B|| = ||A|| ||B|| sin

 

0.23 = sin

sin -1(0.23) = 13.2971

 

 

 

 

- 외적을 알면 어디에 도움이 될까?

EX) 나와 적의 위치를 알때 직교하는 UPVector를 알수 있도록 해준다. 그것이 UpVector가 될수도 있고,  RightVector가 될수도 있기에 상당히 유용하게 사용할 수 있게 된다.

 

 

 

EX) 폴리곤의 법선 벡터 정보를 알려준다.

폴리곤의 직교되는 법선 벡터정보를 알게 되면서 라이트 정보라든지 오브젝트 충돌등에 유용하게 사용할수 있다. 

     

 

 

반응형
반응형

유니티 스크립트에서는 기본적으로 쿼터니언을 제공한다.

스크립트 에디터에서 Quternion을 치고 F12를 누르면~ 

 

쿼터니언에 관련된 다양한 함수를 확인할 수 있다.

 

 

이중 SetLookRotation을 활용하면 편리하게 룩앳 함수를 만들수 있다.

 

using UnityEngine;
using System.Collections;

public class NewBehaviourScript : MonoBehaviour {

 [SerializeField] private GameObject targetObj;

 void Start () { 
 }


 void Update () {
  lookTarget(); 
 }

 void lookTarget()
 {
  Quaternion lookAt = Quaternion.identity;    // Querternion 함수 선언
  Vector3 lookatVec = (targetObj.transform.position - transform.position).normalized; //타겟 위치 - 자신 위치 -> 노멀라이즈
  lookAt .SetLookRotation (lookatVec);  // 쿼터니언의 SetLookRotaion 함수 적용
  transform.rotation = lookAt ;   //최종적으로 Quternion  적용
 }
}

위와 같이 코딩을 하고 바라볼 타겟 오브젝트를 지정해 주면 아래처럼 작동하는 룩앳함수가 완성된다.

 

 

 

 

반응형
반응형

내적(Dot Product)이란?

-      정규화된

한 벡터가 다른 벡터에 투영된 길이 값을 나타낸다.Ex) Dot(A , B) ? BA위치로 회전했을 때 투영되어 직교되는 위치만큼의 크기 값

 

EX2) Dot(B,A)는?

    

 

 

각 벡터를 Normalize한 후의 스칼라 곱의 결과값이며 그 값은 두 벡터의 코사인의 값과 일치한다. 그러므로 음수 인지 양수 인지 그리고 각도의 크기 값도 알아 낼 수 있다.

 

 

1.    먼저 3D맥스상에서 임의좌표를 가지는 두 개의 벡터를 만든다.

C = [5 , 2, -3]

D = [8, 1, -4]

    

2.    먼저 AB의 크기를 구한다.

 

3.    벡터의 크기 값을 활용하여 정규화(Normalize)를 한다.

 

||Normalize A|| = 1 이어야 한다! 

||Normalize B|| = 1 이어야 한다!

 

 

4.    두 벡터의 내적  A

B 을 구해 보자

A B = a1b1 + a2b2 + a3b3

= [(0.811 x 0.889) + (0.32 x 0.11) + (-0.487 x -0.444)]

= 0.72 + 0.035 + 0.216

= 0.971

 

 

 

5.    이제 내적의 결과값으로 여러가지 결과를 도출할 수 있게 됬음.

         내적의 결과 값으로 알게 된 결론은?

Dot(A,

B) > 0이면

 세타 값은 90도 이하

이므로 BA로부터 90도 각도 안에 있음을 알게 됐다.

 

è

이 결과는 게임로직에서 상당히 많이 사용될수 있다. A가 카메라이고 B가 오브젝트일경우 내적의 결과값이 양수라는 것은 BA의 시야안에 들어옴을 의미하고, 음수라는 것은 BA의 시야안에 들어오지 않음을 의미한다.

 

è

이 결과값을 토대로 디렉셔널 라이트와 오브젝트의 법선 벡터를 고려 했을 때 오브젝트가 빛을 얼마만큼 받고 있는지도 알 수 있게 됐다.

 

A가 디렉셔널 라이트이고 B가 법선 벡터를 가지고 있는 오브젝트라고 했을 때

 

이 정도의 빛을 받는 오브젝트임을 알 수 있다.

 

하지만, Dot(A, B)  = 1이라고 한다면

복사량이 최대치가 되어 가장 많은 빛을 받는 상황이 된다. 12시에 떠있는 태양이라고 생각하면 이해가 빠를 듯~

 

Dot(A, B) 

= 0이라면..

빛을 전혀 받지 않는 연산임을 알 수 있게 됐다. 12시가 되겠다.

 

 

코사인 각도와 노멀라이즈 된 내적의 각도 값은 일치하므로              코사인 각도는 맥스의 Listner 창을 활용해서 쉽게 알 수 있다.

          

           두 벡터 사이의 각도가 13.832도 라는 사실도 알게 됐다.

 

내적연산은 가볍다보니 셰이더 프로그램이나 물리 스크립트 에서도 굉장히 자주 쓰이는 기본적인 연산입니다~^^

 

 

 

Cg언어에 내장된 기본적인 Dot 공식- 두 벡터에 대해 -1 ~ 1 범위의 float 값을 얻을 수 있다. -1은 평행하며 나에게서 멀어지는 벡터, 1은 평행하며 나를 향해 다가오는 벡터, 0은 나와 완전히 수직인 벡터를 의미한다.

 

 

 

 

위에서 힘들게 구한 공식을 맥스 리스너(Max Listner)에서 쉽게 확인 할 수 있다.

 

 

반응형
반응형

참고  -http://book.naver.com/bookdb/book_detail.nhn?bid=7525807

 

Properties 개념 익히기

-       셰이더 프로그래머가 직접 규격에 맞춰 GUI 요소를 셰이더 코드에 빠르게 추가할 수 있다. Properties 블록에서 선언한 프로퍼티는 셰이더 코드에서 값, 색상, 그리고 텍스쳐를 변경하는 데 사용할 수 있다.

           Properties

           {

                     _EmissiveColor ("Emissive Color", Color) = (1,1,1,1)

                     _AmbientColor ("Ambient Color" , Range(0,10)) = 2

                     _MySliderValue ("This is a Slider", Range(0,10)) = 2.5

           //         변수 이름          인스펙터GUI이름   타입      기본값

           }

 

프로퍼티 타입 정리

Range(min, max)

최솟값부터 최댓값까지의 범위를 float프로퍼티의 슬라이더를 만든다.

Color

Inspector탭에 Color =(float , float, float, float)를 선택할 수 있는 색상 견본을 만든다.

2D

셰이더로 드래그할 수 있는 텍스쳐 견본을 만든다.

Rect

2의 승수가 아닌 텍스쳐 견본을 만든다. 2D GUI 요소와 같은 기능을 한다.

Cube

Inspector 탭에서 셰이더로 드래그할 수 있는 큐브맵(cube map) 견본을 만든다.

Float

Inspector 탭에 슬라이더가 아닌 float 값을 만든다.

Vector

방향, 색상을 만들 수 있는 4개의 float 프로퍼티를 만든다.

 

 

 

http://docs.unity3d.com/Manual/SL-Properties.html

 

SubShader 개념 익히기

_EmissiveColor , _AmbientColor, _MySliderValue 값을 SubShader{}에서 사용하기 위해서는 프로퍼티의 변수 이름과 똑 같은 이름으로 새로운 변수 3개를 만들어야 한다. 이렇게 하면 동일한 데이터로 작업할 수 있도록, 기존 변수와 새 변수 사이에 자동으로 링크를 설정한다.

                     float4 _EmissiveColor;

                     float4 _AmbientColor;

                     float _MySliderValue;

 

Surf 개념 익히기

SubShader 에서 변수를 만들면, surf{} 함수에서 값을 사용할 수 있다.

c = pow((_EmissiveColor + _AmbientColor), _MySliderValue);  

 

Properties , SubShader , Surf에 대한 세 가지 개념만 확립하면 디퓨즈 컴퍼넌트를 요구하는 셰이더를 만들기 위한 기반이 확립된다.

 

 

세 가지의 기본적인 사항을 파악하고 아래의 코드를 작성하면 기본적인 셰이더를 만들 수 있다.

Shader "Custom/BasicShader" {

Properties

 {

  _EmissiveColor ("Emissive Color", Color) = (1,1,1,1)

  _AmbientColor ("Ambient Color" , Color) = (1,1,1,1)

 _MySliderValue ("This is a Slider", Range(0,10)) = 2.5

 }

SubShader {

 Tags { "RenderType"="Opaque" }

LOD 200

                    

 CGPROGRAM

#pragma surface surf Lambert

 

float4 _EmissiveColor;

float4 _AmbientColor;

float _MySliderValue;

 

 struct Input {

                  float2 uv_MainTex;

                 };

 

 void surf (Input IN, inout SurfaceOutput o) {

 float4 c;

c = pow((_EmissiveColor + _AmbientColor), _MySliderValue);                               

 o.Albedo = c.rgb;

 o.Alpha = c.a;

 }

ENDCG

 }

 FallBack "Diffuse"

}

 

반응형
반응형

최근 한 대학에서 온라인 강의를 진행했습니다.

진행한 내용중 3DMAX를 활용하여 짐벌락을 설명하는 내용입니다. 

 

 

반응형
반응형

회사 디지이너들과 프로그래머들에게 물리기반 셰이더(PBS)에 대한 이해를 돕고자 진행항 PPT

 일시 : 2015년 7월 14일 대회의실

 

참고자료 -[Ndc13]Ndc 2013 김동석:UDK로 물리기반 셰이더 만들기

 http://www.slideshare.net/jalnaga/ndc13ndc-2013-udk-19999169

반응형
반응형

 

 사장님께서 각 팀 팀장들에게 모바일 게임 최적화에 대한 교육 요청을 해주셔서 진행한 PPT입니다.

일시 : 2015년 12월 7일 대회의실

 

 

참고 자료

[데브루키/141206 박민근] 유니티 최적화 테크닉 총정리

http://www.slideshare.net/agebreak/unite2015-47100325?related=1

 

유니티 그래픽 최적화, 어디까지 해봤니

http://www.slideshare.net/ozlael/graphics-opt-ndc?related=2

반응형
반응형

 

 

 

 

 

반응형

'Study' 카테고리의 다른 글

PYTHON 기본 창 띄우기 "Hello World!"  (0) 2016.06.24
외적 연산(Cross Product) 쉽게 이해하기  (0) 2015.12.31
내적 연산(Dot Product) 쉽게 이해하기  (2) 2015.12.30
삼각비의 기본  (0) 2015.12.18
반응형

대부분 삼각함수라고 하지만, 중3에 나오는 삼각비에 가까운 내용이기에 삼각비의 기본이라고 쓰겠습니다. 

 

 

반응형
반응형

빌드 테스트 중에 씬에러 발생으로 빌드를 못하다가 여러가지 뒤져서 알아낸 결과

Bulid Setting - > Player Setting 으로 들어가서

Stripping Level을 Disabled로 변경하자 빌드가 되었다~

원인은 분석중..

 

참고 사이트 - http://westwoodforever.blogspot.kr/2014/02/unityexception-failed-assemblies.html

 

 

반응형

+ Recent posts