반응형

GIMP를 이용해 투명 배경을 만들어 보자.

 

Mario.png
0.00MB

투명 배경이 필요한 그림을 준비한다.

 

GIMP로 불러온다.

 

Layer - Transparency - Color to Alpha... 를 선택한다.

 

Color의 컬러 픽커를 이용하면 정확히 한 픽셀을 선택하기가 어렵다. 위 그림과 같이 여러 픽셀이 선택되면 평균값이 계산 되는거 같다.

 

Color를 선택해 원하는 색을 직접 입력하자. [0..100], [0..255] 선택에 주의한다.

 

투명하게 만들 색을 입력하고 확인하면 Alpha Channel이 생성되고 배경이 투명하게 바뀐다.

 

File - Export As... 를 선택하고 PNG 파일로 저장한다.

 

반응형
Posted by J-sean
:
반응형

Godot Sprite에는 Colorkey를 설정하는 옵션이 없다.PNG 이미지는 알파 채널을 통해 투명 배경을 설정할 수 있어 상관 없지만 JPG, BMP같은 이미지 파일은 투명 배경이 없어 곤란하다. 하지만 셰이더를 이용해 같은 효과를 만들 수 있다.

 

스프라이트를 추가하고 텍스쳐를 지정한다.

 

Material - New Shader Material을 선택한다.

 

Shader - New Shader를 선택한다.

 

적당한 이름을 지정하고 셰이더 파일을 생성한다.

 

 

Shader Editor를 활성화 한다.

 

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
shader_type canvas_item;
// Get texture and a key that we want as transparent
uniform sampler2D Diffuse;
uniform vec4 ChromaKey : source_color;
 
void vertex() {
    // Called for every vertex the material is visible on.
}
 
void fragment() {
    // Called for every pixel the material is visible on.
    
    // The color value is the sampled pixel color
    COLOR = texture(Diffuse, UV);
 
    // If the color is the same as the chroma key, make it transparent.
    if (COLOR == ChromaKey) {
        COLOR.a = 0.0;
    }
}
 
//void light() {
    // Called for every pixel for every light affecting the CanvasItem.
    // Uncomment to replace the default light processing function with this one.
//}
 

 

위와 같은 코드를 작성한다.

 

Shader Parameters를 아래와 같이 지정한다.

ChromaKey: R:54 G:61 B:82 A:255 (Godot 이미지의 배경색)

Diffuse: 텍스쳐 이미지와 동일하게 지정

※ Diffuse에 이미지 지정시 Texture 파라미터의 filter를 선택할 수 없어 이미지가 흐리게 보일 수 있다. 필요하다면 셰이더 코드에서 Diffuse 선언을 아래와 같이 수정한다.

uniform sampler2D Diffuse : filter_nearest;

 

Godot 이미지의 배경이 투명해졌다.

 

 

하지만 게임을 실행해 보면 배경이 투명하지 않다.

 

1
2
3
4
// If the color is the same as the chroma key, make it transparent.
if (distance(COLOR, ChromaKey) < 0.001) {
    COLOR.a = 0.0;
}
 

 

vec4 타입의 ChromaKey와 COLOR 데이터 타입의 비교에서 약간의 오차가 발생하는거 같다.

if()을 위와 같이 수정한다.

 

원하는 색이 정상적으로 투명하게 변한다.

 

※ 참고

이렇게 하나의 스프라이트에 셰이더를 적용하면 같은 씬의 다른 스프라이트에도 모두 같은 방식으로 셰이더를 적용해야 아래와 같은 에러가 생기지 않는 경우가 발생할 수 있다.

E 0:00:01:0199   swap_buffers: Vulkan: Cannot submit graphics queue. Error code: VK_ERROR_DEVICE_LOST
  <C++ Error>    Condition "err" is true. Returning: ERR_CANT_CREATE
  <C++ Source>   drivers/vulkan/vulkan_context.cpp:2536 @ swap_buffers()
E 0:00:01:0208   prepare_buffers: Vulkan: Did not create swapchain successfully. Error code: VK_NOT_READY
  <C++ Error>    Condition "err != VK_SUCCESS" is true. Breaking.
  <C++ Source>   drivers/vulkan/vulkan_context.cpp:2459 @ prepare_buffers()

 

반응형
Posted by J-sean
:
반응형

SDL 기본 라이브러리는 BMP 형식의 이미지만 처리할 수 있다. JPG나 PNG 형식을 처리하기 위해서는 SDL_image 라이브러리가 필요하다.

 

우선 SDL 기본 라이브러리로 BMP 이미지를 렌더링 해 보자.

 

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
#include <iostream>
#include "SDL.h"
 
#pragma comment(lib, "sdl2.lib")
#pragma comment(lib, "sdl2main.lib")
 
int main(int argc, char* argv[]) {
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("SDL Initialization Fail: %s\n", SDL_GetError());
        return -1;
    }
 
    SDL_Window* window = SDL_CreateWindow("SDL Test", SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED, 640480, SDL_WINDOW_RESIZABLE);
 
    if (!window) {
        printf("SDL_CreateWindow Error: %s\n", SDL_GetError());
        SDL_Quit();
        return -1;
    }
 
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -10);
 
    SDL_Surface* bmpSurface = SDL_LoadBMP("image.bmp");
    // Load a BMP image from a file path.
    if (bmpSurface == NULL) {
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        printf("SDL_LoadBMP Error: %s\n", SDL_GetError());
        SDL_Quit();
        return -1;
    }
    SDL_Rect destRect = { 00, bmpSurface->w, bmpSurface->h };
 
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, bmpSurface);
    // Create a texture from an existing surface.
    if (texture == NULL) {
        SDL_FreeSurface(bmpSurface);
        // Free an RGB surface.
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        printf("SDL_CreateTextureFromSurface Error: %s\n", SDL_GetError());
        SDL_Quit();
        return -1;
    }
    SDL_FreeSurface(bmpSurface);
 
    SDL_Event event;
    bool quit = false;
 
    while (!quit) {
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                quit = true;
                break;
            case SDL_KEYDOWN:
                printf("Key pressed: %s\n", SDL_GetKeyName(event.key.keysym.sym));
                if (event.key.keysym.sym == SDLK_ESCAPE)
                    quit = true;
                break;
            default:
                break;
            }
        }
 
        SDL_SetRenderDrawColor(renderer, 255255255, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, NULL&destRect);
        // Copy a portion of the texture to the current rendering target.
        SDL_RenderPresent(renderer);
    }
 
    SDL_DestroyTexture(texture);
    // Destroy the specified texture.
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}
 

 

코드를 작성하고 빌드한다.

 

실행하면 윈도우에 이미지가 렌더링 된다.

 

만약 그래픽 카드의 지원을 받을 수 없는 Embedded System 등에서 소프트웨어 방식의 렌더링만 사용할 수 있다면 Texture, Renderer 를 사용하지 않고 Window Surface, BMP Surface 를 사용해 직접 화면에 이미지를 출력할 수 있다.

 

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
#include <iostream>
#include "SDL.h"
 
#pragma comment(lib, "sdl2.lib")
#pragma comment(lib, "sdl2main.lib")
 
int main(int argc, char* argv[]) {
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("SDL Initialization Fail: %s\n", SDL_GetError());
        return -1;
    }
 
    SDL_Window* window = SDL_CreateWindow("SDL Test", SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED, 640480, SDL_WINDOW_RESIZABLE);
 
    if (!window) {
        printf("SDL_CreateWindow Error: %s\n", SDL_GetError());
        SDL_Quit();
        return -1;
    }
 
    SDL_Surface* windowSurface = SDL_GetWindowSurface(window);
    // Get the SDL surface associated with the window.
    // A new surface will be created with the optimal format for the window,
    // if necessary. This surface will be freed when the window is destroyed.
    // Do not free this surface.
    // This surface will be invalidated if the window is resized. After resizing
    // a window this function must be called again to return a valid surface.
    // You may not combine this with 3D or the rendering API on this window.
 
    SDL_Surface* bmpSurface = SDL_LoadBMP("image.bmp");
    if (bmpSurface == NULL) {
        SDL_DestroyWindow(window);
        printf("SDL_LoadBMP Error: %s\n", SDL_GetError());
        SDL_Quit();
        return -1;
    }
 
    SDL_Event event;
    bool quit = false;
 
    while (!quit) {
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                quit = true;
                break;
            case SDL_KEYDOWN:
                printf("Key pressed: %s\n", SDL_GetKeyName(event.key.keysym.sym));
                if (event.key.keysym.sym == SDLK_ESCAPE)
                    quit = true;
                break;
            default:
                break;
            }
        }
 
        SDL_BlitSurface(bmpSurface, NULL, windowSurface, NULL);
        // Use this function to perform a fast surface copy to a destination surface.
        SDL_UpdateWindowSurface(window);
        // Copy the window surface to the screen. This is the function you use to
        // reflect any changes to the surface on the screen.
    }
 
    SDL_FreeSurface(bmpSurface);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}
 

 

코드를 작성하고 빌드한다.

 

윈도우에 이미지가 출력된다.

 

 

 

이번엔 SDL_image를 이용해 JPG, PNG 등의 이미지를 출력해 보자. 아래 링크에서 SDL_image를 다운받고 적당히 설치한다.

SDL Libraries

 

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
#include <iostream>
#include "SDL.h"
#include "SDL_image.h"
 
#pragma comment(lib, "sdl2.lib")
#pragma comment(lib, "sdl2main.lib")
#pragma comment(lib, "sdl2_image.lib")
 
int main(int argc, char* argv[]) {
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = SDL_CreateWindow("SDL Test", SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED, 640480, SDL_WINDOW_RESIZABLE);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    // SDL_RENDERER_SOFTWARE: the renderer is a software fallback
    // SDL_RENDERER_ACCELERATED : the renderer uses hardware acceleration
    // SDL_RENDERER_PRESENTVSYNC : present is synchronized with the refresh rate
    // SDL_RENDERER_TARGETTEXTURE : the renderer supports rendering to texture
    // Note that providing no flags gives priority to available SDL_RENDERER_ACCELERATED
    // renderers.
 
    IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
    // Initialize SDL_image.
 
    SDL_Surface* imageSurface = IMG_Load("image.png");
    // Load an image from a filesystem path into a software surface.
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, imageSurface);
    SDL_Rect destRect = { 00, imageSurface->w, imageSurface->h };
 
    SDL_Event event;
    bool quit = false;
 
    while (!quit) {
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                quit = true;
                break;
            case SDL_KEYDOWN:
                printf("Key pressed: %s\n", SDL_GetKeyName(event.key.keysym.sym));
                if (event.key.keysym.sym == SDLK_ESCAPE)
                    quit = true;
                break;
            default:
                break;
            }
        }
 
        //SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
        //SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, NULL&destRect);
        SDL_RenderPresent(renderer);
    }
 
    SDL_DestroyTexture(texture);
    SDL_FreeSurface(imageSurface);
    IMG_Quit();
    // Deinitialize SDL_image.
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}
 

 

코드를 입력하고 빌드한다.

 

실행하면 윈도우에 이미지가 렌더링 된다.

 

주석처리된 배경 처리 부분을 아래와 같이 해제하고 알파 채널이 있는 PNG 파일을 렌더링 해 보자.

 

SDL_SetRenderDrawColor(renderer, 0, 0, 255, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);

 

player.png
0.00MB

 

 

 

특별한 처리 없이도 알파 채널이 보존되어 투명한 부분이 잘 표현된다.

 

※ 참고

SDL_image API

 

반응형
Posted by J-sean
: