반응형

raylib로 간단한 파티클 시스템을 만들어 보자.

 

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
#include "raylib.h"
 
const int screenWidth = 640;
const int screenHeight = 480;
 
Texture2D texture;
 
class Particles {
private:
    Vector2 position;
    Vector2 velocity;
public:
    Particles() {
        Reset();
    }
 
    void Draw_particle() {
        //DrawPixel(position.x, position.y, WHITE);
        //DrawCircle(position.x, position.y, 10, WHITE);
        DrawTexture(texture, position.x, position.y, WHITE);
        position.x += velocity.x;
        position.y += velocity.y;
        if (position.x > screenWidth || position.y > screenHeight)
            Reset();
    }
 
    void Reset() {
        position.x = GetRandomValue(-screenWidth * 0.4f, screenWidth);
        position.y = GetRandomValue(-screenHeight * 20);
        float max = 10000.0f;
        velocity.x = (GetRandomValue(1, (int)max) / max) * 0.5f;
        velocity.y = (GetRandomValue(1, (int)max) / max) + 0.8f;
    }
};
 
int main(void)
{
    //SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_UNDECORATED);
    InitWindow(screenWidth, screenHeight, "raylib example");
    // InitWindow() 실행시 내부에서 SetRandomSeed()를 time(NULL)로 초기화 한다.
    // particle 생성시 GetRandomValue()를 사용하므로 InitWindow() 이후에 생성한다.
    SetTargetFPS(60);
 
    texture = LoadTexture("snow.png");
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
    const int number_particles = 400;
    Particles particles[number_particles];
 
    while (!WindowShouldClose())
    {
        BeginDrawing();
 
        ClearBackground(BLACK);
 
        for (int i = 0; i < number_particles; i++)
            particles[i].Draw_particle();
 
        DrawFPS(00);
 
        EndDrawing();
    }
 
    UnloadTexture(texture);
 
    CloseWindow();
 
    return 0;
}
 

 

특별한 설정 없이도 png 파일의 알파 채널을 인식한다.

소스를 입력하고 빌드한다.

 

snow.png
0.00MB

 

 

DrawPixel(position.x, position.y, WHITE) 실행

 

DrawTexture(texture, position.x, position.y, WHITE) 실행


실제 실행하면 텍스쳐가 많이 깜빡인다. (아래 동영상 참고)

DrawPixel() 을 실행할 때는 크게 눈에 띄지 않지만 DrawTexture() 를 실행하면 눈에 띈다.

 

윈도우 사이즈를 크게 할수록 깜빡이는 현상이 줄어드는거 같다. 아니면 snow.png 파일을 LoadImage()로 로드하고 ImageResize()로 크게 바꾼 다음 LoadTextureFromImage()로 로드하면 깜빡임이 약간 줄어드는거 같다. (ImageResize()로 이미지 확대가 핵심)

Vector2로 정의된 위치값을 사용하는 DrawTextureV()를 이용해도 차이가 없다.

정확한 원인을 모르겠다.

 

 

RenerTexture2D를 사용하니까 조금 덜 깜빡이는거 같기도 한데.. 아닌거 같다.

더보기

 

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 "raylib.h"
 
const int screenWidth = 640;
const int screenHeight = 480;
 
Texture2D texture;
 
class Particles {
private:
    Vector2 position;
    Vector2 velocity;
public:
    Particles() {
        Reset();
    }
 
    void Draw_particle() {
        //DrawPixel(position.x, position.y, WHITE);
        //DrawCircle(position.x, position.y, 10, WHITE);
        DrawTexture(texture, position.x, position.y, WHITE);
        position.x += velocity.x;
        position.y += velocity.y;
        if (position.x > screenWidth || position.y > screenHeight)
            Reset();
    }
 
    void Reset() {
        position.x = GetRandomValue(-screenWidth * 0.4f, screenWidth);
        position.y = GetRandomValue(-screenHeight * 20);
        float max = 10000.0f;
        velocity.x = (GetRandomValue(1, (int)max) / max) * 0.5f;
        velocity.y = (GetRandomValue(1, (int)max) / max) + 0.8f;
    }
};
 
int main(void)
{
    //SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_UNDECORATED);
    InitWindow(screenWidth, screenHeight, "raylib example");
    // InitWindow() 실행시 내부에서 SetRandomSeed()를 time(NULL)로 초기화 한다.
    // particle 생성시 GetRandomValue()를 사용하므로 InitWindow() 이후에 생성한다.
    SetTargetFPS(60);
 
    RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
 
    texture = LoadTexture("snow.png");
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
    const int number_particles = 400;
    Particles particles[number_particles];
 
    while (!WindowShouldClose())
    {
        BeginTextureMode(target);
        {
            ClearBackground(BLACK);
 
            for (int i = 0; i < number_particles; i++)
                particles[i].Draw_particle();
 
            DrawFPS(00);
        }
        EndTextureMode();
 
        BeginDrawing();
        {
            //ClearBackground(BLACK);
            //DrawTexture(target.texture, 0, 0, WHITE); // 위아래가 뒤집혀 보인다.
            DrawTextureRec(target.texture, { 00, screenWidth, -screenHeight }, { 00 }, WHITE);
            // OpenGL의 좌표 체계가 다르기 때문에 위아래를 뒤집어야 제대로 표시된다.
        }
        EndDrawing();
    }
 
    UnloadTexture(texture);
    UnloadRenderTexture(target);
 
    CloseWindow();
 
    return 0;
}
 

 

 

Raylib 파티클 예제에 나오는 것 처럼 구조체를 이용해 봐도 별 차이가 없다.

Raylib Particles  

더보기

 

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 "raylib.h"
 
const int screenWidth = 640;
const int screenHeight = 480;
 
Texture2D texture;
 
typedef struct {
    Vector2 position;
    Vector2 velocity;
} s_particle;
 
const int number_particles = 400;
s_particle particles[number_particles];
 
void spawn_particle(s_particle* pt) {
    pt->position.x = GetRandomValue(-screenWidth * 0.4f, screenWidth);
    pt->position.y = GetRandomValue(-screenHeight * 20);
    float max = 10000.0f;
    pt->velocity.x = (GetRandomValue(1, (int)max) / max) * 0.5f;
    pt->velocity.y = (GetRandomValue(1, (int)max) / max) + 0.8f;
}
 
void draw_particle(s_particle pt[]) {
    for (int i = 0; i < number_particles; i++) {
        s_particle* particle = &pt[i];
        particle->position.x += particle->velocity.x;
        particle->position.y += particle->velocity.y;
 
        if (particle->position.x > screenWidth || particle->position.y > screenHeight)
            spawn_particle(particle);
 
        DrawTexture(texture, particle->position.x, particle->position.y, WHITE);
    }
}
 
int main(void)
{
    //SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_UNDECORATED);
    InitWindow(screenWidth, screenHeight, "raylib example");
    // InitWindow() 실행시 내부에서 SetRandomSeed()를 time(NULL)로 초기화 한다.
    // particle 생성시 GetRandomValue()를 사용하므로 InitWindow() 이후에 생성한다.
    SetTargetFPS(60);
 
    texture = LoadTexture("snow.png");
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
    for (int i = 0; i < number_particles; i++) {
        spawn_particle(&particles[i]);
    }
 
    while (!WindowShouldClose())
    {
        BeginDrawing();
        {
            ClearBackground(BLACK);
 
            draw_particle(particles);
 
            DrawFPS(00);
        }
        EndDrawing();
    }
 
    UnloadTexture(texture);
 
    CloseWindow();
 
    return 0;
}
 

 

한 가지 확인한 것은 velocity->x, velocity->y의 값을 임의의 소수가 아닌 (1이나 2같은)정수로 바꾸면 깜빡임이 없다.

Raylib 렌더링 함수에서 소수 처리 부분에 문제가 있는게 아닐까 싶다.

 

매 프레임마다 눈 이동 거리를 delta time으로 계산해도 별 의미가 없는거 같다.

더보기

 

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
#include "raylib.h"
 
const int screenWidth = 640;
const int screenHeight = 480;
 
Texture2D texture;
 
typedef struct {
    Vector2 position;
    Vector2 velocity;
} s_particle;
 
const int number_particles = 400;
s_particle particles[number_particles];
 
void spawn_particle(s_particle* pt) {
    pt->position.x = GetRandomValue(-screenWidth * 0.4f, screenWidth);
    pt->position.y = GetRandomValue(-screenHeight * 20);
    //float max = 10000.0f;
    //pt->velocity.x = (float)(GetRandomValue(1, (int)max) / max) * 0.5f;
    //pt->velocity.y = (float)(GetRandomValue(1, (int)max) / max) + 0.8f;
 
    pt->velocity.x = (float)GetRandomValue(030+ 10;
    // 눈이 오른쪽으로 이동하는 속도를 초당 10~40 픽셀로 설정
    pt->velocity.y = (float)GetRandomValue(2080+ 40;
    // 눈이 아래로 떨어지는 속도를 초당 60~120 픽셀로 설정    
}
 
void draw_particle(s_particle pt[], float delta) {
    for (int i = 0; i < number_particles; i++) {
        s_particle* particle = &pt[i];
        particle->position.x += particle->velocity.x * delta;
        particle->position.y += particle->velocity.y * delta;
 
        if (particle->position.x > screenWidth || particle->position.y > screenHeight)
            spawn_particle(particle);
 
        DrawTexture(texture, particle->position.x, particle->position.y, WHITE);
    }
}
 
int main(void)
{
    //SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_UNDECORATED);
    InitWindow(screenWidth, screenHeight, "raylib example");
    // InitWindow() 실행시 내부에서 SetRandomSeed()를 time(NULL)로 초기화 한다.
    // particle 생성시 GetRandomValue()를 사용하므로 InitWindow() 이후에 생성한다.
    SetTargetFPS(60);
 
    texture = LoadTexture("snow.png");
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
    for (int i = 0; i < number_particles; i++) {
        spawn_particle(&particles[i]);
    }
 
    while (!WindowShouldClose())
    {
        BeginDrawing();
        {
            ClearBackground(BLACK);
 
            draw_particle(particles, GetFrameTime());
            // GetFrameTime() : Get time in seconds for last frame drawn (delta time)
 
            DrawFPS(00);
        }
        EndDrawing();
    }
 
    UnloadTexture(texture);
 
    CloseWindow();
 
    return 0;
}
 

 

 

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

픽셀 이미지(JPG, PNG)를 벡터(AI) 이미지로 바꿔보자.

 

일러스트레이터를 실행하고 변환할 이미지를 불러온다.

 

snoopy.jpg
0.09MB

 

 

Tracing으로 바꾼다.

 

변환할 이미지를 선택하고 Image Trace 탭에서 Auto-Color를 선택한다. 필요하다면 다른 옵션을 조절하고 Expand 버튼을 클릭한다.

 

픽셀 이미지가 벡터 이미지로 변환된다.

 

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

'Pillow 화면 변화 감지(Pixel Checksum) 1'에서는 모든 픽셀의 값을 확인해서 좌표까지 알아내기 때문에 시간이 오래 걸린다.

ImageStat 모듈을 사용해 모든 픽셀을 확인하지 않고 전체적인 변화 여부만 감지하면 빠르게 확인 할 수 있다.


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
from PIL import Image
from PIL import ImageGrab
from PIL import ImageChops
from PIL import ImageStat
import time
 
def PixelCheck(x1, y1, x2, y2):
    im1 = ImageGrab.grab((x1, y1, x2, y2))
    # Take a snapshot of the screen. The pixels inside the bounding box are returned as an “RGB” image
    # on Windows or “RGBA” on macOS. If the bounding box is omitted, the entire screen is copied.
    while 1:
        time.sleep(0.1)
        im2 = ImageGrab.grab((x1, y1, x2, y2))
        im = ImageChops.difference(im1, im2)
        # Returns the absolute value of the pixel-by-pixel difference between the two images.
        # 마우스로 인한 변경은 반영 되지 않는다. 같은 이미지이면 difference()의 결과 이미지는 모든 픽셀이 0.
        stat = ImageStat.Stat(im)
        # Calculate statistics for the given image. If a mask is included, only the regions covered by
        # that mask are included in the statistics. You can also pass in a previously calculated histogram.
        if stat.sum != [000]: # Sum of all pixels for each band in the image.
            print("Change detected: sum[%s]: %s" %(im.getbands().__str__(), stat.sum.__str__()))
            # Returns a tuple containing the name of each band in this image. For example, getbands on
            # an RGB image returns (“R”, “G”, “B”).
            return
 
x1, y1, x2, y2 = map(int, input("Enter x1, y1, x2, y2 values: ").split()) # 추적할 영역의 좌상단, 우하단 좌표
PixelCheck(x1, y1, x2, y2)
# x1, y1, x2, y2 = input("Enter x1, y1, x2, y2 values: ").split()
# x1 = int(x1)
# y1 = int(y1)
# x2 = int(x2)
# y2 = int(y2)
cs


반응형

'Python' 카테고리의 다른 글

Pillow 이미지 서치(Image Search) 1  (0) 2018.11.30
pywin32 Windows Extensions for Python 2  (0) 2018.11.27
pywin32 Windows Extensions for Python 1  (0) 2018.11.27
Pillow 화면 변화 감지(Pixel Checksum) 1  (0) 2018.11.20
PyMySQL  (2) 2018.11.19
Posted by J-sean
:
반응형

Pillow 라이브러리를 사용해서 바탕화면의 변화를 추적할 영역을 지정하고 영역에 변화가 있을때 변화된 영역의 좌상단 좌표를 반환 한다.

지정된 영역의 모든 pixel을 확인하기 때문에 넓은 영역을 지정할 수록 시간이 오래 걸린다.


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
from PIL import Image
from PIL import ImageGrab
from PIL import ImageChops
import time
 
def PixelCheck(x1, y1, x2, y2):
    im1 = ImageGrab.grab((x1, y1, x2, y2))
    # Take a snapshot of the screen. The pixels inside the bounding box are returned as an “RGB” image
    # on Windows or “RGBA” on macOS. If the bounding box is omitted, the entire screen is copied.
    while 1:
        time.sleep(0.1)
        im2 = ImageGrab.grab((x1, y1, x2, y2))
        im = ImageChops.difference(im1, im2)
        # Returns the absolute value of the pixel-by-pixel difference between the two images.
        # 마우스로 인한 변경은 반영 되지 않는다. 같은 이미지이면 difference()의 결과 이미지는 모든 픽셀이 0.
        for y in range(im.height):
            for x in range(im.width):
                if im.getpixel((x, y)) != (000): # Returns the pixel value at a given position.
                    return x, y
 
x1, y1, x2, y2 = map(int, input("Enter x1, y1, x2, y2 values: ").split())
# x1, y1, x2, y2 = input("Enter x1, y1, x2, y2 values: ").split()
# x1 = int(x1)
# y1 = int(y1)
# x2 = int(x2)
# y2 = int(y2)
 
coord = PixelCheck(x1, y1, x2, y2) # 추적할 영역의 좌상단, 우하단 좌표
print(x1 + coord[0], y1 + coord[1]) # 추적 영역 중 변화된 영역의 좌상단 좌표(스크린 기준)
cs


PixelAccess class 를 사용해 PIL.Image data를 pixel level 에서 읽어 판단하기. (쓰기도 가능)

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
from PIL import Image
from PIL import ImageGrab
from PIL import ImageChops
import time
 
def PixelCheck(x1, y1, x2, y2):
    im1 = ImageGrab.grab((x1, y1, x2, y2))
    # Take a snapshot of the screen. The pixels inside the bounding box are returned as an “RGB” image
    # on Windows or “RGBA” on macOS. If the bounding box is omitted, the entire screen is copied.
    while 1:
        time.sleep(0.1)
        im2 = ImageGrab.grab((x1, y1, x2, y2))
        im = ImageChops.difference(im1, im2)
        # Returns the absolute value of the pixel-by-pixel difference between the two images.
        # 마우스로 인한 변경은 반영 되지 않는다. 같은 이미지이면 difference()의 결과 이미지는 모든 픽셀이 0.
        px = im.load()
        # Allocates storage for the image and loads the pixel data. In normal cases, you don’t need to
        # call this method, since the Image class automatically loads an opened image when it is accessed
        # for the first time.
        for y in range(im.height):
            for x in range(im.width):
                if px[x, y] != (000):
                    return x, y
        # Accessing individual pixels is fairly slow. If you are looping over all of the pixels in an image,
        # there is likely a faster way using other parts of the Pillow API.
 
x1, y1, x2, y2 = map(int, input("Enter x1, y1, x2, y2 values: ").split())
# x1, y1, x2, y2 = input("Enter x1, y1, x2, y2 values: ").split()
# x1 = int(x1)
# y1 = int(y1)
# x2 = int(x2)
# y2 = int(y2)
 
coord = PixelCheck(x1, y1, x2, y2) # 추적할 영역의 좌상단, 우하단 좌표
print(x1 + coord[0], y1 + coord[1]) # 추적 영역 중 변화된 영역의 좌상단 좌표(스크린 기준)
cs


반응형

'Python' 카테고리의 다른 글

Pillow 이미지 서치(Image Search) 1  (0) 2018.11.30
pywin32 Windows Extensions for Python 2  (0) 2018.11.27
pywin32 Windows Extensions for Python 1  (0) 2018.11.27
Pillow 화면 변화 감지(Pixel Checksum) 2  (0) 2018.11.21
PyMySQL  (2) 2018.11.19
Posted by J-sean
: