fullstack

blender에서 3d nft random generate 하는 법

Web3

FZRandomizer 3버전을 사용하여 blender에서 3d nft를 random generate 하는 법을 알아보겠습니다

 

우선 다음 링크에서 FZRandomizer 3를 무료로 다운받아줍니다

https://fruitzeus.gumroad.com/l/FZRandomizer

 

FZRandomizer 3

FZRandomizer is a blender addon which allows you to randomize characters & other mesh objects.READ ME:Terms & Conditions

fruitzeus.gumroad.com

그럼 FZRandomizer_3_0_3.py 와 같은 파이썬 파일을 하나 받게됩니다

 

 

그럼 이제 blender에서 Edit - Preferences 로 들어간 뒤, Add-ons 탭을 선택해 줍니다

다음으로 Install an add-on 버튼을 눌러 아까 받은 파일을 인스톨 해주면 됩니다

 

그럼 다음과 같이 FZRandomizer 가 추가된 것을 볼 수 있고,

체크박스가 표시되어 있어야 합니다

 

이제 blender 뷰포트의 오른쪽상단을 보면 다음과 같이 FZRandomizer 탭이 추가된 것을 볼 수 있습니다

 

먼저 Host Builder를 눌러줍니다

Host Builder를 이용하면 collection을 정의하여 자동으로 collection을 구성할 수 있습니다

먼저 Host Name을 입력후 Add Subcollection 버튼으로 추가하고 싶은 Subcollection을 추가해 줍니다

여기에서는 간단하게 head와 body만 추가해 보았습니다

 

그럼 다음과 같이 collection이 생성된것을 볼 수 있습니다

이제 여기에 각각 부위별 모델을 넣고 generate 하면 됩니다

 

이제 FZRandomizer 항목을 열어보겠습니다

뭔가 이것저것 많은데, 하나씩 설명해 보겠습니다

 

- unique 체크박스 표시

각각의 유니크한 결과물이 나오도록 표시해 줍니다

체크하면 중복된 결과물이 나오지 않습니다

 

- GENERATE 버튼

추출합니다

 

- Variants 조절

몇개를 추출할 것인지 값을 설정해 줍니다

 

- Calculate Possibilities 버튼

현재 나올 수 있는 조합갯수를 계산해 줍니다

 

- Rarity

카테고리안의 각각 오브젝트들의 확률을 조절합니다

 

- Rules

규칙을 도입하여 배치할 수 있습니다

예를들면, 특정오브젝트에는 어떤 특정오브젝트가 꼭 같이 나오도록 혹은 나오지않도록 설정할 수 있습니다

 

- Metadata

이미지와 같이 추출할 Metadata에 대한 설정을 할 수 있습니다

 

- Output

Output Path를 설정하고 렌더링을 진행합니다

 


그럼 이제 랜덤조합으로 모델을 추출해보고 렌더링 이미지에 해당 구성요소 정보를 포함하는 json까지 추출해 보는 과정을 해보겠습니다

 

여기서는 간단하게 큐브의 각도를 조절하여 body 2개와 head 3개로 조합으로 만들어 보겠습니다

 

그럼 Calculate Possibillities 버튼을 눌러보면 현재 나올수 있는 조합 갯수 2X3 이므로 6개로 표시됩니다

Varuants도 최대치인 6으로 설정하겠습니다

 

다음으로 Metadata 항목에서 Write To JSON을 체크하여 JSON파일을 뽑을수 있도록 합니다

Field 를 추가해 주어야 하는데 저는 name 과 attributes를 추가하였습니다

먼저 name에는 #1, #2, #3 이런식으로 순서번호가 이름으로 들어갈수 있게 하기위해 인덱스가 들어갈 위치에 __VAR를 추가해주면 됩니다

그리고 attributes 라고 추가를 하면 값에 [attributes] 라고 들어가게 되는데 여기엔 조합된 속성 정보가 자동으로 들어가게 됩니다

 

위 설정으로 추출된 JSON 예시입니다

{
    "name": "#1",
    "attributes": [
        {
            "trait_type": "body",
            "value": "body2"
        },
        {
            "trait_type": "head",
            "value": "head2"
        }
    ]
}

 

Rarity 나 Rules에 대한 자세한 설명은 생략하겠습니다

이제 설정이 완료되었다면 GENERATE 버튼을 눌러줍니다

 

그럼 Variants라는 collection이 생성이되고

아래 키프레임을 움직이면 생성된 모델들을 볼 수 있습니다

 

또한, 설정된 경로에 metadata라는 폴더가 생성되고 json파일들도 생성된것을 확인해 볼 수 있습니다

 

이제 Output에서 Path를 설정해 주고 Still Images를 선택합니다

그리고 Render Variants를 눌러주면 렌더링을 시작합니다

렌더링할 모델이 많을 경우 굉장히 오래걸릴 수 있으니, 콘솔창을 띄우고 진행상황을 확인하는것을 추천합니다

 

이제 설정된 경로의 폴더를 보면 모델들이 잘 렌더링 된 것을 확인해 볼 수 있습니다

 

[Unity] RequireComponent

Unity

RequireComponent는 게임 오브젝트에 꼭 필요한 컴포넌트를 스크립트로 작성하여 추가하는 것 입니다

[RequireComponent (typeof (Rigidbody))]

이렇게 작성을 하면 Rigidbody 컴포넌트가 해당 스크립트를 가진 게임 오브젝트에 자동으로 추가됩니다

 

다음은 예제 코드입니다

using UnityEngine;

// PlayerScript requires the GameObject to have a Rigidbody component
[RequireComponent (typeof (Rigidbody))]
public class PlayerScript : MonoBehaviour {
	Rigidbody rb;
	
	void Start() {
		rb = GetComponent<Rigidbody>();
	}
	void FixedUpdate()  {
		rb.AddForce(Vector3.up);
	}
}

 

이제 게임 오브젝트에 위 스크립트를 추가하면, Rigidbody 컴포넌트가 자동으로 추가되는 것을 볼 수 있습니다

이 게임 오브젝트의 Rigidbody 컴포넌트를 Remove Component 하려고 하면 다음과 같이 경고창이 나오는 것을 볼 수 있습니다

 

 

[Solidity] 함수제어자 modifier

Web3/Solidity

contract의 소유자만 호출할 수 있는 함수를 만들고 싶다고 가정해봅시다

함수의 첫 줄에 require문을 넣어 처리할 수도 있지만 더욱 좋은 방법은 함수제어자를 사용하는 것 입니다

 

함수제어자는 다음과 같이 만들 수 있습니다

modifier onlyOwner() {
  require(msg.sender == owner);
  _;
}

함수제어자는 위와같이 function 키워드 대신 modifier 키워드를 사용합니다

그리고 require 등으로 실행조건을 체크하고, 마지막에는 _; 으로 끝나야 합니다

 

그럼 함수에서 함수제어자를 사용해 보겠습니다

function withdraw() external onlyOwner {
  owner.transfer(this.balance);
}

위에서 만든 함수제어자 onlyOwner를 함수에 붙여주었습니다

그럼 이제 withdraw 함수가 호출되면 함수제어자 onlyOwner가 실행되고,

함수제어자 내부의 _; 부분에서 함수로 되돌아와 함수가 실행되게 됩니다

이제 이 함수는 contract의 소유자만이 호출할 수 있는 함수가 되었습니다

 

함수제어자를 이용하면 이처럼 특정조건에 부합할때만 함수가 실행되도록 간편하게 설정할 수 있습니다

[Solidity] 상속, 다중상속, 함수 오버라이드(override)

Web3/Solidity

Solidity의 contract는 객체지향언어에서의 class와 닮은 점이 많습니다

그 중 상속에 대해서도 매우 유사한 형태를 보입니다

 

상속

상속은 다음과 같이 사용하면 됩니다

contract Doge {
  function catchphrase() public returns (string) {
    return "So Wow CryptoDoge";
  }
}

contract BabyDoge is Doge {
  function anotherCatchphrase() public returns (string) {
    return "Such Moon BabyDoge";
  }
}

contract 이름 뒤에 is 키워드를 이용하여 뒤에 상속받을 부모 contract의 이름을 써주면 됩니다

그럼 자식 contract는 상속받은 부모 contract의 모든 public 변수와 함수에 접근이 가능합니다

 

다중 상속

다중상속은 다음과 같이 사용하면 됩니다

contract MomDoge {
  function catchphrase() public returns (string) {
    return "So Wow CryptoDoge";
  }
}

contract DadDoge {
  function catchphrase() public returns (string) {
    return "So Wow CryptoDoge";
  }
}

contract BabyDoge is MomDoge, DadDoge {
  function anotherCatchphrase() public returns (string) {
    return "Such Moon BabyDoge";
  }
}

이미 상속받은 부모 contract가 있다면 뒤에 ','를 붙여 구분하여 다중상속을 할 수 있습니다

 

함수 오버라이드

상속을 받으면 부모의 public함수에 접근이 가능합니다

이때 부모의 함수의 이름과 같은 이름과 매개변수를 사용하여 함수를 재정의 하고 싶을 때가 있습니다

이를 함수 오버라이드(Override)라고 합니다

 

기본적인 단일상속에서는 다음과 같이 사용하면 됩니다

contract MomDoge {
  function catchphrase() public virtual returns (string) {
    return "So Wow CryptoDoge";
  }
}

contract BabyDoge is MomDoge {
  function catchphrase() public override returns (string) {
    return "Such Moon BabyDoge";
  }
}

부모 contract의 함수에서는 virtual을 자식 contract의 함수에서는 override를 명시해 주면 됩니다

 

만약 다중상속이고 오버라이드 하려는 함수가 여러 부모가 가지고 있는 함수라면

다음과 같이 괄호를 사용하여 해당 함수를 가진 contract들을 명시해 주어야 합니다

 

contract MomDoge {
  function catchphrase() public virtual returns (string) {
    return "So Wow CryptoDoge";
  }
}

contract DadDoge {
  function catchphrase() public virtual returns (string) {
    return "So Wow CryptoDoge";
  }
}

contract BabyDoge is MomDoge, DadDoge {
  function catchphrase() public override(MomDoge, DadDoge) returns (string) {
    return "Such Moon BabyDoge";
  }
}

[Solidity] error handler (require, assert, revert)

Web3/Solidity

Solidity의 에러 핸들러에는 require, assert, revert 세가지가 있습니다

각각 어떤 경우에 사용하는지, 어떻게 사용하는지 알아보겠습니다

 

require

require는 특정 조건이 참이 아니라면 에러 메시지를 발생하고 실행을 멈춥니다

require로 에러를 발생시키면 사용하려던 gas를 환불 시켜 줍니다

주로 사용자 사용자의 입력을 확인하는데 사용합니다

 

사용방법은 다음과 같습니다

require(msg.value % 2 == 0, "Even value required.");

 

assert

assert는 특정 조건이 참이 아니라면 에러를 발생시켜 실행을 멈춥니다

assert는 gas를 환불 시켜 주지 않습니다

주로 내부적 코드결함이 있는지 확인하는데 사용합니다

(오버플로우나 언더플로우 등 치명적인 문제를 찾을 때 사용)

 

사용방법은 다음과 같습니다

 assert(address(this).balance == balanceBeforeTransfer - msg.value / 2);

 

revert

revert는 조건없이 에러를 발생시킬 때 사용합니다

require와 마찬가지로 에러를 발생시키면 사용하려던 gas를 환불 시켜 줍니다

 

사용방법은 다음과 같습니다

revert("Not enough Ether provided.");

revert를 사용하려면 어쨋든 특정 조건문 안에 넣어야 하는데, 이는 require로 대체가 되기 때문에 

주로 require가 사용되고 revert는 잘 사용되지 않습니다

[Solidity] view, pure 함수

Web3/Solidity

contract를 만들때 중요하게 생각해야 하는 것 중 하나가 가스비용 최적화입니다

블록체인에 데이터를 쓸 때 마다 가스비용이 들기 때문에 이를 최소화 하는게 중요합니다

 

이 때 필요한 것이 view 함수입니다

view 함수는 function 밖의 변수를 읽기만 할 뿐, 변경할 수 없습니다

따라서 view 함수를 쓰는 것은 블록체인에 어떤 트랜젝션도 만들지 않는다는 것을 의미 합니다

 

view 함수는 사용자에 의해 외부에서 호출되었을 경우 가스를 전혀 소모하지 않습니다

(내부에서 다른 함수에 의해 호출되었을 경우 가스를 소모할 수 있음)

그래서 여기에 접근제어자 중 외부에서만 호출할 수 있게하는 exturnal을 같이 사용한다면

이 함수는 가스비용을 절대 소모하지 않는 함수가 됩니다

 

사용방법은 다음 예시와 같습니다

 

function func() exturnal view {
	...
}

 

pure 함수는 view 함수보다 조금 더 빡센(?) 함수입니다

view 함수가 읽기만 가능하다면, pure 함수는 읽기 조차도 불가능 합니다

 

[Solidity] 접근 제어자 (public, private, internal, external)

Web3/Solidity

접근 제어자는 함수가 언제, 어디서 호출될 수 있는지 제어합니다

Solidity에서 접근 제어자의 종류는 다음과 같습니다

 

public

이 함수는 contract의 내외부 모두에서, 어디서든지 호출될 수 있습니다

 

private

이 함수는 contract의 내부의 다른 함수들에 의해서만 호출될 수 있습니다

 

internal

이 함수는 contract의 내부 혹은, 해당 contract를 상속하는 다른 contract에서도 호출될 수 있습니다

 

external

이 함수는 오직 contract 외부에서만 호출될 수 있습니다

 

[Python] Mac OS 에서 .DS_Store 파일 제거하기

Language/Python

이미지 프로세싱을 위해  다음과 같은 코드로 특정 폴더의 이미지들을 불러와 리스트화 하였다

 

dir = "color"
imagePaths = [os.path.join(dir,file_name) for file_name in os.listdir(dir)]

 

그래서 imagePaths 에 불러온 파일들을 프로세싱하려고 보니 다음과 같은 오류가 발생하였다

PIL.UnidentifiedImageError: cannot identify image file 'color/.DS_Store'

 

imagePaths 안에 .jpg나 .png같은 이미지 파일이 아닌 .DS_Store 파일이 들어가서 문제가 된 것인데,

.DS_Store 파일은 mac os 에서 자동으로 생성하는 메타데이터 파일이다

 

위 코드에 다음과 같은 코드를 추가하여 .DS_Store 파일은 지워주어 해결하였다

 

if dir + '/.DS_Store' in imagePaths:
    imagePaths.remove(dir + '/.DS_Store')

 

 

[Unity] Json 파일 간단하게 Class 변환하기 (Json.NET)

Unity

Json.NET을 이용하여 Json 파일을 간단하게 Class 로 변환할 수 있다

Json.NET 에셋스토어에서 받을 수 있다

 

우선 간단한 Json 파일을 만들어 보았다

{
    "level" : 0,
    "coin" : 0
}

 

그 다음에는 이 정보를 파싱할 Class도 만들어 보자

[Serializable]
class Data
{
    int level;
    int coin;
}

 

주의할 점은 Class 에 [Serializable] 를 붙여 직렬화 해 주어야 하고, 변수명을 서로 맞춰 주어야 한다

 

TextAsset jsonData = Resources.Load("Json/Data") as TextAsset;
_data = JsonUtility.FromJson<GameData>(jsonData.ToString());

 

Json 파일은 Resources 경로에 Json/Data.json 으로 저장하여 간단하게 Resources.Load 를 이용하여 불러와 보았다

이렇게 사용하면 Json Object를 생성하여 일일히 파싱하는 번거로움을 줄일 수 있다

 

Class를 다시 Json으로 변환할때는 JsonUtility.ToJson(_data) 이런식으로 사용할 수 있다

 

 

 

[Unity] 디바이스 경로에 파일 입출력하기 (Application.persistentDataPath)

Unity

게임정보를 저장할 때 PlayerPrefabs를 쓰면 쉽고 편리하게 정보를 저장할 수 있지만, 조금 복잡하고 많은 데이터를 저장해야 할 때에는 PlayerPrefabs는 한계가 있습니다

이럴 때에는 xml 이나 json 파일을 만들어서 디바이스 내부에 파일로 정보를 저장하는 것이 좋습니다

 

우선 파일입출력을 사용하기위해서 다음과 같은 namespace를 추가해 줍니다

using System.IO;

 

저는 Json파일을 생성하여 저장정보를 저장하겠습니다

이를 위해서 JsonUtility를 사용하였습니다

 

디바이스의 저장경로는 Application.persistentDataPath 로 얻어오면 됩니다

 

먼저 파일을 쓰는 로직입니다

File.WriteAllText(Application.persistentDataPath + "/UserData.json", JsonUtility.ToJson(_data));

 

다음은 파일을 읽는 로직입니다

if (File.Exists(Application.persistentDataPath + "/UserData.json"))
{
    string json = File.ReadAllText(Application.persistentDataPath + "/UserData.json");
    _data = JsonUtility.FromJson<Data>(json);
}

 

위 예제는 최대한 간단하게 입출력만 한 예제이고, 보안을 위해서 파일을 저장할 떄 암호화를 해주면 더욱 좋습니다