CloudFront를 통해 퍼블릭 상태의 객체에 대한 접근을 차단하고, https까지 적용시키려고 합니다.

 

https://whyeskang.com/411

 

AWS S3로 React 배포하기

S3와 CloudFront를 이용한 배포 방법이 있고, S3 만으로 배포하는 방법이 있습니다. 권장하는 방법은 S3, CloudFront를 모두 사용하는 방법이고, 이 글에서는 S3 만으로 배포하는 것을 다룹니다. 사전에

whyeskang.com

우선 이전 글에 이어서 포스팅하니, 앞 내용은 여기서 확인해주시면 됩니다.

 

현재 S3만으로 배포가 완료된 이 버킷은 퍼블릭 상태이고, 퍼블릭 차단이 해제되어 있습니다.

먼저 이것부터 돌려놓습니다.

퍼블릭 액세스 차단을 다시 활성화하고, 현재 등록된 버킷정책을 삭제하여 액세스를 "버킷 및 객체가 퍼블릭이 아님" 상태로 돌려놓습니다.

완료된 화면입니다.

 

그리고 정적 웹 사이트 호스팅로 "비활성됨" 으로 변경합니다.

 

https://us-east-1.console.aws.amazon.com/cloudfront/v3/home

 

https://us-east-1.console.aws.amazon.com/cloudfront/v3/home

 

us-east-1.console.aws.amazon.com

그러면 이제 위 링크를 이용하여 CloudFront 페이지로 넘어갑니다.

 

우측의 "배포 생성" 버튼을 누릅니다.

 

우선 원본 도메인으로 해당 버킷에 해당하는 도메인을 선택합니다.

그리고 S3 버킷 액세스를 "원본 액세스 제어 설정"으로 변경합니다.

 

그 다음 제어 설정 생성을 눌러서 해당 S3의 제어 설정을 생성합니다.

건드릴 것 없이 바로 생성 버턴을 누르시면 됩니다.

 

 

그리고 아래에 Origin Shield 활성화를 "예"로 변경합니다.

지역은 S3 버킷과 동일하게 맞춥니다.

 

기본 캐시 동작에서는 하나만 변경하면 됩니다.

뷰어 프로토콜 정책이 HTTP and HTTPS로 되어있을겁니다.

이거를 "Redirect HTTP to HTTPS"로 변경합니다.

 

그리고 맨 밑에 내려와서 기본값 루트 객체를 /index.html 으로 작성하고 배포를 생성합니다.

 

그러면 배포를 생성함과 동시에 S3 버킷 정책을 업데이트하라고 합니다.

정책을 복사해줍니다.

 

그리고 해당 S3로 넘어가서 버킷 -> 권한 -> 버킷 정책 -> 편집에서 해당 내용을 넣고 저장합니다.

위 사진처럼 되면 완료입니다.

 

다시 생성된 배포로 넘어가면 도메인이 표시되어 있습니다.

 

도메인 + /index.html 으로 들어가면 배포가 완료되었고, https까지 적용된 것을 확인하실 수 있습니다.

그리고 버킷의 엔드포인트까지 노출되지 않아서 S3만으로 배포한 방법보다는 안정적이라고 볼 수 있습니다.

 

하지만 도메인/index.html 을 통해서만 이 페이지가 뜨며, /index.html를 제거한다면 AccessDenied가 뜹니다.

여기서 오류페이지에 대한 응답을 직접 생성하는 방법으로 해결합니다.

 

해당 배포 -> 오류 페이지 응답 생성에서 사용자 정의 오류 응답 생성 버튼을 누릅니다.

 

여기서 오류코드를 응답 페이지로 이동하도록 지정할 수 있습니다.

/index.html로 경로를 설정하고, 응답 코드를 200으로 변경합니다.

 

같은 방법으로 403, 404에 대한 응답 페이지를 생성하였습니다.

 

이제 /index.html 없이 도메인 입력만으로 이동이 가능한 것을 확인할 수 있습니다.

S3와 CloudFront를 이용한 배포 방법이 있고, S3 만으로 배포하는 방법이 있습니다.

권장하는 방법은 S3, CloudFront를 모두 사용하는 방법이고, 이 글에서는 S3 만으로 배포하는 것을 다룹니다.

 

사전에 준비하셔야할 것은 배포 하려고하는 React 프로젝트입니다.

npx create-react-app deploy-app

저는 기본 프로젝트를 배포하기 위해 위 명령어로 새 프로젝트를 만들었습니다.

 

우선 프로젝트를 S3에 업로드한 후에 배포를 진행하게 됩니다.

먼저 리액트 프로젝트를 아래 명령어로 빌드해주시면 됩니다.

npm run build

그럼 프로젝트 바로밑에 build 폴더가 생성되는 것을 확인할 수 있습니다.

build 폴더 아래의 모든 파일을 S3에 업로드합니다.

 

https://s3.console.aws.amazon.com/s3/buckets

 

https://s3.console.aws.amazon.com/s3/buckets

 

s3.console.aws.amazon.com

위 링크를 이용하여 S3 버킷 페이지로 이동합니다.

그리고 우측에 "버킷 만들기" 버튼으로 버킷을 생성합니다.

 

버킷 이름은 원하는대로 작성합니다.

 

객체 소유권은 비활성화됨을 유지합니다.

 

원래는 모든 퍼블릭 액세스를 차단하는 것이 맞습니다.

하지만 S3만으로 배포할 때는 차단을 해제합니다.

이는 추후에 업로드할 CloudFront로 보완할 수 있습니다.

 

나머지 설정은 기본으로 놔두고 버킷을 생성하시면 됩니다.

이렇게 생성된 버킷의 액세스는 "객체를 퍼블릭으로 설정할 수 있음" 상태입니다.

이것을 "퍼플릭" 상태로 변경해야 합니다.

이를 위해 버킷 -> 권한 -> 버킷 정책에서 "편집" 버튼을 눌러 버킷 정책을 넣어주시면 됩니다.

 

1시 방향의 "정책 생성기" 버튼으로 편하게 정책을 생성할 수 있습니다.

그 전에 왼쪽의 버킷 ARN을 복사하고 넘어가도록 합시다.

 

먼저 Policy Type은 "S3 Bucket Policy"를 선택합니다.

Principal은 *

Actions는 GetObject

ARN은 방금 복사했던 ARN + /*을 넣습니다. (/*을 반드시 포함해야 합니다.)

그러면 Add Statement 버튼이 활성화되며, 클릭합니다.

 

Generate Policy 버튼까지 누르면 JSON 형식으로 버킷 정책이 생성됩니다.

위 내용을 복사합니다.

 

그리고 다시 버킷 정책으로 돌아와서 복사한 내용을 붙여 넣으면 됩니다.

그리고 "변경 사항 저장" 버튼을 눌러 저장합니다.

 

그러면 객체의 액세스가 퍼블릭으로 변경된 것을 확인할 수 있습니다.

 

다시 해당 버킷으로 들어갑니다.

여기에 아까 build했던 파일을 다 업로드합니다.

업로드가 완료되면 이런 상태가 됩니다.

 

그리고 속성에서 맨 밑으로 내려가면 "정적 웹 사이트 호스팅"이 있습니다. 편집을 누릅니다.

우선 활성화부터 해주시고, 기본 페이지로 index.html 을 넣어줍니다.

그리고 변경사항을 저장합니다.

 

그러면 이렇게 URL을 발급 받을 수 있습니다.

 

그리고 해당 URL을 클릭하면 배포가 완료된 것을 확인할 수 있습니다.

 

다만 이 방법은 객체가 퍼블릭 상태고, https가 적용되지 않아 보안상의 이슈가 있습니다.

이를 해결하기 위해서는 CloudFront에 S3를 연결해주는 작업이 필요합니다.

CloudFront 관련 글은 아래 링크에서 확인해주시면 되겠습니다.

https://emoney96.tistory.com/412

 

GitHub Actions를 이용하기 전에 Github & Slack부터 진행하며, Slack 워크스페이스가 만들어져 있다는 가정하에 시작합니다.

 

우선 알림을 받으려고 하는 채널을 생성합니다.

 

그리고 아래에 있는 "앱 추가" 버튼을 누릅니다.

 

"GitHub"를 추가합니다.

 

그 다음은 채널 우클릭 -> 채널 세부정보 보기 -> 통합 -> 앱 에서 앱 추가를 합니다.

GitHub를 추가하시면 됩니다.

그러면 해당 채널에서 위 메시지를 확인할 수 있습니다.

 

/github signin 명령어를 치면 GitHub에 연결할 수 있도록 메시지가 전송됩니다.

버튼을 눌러서 연결할 수 있고, Verification Code를 받으면 위 사진에 있는 Enter code에 입력하면 연동되는 것을 확인할 수 있습니다.

 

이제 계정과 연결을 했으니 GitHub Repository에 연결하도록 합니다.

명령어는 /github subscribe owner/repository 입니다.

여기 드래그된 부분을 owner/repository 자리에 넣어주시면 되겠습니다.

 

이 메시지를 받으셨다면 연결은 완료되었습니다.

 

이제 GitActions와 연동을 하겠습니다.

https://api.slack.com/apps

 

Slack API: Applications | Slack

Your Apps Don't see an app you're looking for? Sign in to another workspace.

api.slack.com

먼저 위 링크를 타고 가서 Create New App 버튼으로 앱을 생성합니다.

 

그리고 Settings -> Basic Information -> Add features and functionality에서 Incoming Webhooks를 누르고 활성화합니다.

 

그 다음 아래에서 Add New Webhook to Workspace 버튼으로 워크스페이스와 채널에 연결합니다.

그러면 이렇게 Webhook URL을 받을 수 있습니다. 이거를 GitHub의 secrets에 넣어줍니다.

 

GitHub -> Settings -> Security -> Secrets and variables -> Actions에 들어가셔서 New repository secret 버튼으로 발급 받은 Webhook URL을 넣어줍니다.

이렇게 등록되어야 합니다.

 

이제 yml 파일을 .github/workflows 경로 내에 작성해야 합니다.

Actions 페이지로 와서 "set up a workflow yourself"를 클릭합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
name: Slack Notification
 
on:
  pull_request:
    branches: [ "master""develop" ]
 
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: action-slack
      uses: 8398a7/action-slack@v3
      with:
        status: ${{ job.status }}
        author_name: www-be
        fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
        if_mention: failure,cancelled
      env:
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} # required
      if: always() # Pick up events even if the job fails or is canceled.
 
cs

먼저 name으로 workflow의 이름을 작성합니다.

 

on은 workflow가 실행될 조건을 명시합니다.

보통 push나 pull request를 등록하며, 저는 pull request만 작성했습니다.

 

jobs에는 실행되는 명령어들을 작성합니다.

여기서 secrets에 등록한 SLACK_WEBHOOK_URL을 사용합니다.

그 외 파라미터나 필드 등 설명은 https://action-slack.netlify.app/ 여기서 확인해주시거나 아래 레퍼런스에서 확인해주시면 되겠습니다.

 

등록이 완료되었다면 이렇게 알림을 받아보실 수 있습니다.

 

Reference

GitHub & Slack 연동

Git Actions 활용

이 글에서는 solidity 문법을 다루지는 않으며, 배포된 solidity의 Contract 함수를 web3에서 호출하는 방법을 포스팅합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// SPDX-License-Identifier GPL-30
pragma solidity >= 0.7.0 < 0.9.0;
 
contract Hello {
    uint public num = 0;
    string public hi = "hello solidity!!";
 
    function addNumAndX(uint x) public {
        num += x;
    }
 
    function hello() public view returns(string memory) {
        return hi;
    }
 
    function getNum() public view returns(uint) {
        return num;
    }
}
 
cs

우선 solidity를 이렇게 작성해줍니다. 저는 Remix에서 작성하였습니다.

그 다음 compiler에서 컴파일을 해준 후에

 

deploy에서 배포를 해야합니다.

아래의 Deploy 버튼을 누르기 전, 환경을 "Injected Provider - MetaMask"로 변경합니다.

그리고 Deploy 버튼을 누릅니다.

 

그러면 해당 Contract를 배포하기 위한 가스비를 지불하는 창이 뜹니다.

위 창은 크롬의 MetaMask 확장 프로그램입니다.

 

배포가 완료되면 아래의 Deployed Contracts에 해당 컨트랙트가 뜹니다.

이제 우측 복사 버튼을 눌러 컨트랙트 주소를 가져올 수 있습니다.

이제 React로 넘어갑니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import {Component} from 'react';
import Web3 from 'web3';
 
class App extends Component {
    constructor(props) {
        super(props);
 
        const contractAddress = '0xaFA55F3E3DB63C536581762ceb3149aD3349913d';
        const abi = [
            {
                "inputs": [
                    {
                        "internalType""uint256",
                        "name""x",
                        "type""uint256"
                    }
                ],
                "name""addNumAndX",
                "outputs": [],
                "stateMutability""nonpayable",
                "type""function"
            },
            {
                "inputs": [],
                "name""getNum",
                "outputs": [
                    {
                        "internalType""uint256",
                        "name""",
                        "type""uint256"
                    }
                ],
                "stateMutability""view",
                "type""function"
            },
            {
                "inputs": [],
                "name""hello",
                "outputs": [
                    {
                        "internalType""string",
                        "name""",
                        "type""string"
                    }
                ],
                "stateMutability""view",
                "type""function"
            },
            {
                "inputs": [],
                "name""hi",
                "outputs": [
                    {
                        "internalType""string",
                        "name""",
                        "type""string"
                    }
                ],
                "stateMutability""view",
                "type""function"
            },
            {
                "inputs": [],
                "name""num",
                "outputs": [
                    {
                        "internalType""uint256",
                        "name""",
                        "type""uint256"
                    }
                ],
                "stateMutability""view",
                "type""function"
            }
        ];
 
        this.fromAddress = '0xE8Ed81Ae938Ede438501d12d87324AB1428A251a';
        this.web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546');
        this.contract = new this.web3.eth.Contract(abi, contractAddress);
    }
}
cs

web3 모듈을 가져와서 사용하고, abi, contractAddress를 이용하여 contract를 가져옵니다.

여기서 abi는 Contract 함수와 매개변수들의 정보가 담겨있는 JSON 형식의 리스트입니다.

Remix의 compiler 메뉴 밑에 해당 컨트랙트의 ABI를 복사할 수 있습니다.

그대로 가져와서 React 코드에 붙여줍니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
render() {
    return (
        <div className="App">
            <button onClick={this.connectWallet.bind(this)}>connectWallet</button>
            <br/>
            <button onClick={this.hello.bind(this)}>hello</button>
            <br/>
            <button onClick={this.addNumAndX.bind(this)}>addNumAndX</button>
            <br/>
            <button onClick={this.getNum.bind(this)}>getNum</button>
            <br/>
        </div>
    );
}
 
cs

화면에는 버튼을 놓았습니다.

각각 connectWallet, hello, addNumAndX, getNum 함수를 호출하는 버튼입니다.

함수에서는 constructor의 this를 사용할 수 없어 bind(this)로 this를 사용할 수 있도록 넘겨주었습니다.

 

이제 메소드입니다.

1
2
3
4
5
6
connectWallet() {
    this.web3.eth.requestAccounts().then((res) => {
        console.log(res);
    });
}
 
cs

지갑연결을 요청하는 코드입니다.

MetaMask가 설치되어있다면 문제없이 작동됩니다.

res는 지갑 주소가 array 형식으로 담겨있습니다.

 

1
2
3
4
5
6
hello() {
    this.contract.methods.hello().call((err, res) => {
        console.log(res);
   });
}
 
cs

다음은 Contract의 hello 함수를 호출하는 부분입니다.

string을 return받는 역할만 있어 가스비를 지출하지 않으며, call을 이용하여 호출할 수 있습니다.

res는 string입니다.

 

1
2
3
4
5
6
getNum() {
    this.contract.methods.getNum().call((err, res) => {
        console.log(res);
   });
}
 
cs

다음은 변수 num의 값을 가져오기 위한 getNum 함수 호출입니다.

hello 함수와 동일하게 call을 이용하여 호출합니다.

res는 uint입니다.

 

1
2
3
4
5
6
7
8
9
10
11
addNumAndX() {
    let x = 2;
    this.contract.methods.addNumAndX(x).send({fromthis.fromAddress})
        .on('receipt'function (res) {
            console.log(res);
        })
        .on('error'function (err) {
            console.log(err);
        });
}
 
cs

다음은 num에 x만큼 더하는 로직이 있는 addNumAndX 함수 호출입니다.

다른 함수와는 다르게 값을 변경하는 로직이 포함돼서 그런지 가스비를 요구하고 있습니다.

이 코드에서는 지불할 ETH가 0이지만 형식적으로 지불은 해야합니다.

가스비 지불을 위해 call 대신 send를 사용하였으며, 지불할 주소를 from에 작성하면 호출할 수 있습니다.

 

'receipt'을 감지하면 가스비 지불이 완료되었고, 트랜잭션 내역을 확인할 수 있습니다.

transactionHash를 통해 etherscan에서도 확인이 가능합니다.

그리고 getNum 함수를 다시 호출하면 값이 변경된 것을 확인할 수 있습니다.

 

다른 로직들은 [web3 공식문서]에서 확인해주시면 됩니다.

 

아래는 전체 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import {Component} from 'react';
import Web3 from 'web3';
 
class App extends Component {
    constructor(props) {
        super(props);
 
        const contractAddress = '0xaFA55F3E3DB63C536581762ceb3149aD3349913d';
        const abi = [
            {
                "inputs": [
                    {
                        "internalType""uint256",
                        "name""x",
                        "type""uint256"
                    }
                ],
                "name""addNumAndX",
                "outputs": [],
                "stateMutability""nonpayable",
                "type""function"
            },
            {
                "inputs": [],
                "name""getNum",
                "outputs": [
                    {
                        "internalType""uint256",
                        "name""",
                        "type""uint256"
                    }
                ],
                "stateMutability""view",
                "type""function"
            },
            {
                "inputs": [],
                "name""hello",
                "outputs": [
                    {
                        "internalType""string",
                        "name""",
                        "type""string"
                    }
                ],
                "stateMutability""view",
                "type""function"
            },
            {
                "inputs": [],
                "name""hi",
                "outputs": [
                    {
                        "internalType""string",
                        "name""",
                        "type""string"
                    }
                ],
                "stateMutability""view",
                "type""function"
            },
            {
                "inputs": [],
                "name""num",
                "outputs": [
                    {
                        "internalType""uint256",
                        "name""",
                        "type""uint256"
                    }
                ],
                "stateMutability""view",
                "type""function"
            }
        ];
 
        this.web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546');
        this.fromAddress = '0xE8Ed81Ae938Ede438501d12d87324AB1428A251a';
        this.contract = new this.web3.eth.Contract(abi, contractAddress);
 
    }
 
    connectWallet() {
        this.web3.eth.requestAccounts().then((res) => {
            console.log(res);
        });
    }
 
    hello() {
        this.contract.methods.hello().call((err, res) => {
            console.log(res);
        });
    }
 
    addNumAndX() {
        let x = 2;
        this.contract.methods.addNumAndX(x).send({fromthis.fromAddress})
            .on('receipt'function (res) {
                console.log(res);
            })
            .on('error'function (err) {
                console.log(err);
            });
    }
 
    getNum() {
        this.contract.methods.getNum().call((err, res) => {
            console.log(res);
        });
    }
 
    render() {
        return (
            <div className="App">
                <button onClick={this.connectWallet.bind(this)}>connectWallet</button>
                <br/>
                <button onClick={this.hello.bind(this)}>hello</button>
                <br/>
                <button onClick={this.addNumAndX.bind(this)}>addNumAndX</button>
                <br/>
                <button onClick={this.getNum.bind(this)}>getNum</button>
                <br/>
            </div>
        );
    }
}
 
export default App;
 
cs

'Etc' 카테고리의 다른 글

AWS S3로 React 배포하기  (0) 2023.02.02
GitHub Actions를 이용한 Slack Notification  (0) 2023.01.30
GitLab -> GitHub Mirroring  (0) 2022.06.12
Unity Script로 카메라 Culling Mask 기능 사용하기  (2) 2021.10.29
Unity 카메라 Culling Mask  (0) 2021.10.29

GitLab에 생성되어 있는 레포지토리를 GitHub로 옮기는 것을 정리합니다.

우선, 대용량 파일이 포함된 레포지토리를 미러링하는 것은 다루지 않음을 먼저 알립니다.

 

먼저 GitHub에서 새로운 Repository를 생성합니다.

공개 여부는 자유이며, Repository name만 작성하여 만들면 됩니다.

그러면 Repository가 생성되었고, HTTPS와 SSH URL을 볼 수 있습니다.

여기서 필요한건 HTTPS URL이니 따로 메모해둡시다.

그 다음 토큰 발급을 위해 본인 프로필 -> Settings에 들어갑니다.

그리고 좌측에 Personal access tokens를 눌러주면 해당 화면이 나옵니다.

여기서 Generate new token을 눌러 토큰을 생성합니다.

Note는 자유롭게 구분할 수 있도록 작성해주시고, scope는 repo만 체크를 합니다.

토큰 만료 시 재발급 받을 수 있으므로 Expiration도 자유입니다.

이후 아래에 있는 Generate Token 버튼을 누릅니다.

그러면 이렇게 토큰이 보이게 되는데 다른 경로로는 볼 수 없으니 반드시 바로 복사해줍니다.

만약 토큰을 잊어버렸다면 재발급을 받도록 합니다.

해당 토큰을 눌러주면 Edit 창으로 오게 되며, Regenerate token 버튼을 누르면 유효기간을 재설정하고, 새로운 토큰을 발급해줍니다.

토큰 만료 시에도 동일한 방법으로 재발급 받습니다.

 

이제 미러링을 하기 위해 생성되어 있는 GitLab 레포지토리에서 Settings -> Repository에 들어갑니다.

Mirroring repositories에 있는 Expand를 누릅니다.

이 곳에서 미러링을 진행합니다.

작성해야 할 곳은 "Git repository URL", "Password" 입니다.

Git repository URL에는 아까 위에서 메모해둔 HTTPS URL을 이용합니다.

HTTPS URL은 "https://github.com/닉네임/저장소이름.git"으로 되어있는데

github 앞에 "닉네임@"을 추가한 "https://닉네임@github.com/닉네임/저장소이름.git"을 넣어주시면 됩니다.

 

Password에는 조금 전 발급 받았던 Personal access tokens을 넣어줍니다.

이제 Mirror repository 버튼을 누릅니다.

그 후 바로 밑에 "Update now"라고 하는 새로고침 버튼을 눌러줍니다.

 

이제 생성했던 GitHub Repository에 들어가면 미러링이 완료된 것을 확인할 수 있습니다.

다만 이 방법은 GitLab에 등록했던 Issues와 Merge Request가 이동하지 않으며, Commit 기록만 이동하게 됩니다.

다른 방법이 있을지는 모르겠지만 GitLab과 GitHub은 다른 부분이 조금 있기 때문에 옮겨지지 않는다는 개인적인 생각입니다.

'Etc' 카테고리의 다른 글

GitHub Actions를 이용한 Slack Notification  (0) 2023.01.30
React Web3로 Contract 함수 호출  (2) 2023.01.10
Unity Script로 카메라 Culling Mask 기능 사용하기  (2) 2021.10.29
Unity 카메라 Culling Mask  (0) 2021.10.29
TypeScript 실행  (0) 2021.08.30

[이전글]에서 카메라의 Culling Mask에 대해 소개하였습니다.

이 글에서는 script로 Culling Mask를 특정 상황에서 변경하는 것을 다룰 것입니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
// CullingMask를 Everything으로 변경합니다.
Camera.main.cullingMask = -1;
// CullingMask를 Nothing으로 변경합니다.
Camera.main.cullingMask = 0;
// CullingMask에 "Group" Layer를 추가합니다.
Camera.main.cullingMask |= 1 << LayerMask.NameToLayer("Group");
// CullingMask에 "Group" Layer를 제거합니다.
Camera.main.cullingMask = Camera.main.cullingMask & ~(1 << LayerMask.NameToLayer("Group"));
// Nothing 상태인 CullingMask에서 Group Layer를 추가합니다.
Camera.main.cullingMask = 1 << LayerMask.NameToLayer("Group");
// Everything 상태인 CullingMask에서 Group Layer를 제거합니다.
Camera.main.cullingMask = ~(1 << LayerMask.NameToLayer("Group"));
cs

script에서 Culling Mask를 다루는 명렁어는 대략 이정도 있으며, 이를 활용하여 script를 구현합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ChangeCullingMask : MonoBehaviour
{
    void changeCullingMask(int idx)
    {
        if (idx == 0)
        {
            // CullingMask를 Everything으로 변경합니다.
            Camera.main.cullingMask = -1;
        }
        else if (idx == 1)
        {
            // CullingMask에 Group2를 추가하고 Group1을 제거합니다.
            Camera.main.cullingMask |= 1 << LayerMask.NameToLayer("Group2");
            Camera.main.cullingMask = ~(1 << LayerMask.NameToLayer("Group1"));
        }
        else
        {
            // CullingMask에 Group1을 추가하고 Group2를 제거합니다.
            Camera.main.cullingMask |= 1 << LayerMask.NameToLayer("Group1");
            Camera.main.cullingMask = ~(1 << LayerMask.NameToLayer("Group2"));
        }
    }
}
cs

위 코드는 ChangeCullingMask라는 이름의 script이며, 버튼이 눌러질 때마다 인덱스(idx)와 함께 호출될 메소드를 정의하였습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class ButtonClick : MonoBehaviour
{
    public ChangeCullingMask changeCullingMask;
    public int idx;
    private void OnMouseDown()
    {
        changeCullingMask.Change(idx);
    }
}
cs

그 다음은 ButtonClick이라는 이름의 script입니다.

마우스 클릭 이벤트로 호출되는 OnMouseDown 메소드를 사용하였습니다.

이제 버튼을 클릭할 때마다 이 메소드가 호출됩니다.

 

이제 작성한 script들을 object에 적용시키는 일만 남았습니다.

우선 메인 카메라 밑에 버튼으로 사용하기 위해 Cube 3개를 생성합니다.

 

그리고 ChangeCullingMask.cs를 MainCamera에 적용시킵니다.

 

그리고 생성해놓은 Cube들에 ButtonClick.cs를 적용시킨 후에

ChangeCullingMask에 MainCamera를 넣고, 인덱스(idx)를 0 1 2로 각각 지정해줍니다.

 

 

이제 실행해봅니다.

먼저 첫번째 Cube를 클릭한 모습입니다.

idx = 0이며, CullingMask를 Everything으로 변경하여 모든 Object를 볼 수 있습니다.

 

두번째 Cube를 클릭한 모습입니다.

idx = 1이며, "Group1" Layer를 지정한 파란색 Cube들이 카메라에 보이지 않습니다.

 

세번째 Cube를 클릭한 모습입니다.

idx = 2이며, "Group1" Layer를 지정한 파란색 Cube들이 다시 카메라에 보이고 "Group2" Layer를 지정한 빨간색 Cube들이 카메라에 보이지 않습니다.

 

이런식으로 여러 상황에서 CullingMask를 변경하여 카메라에 특정 Object만 보이게 설정할 수 있습니다.

'Etc' 카테고리의 다른 글

React Web3로 Contract 함수 호출  (2) 2023.01.10
GitLab -> GitHub Mirroring  (0) 2022.06.12
Unity 카메라 Culling Mask  (0) 2021.10.29
TypeScript 실행  (0) 2021.08.30
TypeScript 설치  (0) 2021.08.30

Unity의 Culling Mask란 원하는 Layer를 가진 Object들만 카메라로 볼 수 있게 하는 기능입니다.

image

우선 여러개의 Cube를 생성하여 그룹을 나눕니다. (Group1, Group2)

구별을 위해 Group1에는 파란색, Group2에는 빨간색 Material을 넣었습니다.

 

그리고 그룹 간 구분을 위해 Layer -> Add Layer에서 Layer를 두개 만들어줍니다.
저는 "Group1"과 "Group2"를 생성하였습니다.

imageimage

 

그 다음 Group1에 "Group1" 이라는 Layer를, Group2에 "Group2" 라는 Layer를 추가해 넣어줍니다.

imageimage

이제 Culling Mask 사용을 위한 준비가 끝났습니다.

 

Main Camera의 Inspector -> Camera Component에 Culling Mask가 있습니다.
현재 Everything이 default로 지정이 되어있으며, 모든 Object를 카메라로 보여주고 있습니다.

image

그리고 현재 메인 카메라에 보이는 모습입니다.

 

이제 Culling Mask에서 Group1을 지우겠습니다.

Group1을 체크 해제하는 순간 Culling Mask는 Everything -> Mixed가 되는 것을 볼 수 있으며

Scene 창에서는 Group1이 보이지만 메인 카메라 화면에는 보이지 않는 것을 확인할 수 있습니다.

 

다만 카메라에는 안보이지만 실제로 존재하는 Object이므로 충돌 판정은 있습니다.

Collider를 없애서 그냥 통과하게 만들거나 하는 응용도 가능해보입니다.

'Etc' 카테고리의 다른 글

GitLab -> GitHub Mirroring  (0) 2022.06.12
Unity Script로 카메라 Culling Mask 기능 사용하기  (2) 2021.10.29
TypeScript 실행  (0) 2021.08.30
TypeScript 설치  (0) 2021.08.30
Windows 10 에서 WSL을 이용한 우분투 설치  (0) 2021.08.29

TypeScript를 설치했으니 이제 실행을 테스트 해야합니다.

 

TypeScript 실행에는 두 가지 방법이 있습니다.

  1. TypeScript를 JavaScript로 변환하여 실행하는 방법
  2. TypeScript를 바로 실행하는 방법

 

간단하게 작성된 코드를 실행합니다.

 

TypeScript를 JavaScript로 변환하여 실행하는 방법

아래의 명령어를 입력하여 JavaScript로 변환합니다.

tsc test.ts

그러면 같은 폴더에 test.js라는 JavaScript 파일이 생기고

 

열어보면 TypeScript에서 작성했던 코드가 변환되어 있음을 알 수 있습니다.

이제 아래의 명령어로 test.js를 실행합니다.

node test.js

이렇게 실행이 잘되는 것을 확인할 수 있습니다.

 

 

TypeScript를 바로 실행하는 방법

구글링을 하던 도중 ts-node를 통해 실행한다는 것을 알게되어 따라 해보았습니다.

 

ts-node는 아래의 명령어를 통해 설치합니다.

npm install -g ts-node

 

그 다음 아래의 명령어로 바로 실행을 합니다.

ts-node test.ts

네 그러면 에러가 발생합니다.

이를 해결하기 위해서는 tsconfig.json 이라는 TypeScript 설정 파일이 필요합니다.

직접 작성해도 되지만 아래의 명령어를 통해 자동 생성을 하였습니다.

그러면 Successfully 메시지와 함께 tsconfig.json 파일이 생깁니다.

 

이제 ts-node test.ts로 실행합니다.

이제 실행이 잘되는 것을 확인할 수 있습니다.

'Etc' 카테고리의 다른 글

Unity Script로 카메라 Culling Mask 기능 사용하기  (2) 2021.10.29
Unity 카메라 Culling Mask  (0) 2021.10.29
TypeScript 설치  (0) 2021.08.30
Windows 10 에서 WSL을 이용한 우분투 설치  (0) 2021.08.29
C++ cout 소수점 고정  (0) 2021.08.05

TypeScript를 설치하기 위해서는 nodejs가 먼저 설치되어 있어야합니다.

 

https://nodejs.org/ko/

 

Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

여기서 nodejs를 설치합니다.

 

cmd에 node -v나 node --version을 쳐서 버전이 나오면 설치가 된겁니다.

 

그 다음 밑의 명령어를 통해 TypeScript를 설치합니다.

npm install -g typescript

설치 이후에 tsc -v나 tsc --version을 쳐서 버전이 나오면 설치가 된겁니다.

 

 

혹시 vscode에서 tsc -v 입력 시 이런 에러가 발생한다면 Windows 정책으로 PowerShell 실행에 제한이 있기 때문입니다.

 

그런 경우에는 Windows PowerShell을 켜서 Set-ExecutionPolicy Unrestricted를 입력 후 y를 입력합니다.

 

그러면 버전이 잘 뜨는것을 확인할 수 있습니다.

'Etc' 카테고리의 다른 글

Unity 카메라 Culling Mask  (0) 2021.10.29
TypeScript 실행  (0) 2021.08.30
Windows 10 에서 WSL을 이용한 우분투 설치  (0) 2021.08.29
C++ cout 소수점 고정  (0) 2021.08.05
Java 문자열이 정수인지 확인  (0) 2021.06.01

Windows 10에 WSL이라는 Linux용 Windows 하위 시스템 기능을 이용하여 우분투를 설치하는 과정입니다.

 

먼저 Windows 기능 켜기/끄기 라는 프로그램을 실행시킵니다.

 

Linux용 Windows 하위 시스템을 체크하고 확인을 누릅니다.

 

그러면 PC를 재부팅 해라고 합니다.

재부팅을 해줍니다.

 

그 다음 Microsoft Store 앱을 켜줍니다.

 

WSL을 검색하여 Ubuntu를 설치하고 실행합니다.

 

첫 화면으로는 몇 분 동안 설치를 진행합니다.

 

그 다음 새 계정정보를 입력하면 설치가 완료됩니다!

 

 

싸피에서 우분투를 쓸 기회가 있었지만 이 부분은 다른 팀원분이 맡아주셨기에 처음이네요.

익숙해질 정도로 써봐야할 것 같습니다.

'Etc' 카테고리의 다른 글

TypeScript 실행  (0) 2021.08.30
TypeScript 설치  (0) 2021.08.30
C++ cout 소수점 고정  (0) 2021.08.05
Java 문자열이 정수인지 확인  (0) 2021.06.01
localStorage를 이용한 데이터 저장  (0) 2021.05.11

알고리즘 문제를 풀다보면 "소수점 2자리까지 출력하시오" 라고 하는 문제를 자주 보실겁니다..

이런 문제들을 매번 볼때마다 검색하는 저를 발견하였기에 정리합니다.

 

cout << fixed; 으로 소수점 자릿수를 고정합니다.

그 다음 cout.precision(n);으로 고정할 소수점 자리를 지정합니다.

이제 출력하시면 됩니다.

 

소수점을 3자리로 고정했으니 3자리까지만 출력됩니다.

 

 

다만 위의 사진처럼 소수점 아래에서 반올림을 해서 출력을 하니 이부분 조심해서 사용해야합니다.

'Etc' 카테고리의 다른 글

TypeScript 설치  (0) 2021.08.30
Windows 10 에서 WSL을 이용한 우분투 설치  (0) 2021.08.29
Java 문자열이 정수인지 확인  (0) 2021.06.01
localStorage를 이용한 데이터 저장  (0) 2021.05.11
Java 소수점 자리출력  (0) 2021.03.03

matches 메소드와 정규식을 이용하여 해당 문자열이 정수인지 확인할 수 있습니다.

 

str.matches("-?\\d+")

=> 참이면 true, 거짓이면 false를 리턴합니다.

1
2
3
if(price != null && !price.matches("-?\\d+")) {
    System.out.println("price 정수 아님");
}
cs

 

'Etc' 카테고리의 다른 글

TypeScript 설치  (0) 2021.08.30
Windows 10 에서 WSL을 이용한 우분투 설치  (0) 2021.08.29
C++ cout 소수점 고정  (0) 2021.08.05
localStorage를 이용한 데이터 저장  (0) 2021.05.11
Java 소수점 자리출력  (0) 2021.03.03

+ Recent posts