Get it on Google Play


Wm뮤 :: 'Unity' 카테고리의 글 목록 (2 Page)

블로그 이미지
가끔 그림그리거나 3D모델링하거나
취미로 로봇만드는
전자과 게임프로그래머 (퇴사함)
2022.3.22f1 주로 사용
모카쨩
@Ahzkwid

Recent Comment

Archive


2024. 4. 18. 15:40 Unity/C#

 

 

 

https://ahzkwid.booth.pm/items/5632873

 

Automatic Shadow Distance - Wmup - BOOTH

ワールド用です DirectionalLightの影の長さをFPSに応じて自動的に変更するツールです。 動きがきれいじゃないので、キャラクターシャドウ専用に使用するのをお勧めします - Code - https://gist.githu

ahzkwid.booth.pm

여기서 다운 가능

 

 

 

 

 

using UdonSharp;
using UnityEngine;
using UnityEngine.UI;
using VRC.SDKBase;
using VRC.Udon;

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class AutomaticShadowDistance : UdonSharpBehaviour
{
    public Light directionalLight;
    public float frameCheckTimeCycle = 3f;
    int playerLayerIndex = 9;
    public Vector2 targetFps = new Vector2(30, 60);
    public Vector2 defaultShadowDistance = new Vector2(10, 80);
    public Vector2 playerShadowDistance = new Vector2(1,15);

    float tPre = 2;

    void UpdateShadowDistance(float t)
    {
        var defaultShadowDistanceMin = defaultShadowDistance.x;
        var defaultShadowDistanceMax = defaultShadowDistance.y;
        var playerShadowDistanceMin = playerShadowDistance.x;
        var playerShadowDistanceMax = playerShadowDistance.y;


        var targetDistanceDefault = Mathf.Lerp(defaultShadowDistanceMin, defaultShadowDistanceMax, t);
        var targetDistancePlayer = Mathf.Lerp(playerShadowDistanceMin, playerShadowDistanceMax, t);
        
        {
            //QualitySettings.shadowDistance = targetDistanceDefault;
        }
        {
            var ShadowCullDistances = new float[32];
            //ShadowCullDistances[0] = Mathf.Lerp(ShadowCullDistances[0], targetDistanceDefault, 0.1f);
            ShadowCullDistances[0] = targetDistanceDefault;
            ShadowCullDistances[11] = ShadowCullDistances[0];
            ShadowCullDistances[13] = ShadowCullDistances[0];
            ShadowCullDistances[14] = ShadowCullDistances[0];
            ShadowCullDistances[playerLayerIndex] = targetDistancePlayer;
            ShadowCullDistances[10] = ShadowCullDistances[playerLayerIndex];
            ShadowCullDistances[18] = ShadowCullDistances[playerLayerIndex];
            directionalLight.layerShadowCullDistances = ShadowCullDistances;

            //Camera.main.layerCullDistances = ShadowCullDistances;
        }
    }

    LightShadows shadowType = LightShadows.Soft;
    void Start()
    {
        //if (directionalLight==null)
        //{
        //    /*
        //    var lights = FindObjectsOfType<Light>();
        //    foreach (var light in lights)
        //    {
        //        if (light.type==LightType.Directional)
        //        {
        //            directionalLight = light;
        //        }
        //    }
        //    */
        //    /*
        //    var light= FindObjectOfType<Light>();
        //    if (light.type == LightType.Directional)
        //    {
        //        directionalLight = light;
        //    }
        //    */
        //}
        if (directionalLight.shadows != LightShadows.None)
        {
            shadowType = directionalLight.shadows;
        }

        UpdateShadowDistance(0);

        lastCheckTime = 0;
    }
    float lastCheckTime = 0;
    int frameCount = 0;

    public Toggle toggle;
    public Slider slider;
    public GameObject lockPanel;

    public bool alwaysUseShdow = true;
    bool CheckT(float t)
    {
        return ((Mathf.Abs(t - tPre) > 0.1f)
            || ((t == 0) && (tPre < 0.1f))
            || ((t == 1) && (tPre > 0.9f)));
    }
    void Update()
    {
        var useShadowOff = !alwaysUseShdow;

        var toggleManual = toggle;
        lockPanel.SetActive(toggleManual.isOn == false);



        var useShadowOffvalue = 0.1f;
        if (toggleManual.isOn)
        {
            if (slider.value > useShadowOffvalue)
            {
                var t = (slider.value - useShadowOffvalue) * (1f / (1f- useShadowOffvalue));
                if (CheckT(t))
                {
                    UpdateShadowDistance(t);
                    tPre = t;
                }
                if (useShadowOff)
                {
                    if (directionalLight.shadows == LightShadows.None)
                    {
                        directionalLight.shadows = shadowType;
                    }
                }
            }
            else
            {
                if (useShadowOff)
                {
                    if (directionalLight.shadows != LightShadows.None)
                    {
                        directionalLight.shadows = LightShadows.None;
                    }
                }
            }
        }
        else
        {


            frameCount++;

            if (Time.time - lastCheckTime >= frameCheckTimeCycle)
            {
                var fps = 0f;
                if (Time.deltaTime > 0)
                {
                    fps = 1f / Time.deltaTime;
                }
                if (frameCheckTimeCycle > 0.1f)
                {
                    fps = frameCount / frameCheckTimeCycle;
                }


                var min = targetFps.x;
                var max = targetFps.y;
                var t = (Mathf.Clamp(fps, min, max) - min) / (max - min);

                /*
                if ((Mathf.Abs(t - tPre) > 0.1f)
                    || ((t == 0) && (tPre < 0.1f))
                    || ((t == 1) && (tPre > 0.9f)))
                */
                if (CheckT(t))
                {

                    UpdateShadowDistance(t);
                    tPre = t;

                }


                if (Time.time > 10)
                {
                    if (useShadowOff)
                    {
                        if (directionalLight.shadows == LightShadows.None)
                        {
                            if (t > 0.8f)
                            {
                                directionalLight.shadows = shadowType;
                            }
                        }
                        else
                        {
                            if (fps < min / 2)
                            {
                                directionalLight.shadows = LightShadows.None;
                            }
                        }
                    }
                }
                if (directionalLight.shadows == LightShadows.None)
                {
                    slider.value = 0f;
                }
                else
                {
                    slider.value = useShadowOffvalue + t * (1f- useShadowOffvalue);
                }


                frameCount = 0;
                lastCheckTime = Time.time;
            }
        }
    }
}

'Unity > C#' 카테고리의 다른 글

유니티 프리팹 드래그 드랍  (0) 2024.05.09
c# Dictionary(딕셔너리) 관련  (0) 2024.03.19
자주 쓰는 DateTime 코드 모음  (0) 2023.12.19
posted by 모카쨩
2024. 4. 16. 23:27 Unity

Assembly Definition Asset
네임스페이스 폴더같은 기능이다

 

에셋을 팔다보니 내가 만든 툴들 동봉해야 하는경우 많았는데 버전충돌 방지하려고 서로 다른 네임스페이스 넣는건 좋았는데 하나하나 일일히 넣으려니 ㅈㄴ 귀찮았다

 

 

 

 

이렇게 하면 파일별로 네임스페이스 수정 안 하고 저거 두개만 수정하면 된다

 

 

 

 

 

 

 

 

 

 

 

그외

define 제약을 걸필요가 있을때

 

걸고 새로고침 돌리면 된다

위 내용은 Unity 2021.1부터 사용가능하게 한다는 제약

유니티 버그인지 저거 하고 어플라이해도 새로고침전까지 에러메세지가 뜬다

에러메세지 떠도 적용은 잘 된거니 걱정말자

적용예시 : https://github.com/ahzkwid/BoothSupport/issues/10

 

 

 

 

using VRC.SDK3A.Editor;

그런데 이렇게 외부에 Assembly Definition이 적용된 클래스를 참조하려 할경우

 

Assets\Ahzkwid\AvatarTools\VRCTools\Editor\VRCBuildProcessor.cs(4,11): 
error CS0234: The type or namespace name 'SDK3A' does not exist
in the namespace 'VRC' (are you missing an assembly reference?)

 

이렇게 미싱이 떠버리는데

 


잘 찾아서 연결하면 된다

경우에 따라 GUID 참조는 안 쓰는게 좋을수도 있다

 

그런데 이렇게 해도 빌드후 업로드시에 미싱이 뜰수도 있다

에디터 함수일경우에 에디터모드가 풀리면서 그런건데

당연히 나는 폴더로 구분해놓으면 괜찮을줄 알았다
그런데 이거 왜인지 이경우에는 동작 안 하더라

#if UNITY_EDITOR

 

위 코드를 넣어서 전처리로 해결해야 한다

 

 

 

 

 

그리고 Root Namespace란은 딱히 안 넣어도 된다

 

 

 

 

 

 

 

 

 

'Unity' 카테고리의 다른 글

LTCGI  (0) 2024.09.06
게임개발용 부하테스트 2024  (0) 2024.02.27
유니티 모델 임포트 에러  (0) 2024.02.24
posted by 모카쨩
2024. 3. 19. 01:48 Unity/C#

 

ClassList to Dictionary

아래의 경우에는 중복되는 userCode의 경우 price를 전부 병합하여 생성한다

왜냐면 Dictionary는 동일키생성을 허용하지 않기 때문이다

 

v1

더보기
var dictionary = classList.GroupBy(x => x.userCode).ToDictionary(x=>x.First().userCode, x=>x.Sum(x=>x.price));

v2

var dictionary = groups.ToDictionary(x => x.Key, x => x.ToList());

 

 

 

Dictionary Sort

//오름차순 정렬
dictionary=dictionary.OrderBy(x => x.Value).ToDictionary(x=>x.Key, x => x.Value); //오름차순 정렬
 
//내림차순 정렬
dictionary=dictionary.OrderByDescending(x => x.Value).ToDictionary(x=>x.Key, x => x.Value); //내림차순 정렬

 

 

슬라이스

{
    //슬라이스(길이만큼 자르기)
    var length = 3;
    dictionary = dictionary.Take(length).ToDictionary(x => x.Key, x => x.Value);
}

 

 

중복제거

단 Dictionary는 원래 중복 Key를 허용하지 않기 때문에 Value만 가능하다

dictionary = dictionary.GroupBy(x => x.Value).Select(x => x.First()).ToDictionary(x => x.Key, x => x.Value); //중복제거

 

 

 

FindIndex

순위를 매길때 사용했다

var rank = dictionary.Keys.ToList().FindIndex(x => x == id);

 

 

Insert

중간에 넣기 전에 동일키를 지우고 넣는다

var item = dictionary.ElementAt(index);
dictionary.Remove(item.Key);
var list = dictionary.ToList();
list.Insert(length - 1, item);
dictionary = list.ToDictionary(x=>x.Key, x => x.Value);

'Unity > C#' 카테고리의 다른 글

AutomaticShadowDistance  (0) 2024.04.18
자주 쓰는 DateTime 코드 모음  (0) 2023.12.19
Path 연산  (0) 2023.09.09
posted by 모카쨩
2024. 2. 27. 10:06 Unity

 

 

 

 

-테스트 환경-

CPU : 라이젠 5 1600

메모리 : 32GB 1333Mhz

GPU : RTX 3050 8GB

 

 

 

-사용 코드-

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

public class DrawCallTest : MonoBehaviour
{

    int stopCount = 100;
    public int wantFPS = 60;
    List<GameObject> gameObjects = new List<GameObject>();
    public Renderer renderTarget;
    // Start is called before the first frame update
    void Start()
    {
        renderTarget.gameObject.SetActive(false);
    }
    float preTime = 0;
    // Update is called once per frame
    void Update()
    {
        if (Time.time>3)
        {
            if (stopCount<=0)
            {
                return;
            }
            if (Time.deltaTime > 1f / wantFPS)
            {
                stopCount--;
            }
            else
            {
            }
            stopCount=Mathf.Clamp(stopCount, 0, 10);
            var wid = (int)Mathf.Sqrt(gameObjects.Count+1);
            for (int i = 0; i < 10; i++)
            {
                var instance = Instantiate(renderTarget.gameObject);

                instance.SetActive(true);
                gameObjects.Add(instance);
            }
        }
    }
}

 

 

-사용된 fbx 파일 -

98306.fbx
0.02MB
393218.fbx
0.04MB
1572866.fbx
0.10MB
6291458.fbx
0.35MB

 

언릿쉐이더로 진행

 

 

 

드로우콜 테스트

목표치 60fps일경우 6152

 

 

 

 

목표치 144fps일경우 1112

 

 

 

 

 

 

 

 

 

 

 

 

목표치 60fps일경우 38.3M Tris

 

 

 

 

목표치 144fps일경우 12.3M Tris

 

 

 

2020에 970으로 쟀을때보다 성능이 많이 좋아졌다

 

그리고 3050은 최약체라서 목표치를 60으로 잡으면 충분할것 같다

 

주의점은 위에서 테스트된건 스킨드메쉬가 아니라 메쉬렌더러라서 버텍스 영향을 좀 덜 받으니

버텍스같은 경우에는 5M 초과하지 않도록 여유분을 주자

드로우 콜의 경우에는 내부 CPU 로직이 많으면 떨어지는 경향이 있으니

로직이 복잡한 게임이라면 여유분을 더 크게주고, 결국 어떤 게임을 만드느냐에 따라서도 영향이 있으니까 알아서 판단

 

 

 

 

-그외

텍스처 메모리와 성능과의 연관성

https://wmmu.tistory.com/entry/%ED%85%8D%EC%8A%A4%EC%B2%98-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%99%80-%EC%84%B1%EB%8A%A5%EA%B3%BC%EC%9D%98-%EC%97%B0%EA%B4%80%EC%84%B1

 

텍스처 메모리와 성능과의 연관성

사용된 코드 using System.Collections; using System.Collections.Generic; using UnityEngine; public class TextureMemoryTest : MonoBehaviour { public Renderer renderTarget; public Texture[] textures; public int max = 800; public bool useTexture = false;

wmmu.tistory.com

 

 

 

 

 

 

 

'Unity' 카테고리의 다른 글

유니티 Assembly Definition Asset  (0) 2024.04.16
유니티 모델 임포트 에러  (0) 2024.02.24
매트캡 생성하기  (0) 2024.01.18
posted by 모카쨩
2024. 2. 24. 07:07 Unity

 

 


ImportFBX Warnings:
Can't generate normals for blendshape 'BreastsSmall' on mesh 'Shirt', mesh has no smoothing groups.Can't generate normals for blendshape 'Breasts_big' on mesh 'Shirt', mesh has no smoothing groups.Can't generate normals for blendshape 'Breasts_normal' on mesh 'Shirt', mesh has no smoothing groups.Can't generate normals for blendshape 'Chira' on mesh 'Shirt', mesh has no smoothing groups.Can't generate normals for blendshape 'Hutomomo' on mesh 'Shorts', mesh has no smoothing groups.Can't generate normals for blendshape 'Length' on mesh 'Shorts', mesh has no smoothing groups.Can't generate normals for blendshape 'MoveY' on mesh 'Hairpin', mesh has no smoothing groups.Can't generate normals for blendshape 'MoveYm' on mesh 'Hairpin', mesh has no smoothing groups.Can't generate normals for blendshape 'MoveZ' on mesh 'Hairpin', mesh has no smoothing groups.Can't generate normals for blendshape 'MoveZm' on mesh 'Hairpin', mesh has no smoothing groups.Can't generate normals for blendshape 'SleeveLeft' on mesh 'Shirt', mesh has no smoothing groups.Can't generate normals for blendshape 'SleeveRight' on mesh 'Shirt', mesh has no smoothing groups.Can't generate normals for blendshape 'UseBra' on mesh 'Shirt', mesh has no smoothing groups.
(Filename: C:\build\output\unity\unity\Modules\AssetPipelineEditor\Public\ModelImporting\FBXImporter.cpp Line: 383)

 

 

 

작동엔 이상없으니 스킵했다

 

 

 

보다시피 Shirt 오류인데

 

 

 

당연히 블렌더상에서는 전혀 이상없다

 

 

 

먼저 쉐이프키를 다 지우니까 안 뜬다

즉 쉐이프키 오류다

 

 

'Unity' 카테고리의 다른 글

게임개발용 부하테스트 2024  (0) 2024.02.27
매트캡 생성하기  (0) 2024.01.18
에셋스토어 업로드 거부사례 모음  (0) 2023.11.27
posted by 모카쨩
2024. 1. 18. 13:59 Unity

 

Matcap

일반 쉐이더 라이팅과 달리 이미 구워진 정보를 쓰므로 비교적 균일하게 그림자를 생성해주는 장점이 있다.

응용해서 금속효과등도 리플렉션에 영향받지 않고 적용되도록 가능

 

리플렉션 맵과 거의 비슷하지만 전방위를 베이크해야해서 만들기 어려운 리플렉션맵과 달리 정면사진만을 원하기 때문에 만들기 쉽다.

단점은 위에서 보면 렌더가 제대로 안 된다

 

 

 

 

다음과 같이 조명 설정

 

 

 

 

 

 

스피어를 만들어서 정면에서 찍고 잘라내면 끝

 

 

아니면 현실 사진 써도 된다

 

 

 

 

 

 

 

 

 

 

 

'Unity' 카테고리의 다른 글

유니티 모델 임포트 에러  (0) 2024.02.24
에셋스토어 업로드 거부사례 모음  (0) 2023.11.27
에셋스토어 업로드 2023  (0) 2023.11.21
posted by 모카쨩
2023. 12. 19. 14:19 Unity/C#

현재시간

long second= System.DateTime.Now.Ticks / 10000000 % 60;
long minute= System.DateTime.Now.Ticks / 10000000/60 % 60;
long hour= System.DateTime.Now.Ticks / 10000000/60/60 % 24;
System.DateTime.NowGetHour(System.DateTime.Now) //24시는 0으로 표기되고 23시는 23시로 나온다
DateTime Date = DateTime.UtcNow.AddYears(-10) //10년전


System.DateTime.Now
//결과:2021-06-08 PM 6:00:44



//Unix시간, 유닉스 타임 스탬프 (UnixTimeStamp)
//DateTime버전 길지만 변환이 쉬움
DateTime date=DateTime.Now;
(Int32)(date.Subtract(new DateTime(1970, 1, 1))).TotalSeconds
//결과: 2021-1-16 (6:12:31 GMT) => 1610788351

//역변환
DateTime date= new DateTime(1970, 1, 1).AddSeconds(unixTime);
//결과: 2021-1-16 (6:12:31 GMT) => 1610788351

//DateTimeOffset버전 짧지만 변환이 어려움
DateTimeOffset.Now.ToUnixTimeSeconds();



var time = System.DateTime.Now;
Debug.Log($"<b>[{time.Hour.ToString("D2")}:{time.Minute.ToString("D2")}:{time.Second.ToString("D2")}.{time.Millisecond.ToString("D3")}]</b>");
//굵은 글씨로 현재시간 시분초(소숫점 포함) 표기
//결과 : [18:17:30.428]

 

 

ticks를 datetime으로

long ticks = System.DateTime.UtcNow.Ticks;
System.DateTime dateTime = new System.DateTime(ticks);
Debug.Log(dateTime);

 

dateTime to int

기준일로부터 68년간 유효하다 (최대 69년)

//68년간 유효
long offsetYears = System.DateTime.MinValue.AddYears(1953).Ticks;
Debug.Log($"offsetYears: {offsetYears}");

long ticks = System.DateTime.Now.Ticks;
Debug.Log($"ticks: {ticks}");

int ticksInt = (int)((ticks- offsetYears)/ 10000000);
Debug.Log($"ticksInt: {ticksInt}");

long intToTicks = (long)ticksInt * 10000000+ offsetYears;
Debug.Log($"intToTicks: {intToTicks}");

System.DateTime dateTime = new System.DateTime(intToTicks);
Debug.Log($"dateTime: {dateTime}");

 

 

datetime 문자열 변환

var dateTimeString = dateTime.ToString();
dateTime= System.DateTime.Parse(dateTimeString);

 

 

DateTime To TimeSpan

원문 : https://stackoverflow.com/questions/17959440/convert-datetime-to-timespan

var timeSpan = System.TimeSpan.FromTicks(dateTime.Ticks);

 

 

DateTime To TotalDays

var timeSpan = System.TimeSpan.FromTicks(dateTime.Ticks);
var totalDays = timeSpan.TotalDays;

 

 

 

DateTime 덧셈


dateTime = dateTime.AddTicks(dateTime2.Ticks);

 

 

 

 

DateTime을 0~1 float로 변환

//오래될수록 1에 가까워짐

//샘플코드는 최대 한달

//7일전 = 0.2258064

//15일전 = 0.483871

//31일전 = 1

var lastUtcTime = System.DateTime.UtcNow.AddDays(-7); //7일전 접속

long min = System.DateTime.MinValue.Ticks;
long max = System.DateTime.MinValue.AddMonths(1).Ticks; //최대 1달
long normalizeTime = System.Math.Max((System.DateTime.UtcNow - lastUtcTime).Ticks, min);
normalizeTime = System.Math.Min(normalizeTime, max);

Debug.Log("마지막 접속으로부터 {(float)(((double)normalizeTime) / max)}개월 지남");

 

 

 

 

한달중 얼마나 지나갔는지 0~1float로 변환

단 day 기준임

v1

더보기
float CalculateDayRatioOfMonth(System.DateTime datetime)
{
    var datetimeAddMonths1 = datetime.AddMonths(1);
    var dayMax = datetimeAddMonths1.AddDays(-datetimeAddMonths1.Day).Day;
    return datetime.Day / dayMax;
}

v2

float GetDayRatioOfMonth(System.DateTime datetime)
{
    return datetime.Day / (float)System.DateTime.DaysInMonth(datetime.Year, datetime.Month);
}

 

 

 

날짜부분만 추출

v1

var date=System.DateTime.Parse(krTime.ToShortDateString());

 

v2

var date = krTime.Date;

 

 

DateTime의 Lerp

ChatGPT가 짜줬다


System.DateTime LerpDateTime(System.DateTime start, System.DateTime end, float t)
{
    var ticksStart = start.Ticks;
    var ticksEnd = end.Ticks;
    var ticksLerp = (long)(ticksStart + (ticksEnd - ticksStart) * (double)t);
    return new System.DateTime(ticksLerp);
}

 

 

한국시간 반환

var krTime = System.DateTime.UtcNow.AddHours(9);

 

 

 

 

 

일몰일출시간 반환

한국기준이고 2022년 기준으로 만들었다

 

 

 

 

'Unity > C#' 카테고리의 다른 글

c# Dictionary(딕셔너리) 관련  (0) 2024.03.19
Path 연산  (0) 2023.09.09
csv 사용법  (0) 2022.03.06
posted by 모카쨩
2023. 12. 18. 13:42 Unity/shader

 

 

Shader error in 'Ahzkwid/Toon': Output variable vert contains a system-interpreted value (SV_RenderTargetArrayIndex) which must be written in every execution path of the shader.  Unconditional initialization may help. at line 586 (on d3d11)

유니티 2019에서는 발생 안 하다가 2022에서 급작스럽게 발생했다.

원인은 struct v2f의 UNITY_VERTEX_OUTPUT_STEREO 구조변경 때문이다.

 

appdata와 vert에 아래구문을 추가한다

struct appdata
{
    UNITY_VERTEX_INPUT_INSTANCE_ID
};
v2f vert (appdata v)
{
    v2f o;

    UNITY_SETUP_INSTANCE_ID(v);
    UNITY_INITIALIZE_OUTPUT(v2f, o); 
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
}

 

참고링크 : https://docs.unity3d.com/kr/2019.4/Manual/SinglePassInstancing.html

 

 

 

 

 

Shader error in 'Ahzkwid/KotatsuFuton': invalid subscript 'instanceID' at line 339 (on d3d11)
Compiling Subshader: 0, Pass: FORWARD, Vertex program with DIRECTIONAL STEREO_INSTANCING_ON VERTEXLIGHT_ON

 

위와 같은 문제이다.

위와 다른점은 위에건 버텍스 프래그 쉐이더를 썼지만 이건 서피스와 버텍스 혼합 쉐이더에서 발생한 차이점이 있다.

내 경우엔 프래그를 안 가져와서 void vert이기 때문에 appdata에 아래 구문 추가하는거로 끝났다.

struct appdata
{
    UNITY_VERTEX_INPUT_INSTANCE_ID
};

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

DepthCameraTexture를 _CameraDepthTexture처럼 쓰기  (0) 2023.10.14
PerlinNoise HLSL  (0) 2023.04.25
스크린 오버레이 샘플  (0) 2023.01.20
posted by 모카쨩

저사양 유저용 블로그 진입