ThirdPerson 예제를 C++ 로 만든후, MyDrone 클래스를 생성후 다음과 같이 작성한다.

 

MyDrone 클래스를 상속받아 BluePrint를 생성한다.

다음과 같이 생성된다.

각각 Mesh를 쒸운다.

 

MyDone 클래스에 FloatingPawnMovement Component 을 추가한다.

 

 

빌드후 블루프린트로 확인한다.

 

다음과 같이 수정한다.

Character 클래스에 MyDrone 래퍼런스를 추가한다.

그후 다음과 같이 설정한다. EditAnywhere 로 설정하였기 때문에 디테일탭에서 볼 수 있다.

Input 설정에서 다음과 같이 추가한다.

 

MyDrone 클래스에 EDroneState 를 추가한다.

 

드론을 활성화 시키기 위하여  Activate funtion을 만든다.

 

 

 

Character 클래스에 드론을 활성화 시키기 위한 토글버튼을 바인드 한다.

 

이제 게임을 시작해보면, 카메라의 시점의 드론으로 이동하는것을 볼 수 있다.

 

이젠, 드론의 움직임을 구현해보자.

 

빌드후 실행한후 F키를 클릭하면 드론이 움직이는것을 확인 할 수 있다.

 

 

드론을 비활성화 하는 코드를 작성한다.

 

게임을 시작후 드론 시점에서 F를 클릭하면 캐릭터로 돌아오는것을 볼 수 있다.

 

 

드론에 SpringArm 과 카메라를 추가하여 좀더 보기좋게 만들자.

 

이젠 블루프린트에 SpringArm과 Camera가 추가된것을 볼 수 있다.

다음과 같이 적당한 위치로 수정하자.

 

 

다음은 프로펠러를 돌려보자.

 

먼저 프로펠러 매시의 pivot을 중앙으로 변경후 작업해야 한다.

작업이 끝났으면,

 

다음과 같이 작성한다.

 

빌드후 프로펠러가 돌아가는것을 확인 할 수 있다.

 

 

Boolean 변수를 하나 추가시켜 카메라 스위치 on off를 만든다.

빌드후 실행해보면 카메라이동 없이 드론을 움직일 수 있다.

 

하지만, 캐릭터로 소유권이 넘어올때 카메라가 뷰가 다시 설정되어 부자연 스럽다.

이부분을 수정해 보자.

 

Character 클래스의 PossessedBy, UnPossessed 그리고 Tick 함수를 오버라이드 한다.

 

빌드후 실행을 해보면 토글을 했을때 카메라 시점에 변화가 없는것을 볼 수 있다.

 

<basic.frag>

1
2
3
4
5
6
7
#version 400
in vec3 Color;
out vec4 FragColor;
void main() {
    FragColor = vec4(Color, 1.0);
}
 
cs

 

 

 

<basic.vert>

1
2
3
4
5
6
7
8
9
10
11
12
#version 400
in vec3 VertexPosition;
in vec3 VertexColor;
out vec3 Color;
 
uniform mat4 MVP;
 
void main()
{
    Color = VertexColor;
    gl_Position = MVP * vec4(VertexPosition, 1.0);
}
cs

 

 

<main>

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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
using namespace std;
 
#include "stdlib.h"
#include "time.h"
#include <GL/glew.h>
#include <GL/freeglut.h>
 
#include "glm\glm.hpp"
#include "glm\gtc\matrix_transform.hpp"
#include <string>
#include <fstream>
#include <array>
 
 
// Prototypes
int setShader(char* shaderType, char* shaderFile);
char* readShader(std::string fileName);
void timer(int);
void createModel(int n);
 
#define BUFFER_OFFSET(x)  ((const void*) (x))
#define FPS 60
#define X_AXIS glm::vec3(1,0,0)
#define Y_AXIS glm::vec3(0,1,0)
#define Z_AXIS glm::vec3(0,0,1)
#define XY_AXIS glm::vec3(1,0.9,0)
#define YZ_AXIS glm::vec3(0,1,1)
#define XZ_AXIS glm::vec3(1,0,1)
 
 
static unsigned int
program,
vertexShaderId,
fragmentShaderId;
 
glm::mat4 MVP, View, Projection;
GLuint vao, points_vbo, colors_vbo, modelID, indices_vbo;
int randomColorSeed[10];
 
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 5.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 cameraRight = glm::vec3(1.0f, 0.0f, 0.0f);
float cameraSpeed = 0.2;
 
float scale = 1.0f, inc = -0.05f, angle1 = 0.0f, angle2 = 0.0f;
 
 
static float R = 2.0// Radius of circle.
static float X = 0.0// X-coordinate of center of circle.
static float Y = 0.0// Y-coordinate of center of circle.
const int MaxNumVertices = 500// Number of vertices on circle.
static int numVertices = 10;
#define PI 3.14159265358979324
 
float theta = 0.0f;
 
std::array<glm::vec3, MaxNumVertices> vertices = {};
std::array<glm::vec3, MaxNumVertices> colors = {};
 
GLfloat shape_vertices[MaxNumVertices][3= { 0.0f, };
GLfloat shape_colors[MaxNumVertices][3= { 0.0f, };
GLuint shape_indices[MaxNumVertices] = { 0, };
 
void init(void)
{
    // Create shader program executable.
    vertexShaderId = setShader((char*)"vertex", (char*)"basic.vert");
    fragmentShaderId = setShader((char*)"fragment", (char*)"basic.frag");
    program = glCreateProgram();
    glAttachShader(program, vertexShaderId);
    glAttachShader(program, fragmentShaderId);
    glLinkProgram(program);
    glUseProgram(program);
 
    modelID = glGetUniformLocation(program, "MVP");
 
    // Projection matrix : 45∞ Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
    //Projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100.0f);
    // Or, for an ortho camera :
    Projection = glm::ortho(-3.0f, 3.0f, -3.0f, 3.0f, 0.0f, 100.0f); // In world coordinates
 
    // Camera matrix
    View = glm::lookAt(
        glm::vec3(003), // Origin. Camera is at (0,0,3), in World Space
        glm::vec3(000),      // Look target. Looks at the origin
        glm::vec3(010)   // Up vector. Head is up (set to 0,-1,0 to look upside-down)
    );
 
 
    // Create and set-up the vertex array object
    glGenVertexArrays(1&vao);
    glBindVertexArray(vao);
 
 
 
    // vertex
    glGenBuffers(1&points_vbo);
    // Populate the position buffer
    glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
    // don't need to do now
    //glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float), cube_vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(03, GL_FLOAT, GL_FALSE, 0, (GLubyte*)NULL);
    // Enable the vertex attribute arrays
    glEnableVertexAttribArray(0); // for Vertex position
 
    // color
    glGenBuffers(1&colors_vbo);
    // Populate the color buffer
    glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
    // don't need to do now
    //glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float), colors, GL_STATIC_DRAW);
    glVertexAttribPointer(13, GL_FLOAT, GL_FALSE, 0, (GLubyte*)NULL);
    glEnableVertexAttribArray(1); // for Vertex color
 
 
 
    glGenBuffers(1&indices_vbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_vbo);
    //glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_indices), cube_indices, GL_STATIC_DRAW);
 
 
    glEnable(GL_DEPTH_TEST);
    timer(0);
}
 
//---------------------------------------------------------------------
//
// transformModel
//
void transformObject(float scale, glm::vec3 rotationAxis, float rotationAngle, glm::vec3 translation) {
    glm::mat4 Model;
    Model = glm::mat4(1.0f);
    Model = glm::translate(Model, translation);
    Model = glm::rotate(Model, glm::radians(rotationAngle), rotationAxis);
    Model = glm::scale(Model, glm::vec3(scale));
 
    View = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
    //View = glm::lookAt(
    //    glm::vec3(xVal, yVal, 5), // Origin. Camera is at (0,0,3), in World Space
    //    glm::vec3(0, 0, -4),      // Look target. Looks at the origin
    //    glm::vec3(0, 1, 0)   // Up vector. Head is up (set to 0,-1,0 to look upside-down)
    //);
    MVP = Projection * View * Model;
    glUniformMatrix4fv(modelID, 1, GL_FALSE, &MVP[0][0]);
}
 
//---------------------------------------------------------------------
//
// display
//
 
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    glBindVertexArray(vao);
 
    transformObject(1.0f, XY_AXIS, angle1 += 0.f, glm::vec3(0.0f, 0.0f, 0.0f));
 
    createModel(numVertices);
    glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(shape_vertices), shape_vertices, GL_STATIC_DRAW);
 
    glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(shape_colors), shape_colors, GL_STATIC_DRAW);
 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices_vbo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(shape_indices), shape_indices, GL_STATIC_DRAW);
 
    // by array
    //glDrawArrays(GL_TRIANGLE_FAN, 0, numVertices);
 
    // by element array
    glDrawElements(GL_TRIANGLE_FAN, numVertices, GL_UNSIGNED_INT, NULL);
 
 
    glutSwapBuffers(); // Now for a potentially smoother render.
}
 
void idle() // Not even called.
{
    glutPostRedisplay();
}
 
void timer(int) {
    glutPostRedisplay();
    glutTimerFunc(1000 / FPS, timer, 0);
}
 
 
// Keyboard input processing routine.
void keyDown(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 27:
            exit(0);
            break;
        case 'w':
            cameraPos += cameraSpeed * cameraFront;
            break;
        case 's':
            cameraPos -= cameraSpeed * cameraFront;
            break;
        case 'r':
            cameraPos -= glm::normalize(glm::cross(cameraFront, cameraRight)) * cameraSpeed;
            break;
        case 'f':
            cameraPos += glm::normalize(glm::cross(cameraFront, cameraRight)) * cameraSpeed;
            break;
        case 'a':
            cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
            break;
        case 'd':
            cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
            break;
        case '+':
            numVertices++;
            break;
        default:
            break;
    }
}
 
//---------------------------------------------------------------------
//
// main
//
 
int main(int argc, char** argv)
{
    //Before we can open a window, theremust be interaction between the windowing systemand OpenGL.In GLUT, this interaction is initiated by the following function call :
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
 
    //if you comment out this line, a window is created with a default size
    glutInitWindowSize(800800);
 
    //the top-left corner of the display
    glutInitWindowPosition(00);
 
    glutCreateWindow("GAME2012_A2_KongWoonhak, 101300258");
 
    // background color is white
    glClearColor(0.0f, 0.5f, 0.5f, 1.0f);
    glewInit();    //Initializes the glew and prepares the drawing pipeline.
 
    init(); // Our own custom function.
 
    //If there are events in the queue, our program responds to them through functions
    //called callbacks.A callback function is associated with a specific type of event.
    //A display callback is generated when the application programm or the
    //operating system determines that the graphics in a window need to be redrawn.
    glutDisplayFunc(display); // Output.
    //glutIdleFunc(idle);
 
    glutKeyboardFunc(keyDown); // Input.
 
    //begin an event-processing loop
    glutMainLoop();
}
 
// Function to initialize shaders.
int setShader(char* shaderType, char* shaderFile)
{
    int shaderId;
    char* shader = readShader(shaderFile);
 
    if (shaderType == "vertex") shaderId = glCreateShader(GL_VERTEX_SHADER);
    if (shaderType == "tessControl") shaderId = glCreateShader(GL_TESS_CONTROL_SHADER);
    if (shaderType == "tessEvaluation") shaderId = glCreateShader(GL_TESS_EVALUATION_SHADER);
    if (shaderType == "geometry") shaderId = glCreateShader(GL_GEOMETRY_SHADER);
    if (shaderType == "fragment") shaderId = glCreateShader(GL_FRAGMENT_SHADER);
 
    glShaderSource(shaderId, 1, (const char**)&shader, NULL);
    glCompileShader(shaderId);
 
    return shaderId;
}
// Function to read external shader file.
char* readShader(std::string fileName)
{
    // Initialize input stream.
    std::ifstream inFile(fileName.c_str(), std::ios::binary);
 
    // Determine shader file length and reserve space to read it in.
    inFile.seekg(0std::ios::end);
    int fileLength = inFile.tellg();
    char* fileContent = (char*)malloc((fileLength + 1* sizeof(char));
 
    // Read in shader file, set last character to NUL, close input stream.
    inFile.seekg(0std::ios::beg);
    inFile.read(fileContent, fileLength);
    fileContent[fileLength] = '\0';
    inFile.close();
 
    return fileContent;
}
 
void createModel(int n)
{
    theta = 0.0f;
    for (int i = 0; i < n; ++i)
    {
 
        vertices[i] = glm::vec3(X + R * cos(theta), Y + R * sin(theta), 0.0);
        colors[i] = glm::vec3((float)rand() / (float)RAND_MAX, (float)rand() / (float)RAND_MAX, (float)rand() / (float)RAND_MAX);
 
        theta += 2 * PI / n;
    }
 
    for (int i = 0; i < n; ++i) {
 
        shape_vertices[i][0= vertices[i].x;
        shape_vertices[i][1= vertices[i].y;
        shape_vertices[i][2= vertices[i].z;
 
        shape_colors[i][0= colors[i][0];
        shape_colors[i][1= colors[i][1];
        shape_colors[i][2= colors[i][2];
 
        // for indices
        shape_indices[i] = i;
    }
 
 
}
cs

 

 

 

<결과>

 

<소스코드>

https://github.com/woonhak-kong/OpenGL_Practice12_dynamic_polygon

'OpenGL' 카테고리의 다른 글

opengl 주사위 만들기  (0) 2021.11.16
Opengl Texture  (0) 2021.11.07
opengl 카메라 이동  (0) 2021.10.02
opengl perspective  (0) 2021.10.02
opengl 직육면체 그리기  (0) 2021.10.02

프로젝트를 Blank C++ 로 생성한후, Pawn을 c++로 만든다.

생성된 c++을 상속하는 BluePrint를 만든다.

게임모드 베이스를 생성한다.

 

만들어진 게임모드베이스를 상속하여 BT를 만든다.

만들어진 BT에서 디폴드 폰을 다음과 같이 변경한다.

프로젝트 세팅에서 Maps & Modes 에서 다음과 같이 변경한다.

 

그후 World Outliner에서 PlayerStart를 삭제한후 게임을 실행시키면 다음과 같이 생성되는것을 볼 수 있다.

 

MyPawn class 헤더파일에 다음과 같이 추가한다.

 

생성자에 다음과 같이 코딩한다.

빌드후, BT pawn 파일을 엔진에서 열어보면 다음과 같이 생성된 컴퍼넌트들을 볼 수 있다.

적절하게 모양을 바꿔주자

 

 

그후 BT_Pawn 파일을 드레그해 월드에 생성한후 다음과 같이 auto possess player을 설정한다.

 

게임을 플레이하면 pawn이 생성되어 카메라가 붙은것을 확인 할 수 있다.

 

다음과 같이 키 바인딩 한다.

 

다음과 같이 pawn을 코딩한다.

<헤더>

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
// Fill out your copyright notice in the Description page of Project Settings.
 
#pragma once
 
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"
 
UCLASS()
class LAB5_KONG_WOONHAK_API AMyPawn : public APawn
{
    GENERATED_BODY()
 
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "My Pawn", meta = (AllowPrivateAccess = "true"))
    class UStaticMeshComponent* MeshComponent;
 
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "My Pawn", meta = (AllowPrivateAccess = "true"))
    class UCameraComponent* FollowCamera;
 
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "My Pawn", meta = (AllowPrivateAccess = "true"))
    class USpringArmComponent* SpringArm;
 
 
 
 
public:
    // Sets default values for this pawn's properties
    AMyPawn();
 
    void CalculateForwardInput(float value);
    void CalculateRightInput(float value);
    void CalculateRotationInput(float value);
    void Move();
    void Rotate();
 
    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Movement");
    float MoveSpeed = 500;
 
    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Movement");
    float RotateSpeed = 100;
 
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Movement");
    FVector MoveForwardDirection;
 
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Movement");
    FVector MoveRightDirection;
 
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Movement");
    FQuat RotationDirection;
 
 
 
protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;
 
public:
    // Called every frame
    virtual void Tick(float DeltaTime) override;
 
    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
 
};
 
cs

 

<cpp>

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
// Fill out your copyright notice in the Description page of Project Settings.
 
 
#include "MyPawn.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
 
// Sets default values
AMyPawn::AMyPawn()
{
     // Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;
 
    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
    SetRootComponent(Cast<USceneComponent>(MeshComponent));
 
    SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    SpringArm->SetupAttachment(RootComponent);
 
    FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
    FollowCamera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);
 
}
 
void AMyPawn::CalculateForwardInput(float value)
{
    MoveForwardDirection= FVector(value * MoveSpeed * GetWorld()->DeltaTimeSeconds, 00);
 
}
 
void AMyPawn::CalculateRightInput(float value)
{
    MoveRightDirection = FVector(0, value * MoveSpeed * GetWorld()->DeltaTimeSeconds, 0);
}
 
void AMyPawn::CalculateRotationInput(float value)
{
    float RotateAmount = value * RotateSpeed * GetWorld()->DeltaTimeSeconds;
    FRotator Rotation = FRotator(0, RotateAmount, 0);
    RotationDirection = FQuat(Rotation);
    //UE_LOG(LogTemp, Warning, TEXT("value  = %f"), value);
}
 
void AMyPawn::Move()
{
    FVector MoveDirection = MoveForwardDirection + MoveRightDirection;
    AddActorLocalOffset(MoveDirection, true);
}
 
void AMyPawn::Rotate()
{
    AddActorLocalRotation(RotationDirection, true);
}
 
// Called when the game starts or when spawned
void AMyPawn::BeginPlay()
{
    Super::BeginPlay();
 
}
 
// Called every frame
void AMyPawn::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
 
    Move();
    Rotate();
}
 
// Called to bind functionality to input
void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);
 
    PlayerInputComponent->BindAxis("MoveForward"this&AMyPawn::CalculateForwardInput);
    PlayerInputComponent->BindAxis("MoveRight"this&AMyPawn::CalculateRightInput);
    PlayerInputComponent->BindAxis("Turn"this&AMyPawn::CalculateRotationInput);
 
}
 
 
cs

 

그후 게임을 실행하면 이동할 수 있다.

 

+ Recent posts