2012-10-29 3 views
2

저는 C++을 처음 접했지만 언어가 괜찮은 것 같습니다. 학습 프로젝트로서 마이너 2D 그래픽 엔진을 만들기로 결정했습니다. 그것은 어려운 프로젝트처럼 보일지 모르지만, 나는 어떻게 나아갈 지 잘 알고 있습니다.처음부터 큰 원을 그리시오

나는 아직 시작하지 않았지만,이 문제를 보았을 때, 나는 머리에 일들을 형성하고있다. 어떤 시점에서 나는 화면에 원을 그리는 함수를 만들어야 할 것이다. 바로 지금 내 접근 방식은 다음과 같을 것입니다.

in a square with sides from (x-r) to (x+r) loop through x and y, 
if at each point, the current distance sqr(x^2+y^2) is less than or equal to r 
, then draw a pixel at that point. 

이 경우 작동하지 않을 수도 있습니다. x + r & y + r이 화면에있는 경우에만 원인을 알 수 있습니다.

문제는 내가 때로는 큰 원을 그릴 필요가 있다는 점에 있습니다. 예를 들어 반경 5000의 원을 그릴 필요가있는 경우 픽셀 루프 계산에 총 10000^2 회 루프가 필요합니다. 따라서 2Ghz의 프로세서를 사용하면이 단일 원이 전체 코어를 차지하면서 ~ 22 배/초인 2Ghz/(10000^2) 만 렌더링 할 수 있습니다 (픽셀 당 하나의 계산 만 필요하다고 생각합니다. 진실).

올바른 방법은 다음 중 어느 것입니까? 나는이 간단한 계산을 위해 GFX를 사용하는 것과 관련이 있다고 생각합니다. 그렇다면 C++ 용 OpenGL을 사용할 수 있습니까? 나는 그걸 또한 배우고 싶습니다 :)

+3

[Midpoint circle algorithm] (http://en.wikipedia.org/wiki/Midpoint_circle_algorithm) – Andrey

답변

6

첫 번째 C/C++ 프로젝트는 사실 그래픽 라이브러리였습니다. OpenGL이나 DirectX가 없었으며 당시 DOS를 사용하고있었습니다. 나는 스크린에서 그릴 수있는 새롭고 더 좋은 (그리고 더 빠른) 방법을 끊임없이 발견하면서 나는 그것으로부터 많은 것을 배웠다.

현대적인 운영 체제의 문제점은 내가 지금까지했던 일을 실제로 허용하지 않는다는 것입니다. 하드웨어를 직접 사용할 수는 없습니다. 그리고 솔직히 요즘은 더 이상 원하지 않습니다.

모든 것을 직접 그릴 수 있습니다. 자신의 픽셀을 넣고 싶다면 SDL을보십시오. 이것은 자신의 C++ 객체로 래핑 할 수있는 C 라이브러리입니다. 다른 플랫폼 (Linux, Windows, Mac 등)에서 작동하며 내부적으로 DirectX 또는 OpenGL과 같은 기능을 사용합니다.

실제 그래픽의 경우, 자신의 픽셀을 그리기 만하면되는 것이 아닙니다. 그것은 효율적이지 않습니다. 또는 적어도 직접 하드웨어를 사용할 수없는 장치는 아닙니다 ...

하지만 용도에 따라 SDL이 반드시 필요하다고 생각합니다. 좋은 결과 내길 바랄 게.

+0

+1 훌륭한 답변! –

+0

"하나의 픽셀을 그리는 것이 아니라 효율이 떨어집니다"<- 때로는 "자신의 픽셀 그리기"가 GPU를 만드는 것보다 효율적입니다. 예를 들어 OpenGL을 사용하면 ~ 400ms 이상 걸리는 컨텍스트를 만들어야하기 때문입니다. 예를 들어,이 사이트의 자동 생성 무작위 아바타가 OpenGL 또는 DirectX를 사용하여 렌더링하는 것을 의심합니다 (그저 GFX 카드를 구매하는 것은 어리석은 짓입니다). 또한 나는 GFX 카드의 안정성이나 호환성을 신뢰하지 않을 것이다. CPU가 있으면 작동 할 것입니다. – Rookie

+2

그래,하지만 반경이 5000 픽셀 인 채워진 원을 그리는 데는 적합하지 않습니까?! 그것은 질문입니다. 이를 염두에두고 픽셀을 하나씩 그리는 것보다 효율적인 방법이 있습니다. – Koder

2

픽셀을 화면에 수동으로 그리는 방법으로 광경을 나타내지 마십시오.

사용하려는 것은 DirectX 또는 OpenGL입니다. 나는 당신이 열려있는 google를 자르고 읽는 것을 제안한다, 거기 밖으로 읽을 것이다 많게있다.

일단 라이브러리를 다운로드하고 나면 많은 샘플 프로젝트를 살펴보면 시작할 수 있습니다.

이 시점에는 두 가지 방법이 있습니다. 매우 많은 수의 측면이있는 모양을 나타내는 벡터를 계산하는 수학적 방법이 있습니다 (예 : 원 모양). 또는 알파 채널을 사용하여 화면의 원의 질감 (즉 그림)을 그리는 '속임수'방법으로 나머지 텍스처를 투명하게 만들 수 있습니다. (부정 행위는 코딩하기가 쉽고, 실행이 빠르며 유연성이 떨어지더라도 더 나은 결과를 산출합니다.)

수학적으로 이렇게하려면 두 라이브러리 모두 화면에 선을 그릴 수 있으므로 개별 픽셀이 아닌 각 행의 시작점과 끝점의 관점에서 접근해야합니다. 나는 벡터 그래픽을 원한다.

지금은 무거운 수학 할 수는 없지만, 벡터 방식이 (sudo를 코드)처럼 조금 보일 수 있습니다 :

in-param: num_of_sides, length_of_side; 
float angle = 360/num_of_sides; 
float start_x = 0; 
float start_y = 0; 

x = startX; 
y = startX; 
for(int i(0); i < num_of_sides; ++i) 
{ 
    float endX, endY; 
    rotateOffsetByAngle(x, y, x + lenth_of_side, y, angle * i, endX, endY); 
    drawline(x, y, endX, endY); 
    x = endX; 
    y = endY; 
} 


drawline(float startX, startY, endX, endY) 
{ 
    //does code that draws line between the start and end coordinates; 
} 

rotateOffsetByAngle(float startX, startY, endX, endY, angle, &outX, &outY) 
{ 
    //the in-parameters startX, startY and endX, endY describe a line 
    //we treat this line as the offset from the starting point 

    //do code that rotates this line around the point startX, startY, by the angle. 
    //after this rotation is done endX and endY are now at the same 
    //distance from startX and startY that they were, but rotated. 

    outX = endX; 
    outY = endY; //pass these new coordinates back out by reference; 

} 

을 위의 코드에서 우리는 원의 외부의 주위에 이동 바깥 쪽의 각 개별 선을 하나씩 그립니다. 시작점과 오프셋이있는 각 선에 대해 각도로 오프셋을 회전합니다 (이 각도는 원을 따라 이동할 때마다 증가합니다). 그런 다음 시작점에서부터 옵셋 점까지 선을 그립니다. 다음 반복을 시작하기 전에 시작점을 옵셋 점으로 이동하여 다음 줄이 마지막 줄의 끝에서 시작합니다.

나는 이해할 수 있기를 바랍니다.

+0

op는 학습 프로젝트로 코드를 작성하려고하기 때문에 묻습니다. 제 생각에는 프로그래밍에 익숙해지기 위해 픽셀 단위로 원을 그리는 것만 큼 기본적인 작업을하는 것이 잘못된 것 같아요. –

+0

"수동으로 픽셀을 그리는 것"은 소리를내는 것처럼 그렇게 나쁜 것이 아닙니다. 가끔은 원하지 않거나 GL/DX를 사용할 수 없습니다. 왜 여러 가지 이유가있을 수 있습니다. – Rookie

+0

@philip 네 말이 맞아. 나는 그의 O (n2) 방법을 보았고 조금 무릎을 꿇었다. 그가 내 대답에서 얻길 바라는 메시지는 드로잉 선이 더 나은 접근 방법이라는 것입니다. 이후 줄을 써서 원을 그리는 (상당히 불쌍한 필자는 인정할 것이다) sudo 코드를 추가했지만 의도적으로 실제로 드로잉 비트를 공백으로 남겨 두었다. – Ian

1

그것은 채워진 원을 그리는 한 가지 방법입니다. 당신이 볼 수 있듯이 그것은 천천히 수행 할 것입니다.

현대 그래픽은 하위 수준의 내용을 추상화하여 최적화 할 수 있도록합니다. 개발자는 drawCircle (x, y, r)을 씁니다. 그래픽 libary + 드라이버는 해당 픽셀을 채울 수있는 칩까지 모든 패스를 전달할 수 있습니다.

C++로 작성하고 있지만 그래픽 드라이버를 사용하지 않으면 코어에 가장 가까운 데이터를 조작하지 않습니다. setPixelColour 레벨 메소드와 와이어를 통해 전달되는 실제 바이너리 값 사이에 서브 루틴 호출 레이어가있다. 거의 모든 계층에서 수표와 추가 계산 및 루틴이 실행됩니다. 더 빠른 그래픽의 비밀은 당신이 만드는 이러한 호출의 수를 줄이는 것입니다. drawCircle 명령을 그래픽 칩에 줄 수 있다면 그렇게하십시오. 일정한 모양을 그린 것처럼 평범한 경우 단일 픽셀로 전화를 낭비하지 마십시오.

최신 OS에는 사용자와 같은 개별 응용 프로그램의 요청을 받아서 창 작업, 합성 및 기타 효과와 결합하는 그래픽 처리 계층이 있습니다. 따라서 '화면에 그리기'에 대한 명령은 이미 여러 단계로 중개됩니다. CPU에 제공하려는 것은 계산을 그래픽 서브 시스템으로 오프로드하는 데 필요한 최소한의 정보입니다.

개발주기가 쉽고 비교적 쉽기 때문에 화면에 물건을 그려보고 싶다면 캔버스와 js로 게임을 배우는 것이 좋습니다. C++을 배우고 싶다면 프로젝트 오일러를 사용하거나 기존 그래픽 라이브러리를 사용하여 물건을 그립니다. 2 차원 그래픽 라이브러리를 작성하려면 DirectX 및 OpenGL과 같은 기본 그래픽 기술을 익히십시오. 그래픽이 실제로 구현되는 방식이기 때문입니다. 하지만 그들은 너무 복잡해 보입니다. 그렇다면 먼저 C++을 더 배워야합니다. 그것들은 몇 가지 아주 좋은 이유 때문에 그렇습니다. 그러나 결과는 복잡합니다.

+0

그레이트 읽기뿐만 아니라, 고마워요 :) OpenGL에 아무런 문제가 없지만, 곧 익숙해지기를 바랍니다. 그러나 처음에는 2D로는별로 좋아 보이지 않았습니다. –

1

첫 번째 대답에 따르면 심각한 일을하기 위해 직접 해선 안됩니다. 먼저 화면에 선분을 그리는 함수를 정의 : 방금 예로 들어 이렇게 할 경우에, 다음과 같이 뭔가를 할 수 있었다

void draw_line(int x1, int y1, int x2, int y2); 

이 구현하기가 상대적으로 간단합니다 : 그냥 찾을 방향을 가장 빠르게 변경하고 정수 논리를 사용하면서 다른 차원이 얼마나 바뀌어야하는지 파악하면서 그 방향을 반복합니다. 즉, x가 빠르게 변하면 y = (x-x1)*(y2-y1)/(x2-x1)입니다.

그런 다음 구분 선 요소로서 원을 구현하기 위해이 기능을 사용

void draw_circle(int x, int y, int r) 
{ 
    double dtheta = 2*M_PI/8/r; 
    int x1 = x+r, x2, y1 = y, y2; 
    int n = 2*M_PI/dtheta; 
    for(int i = 1; i < n; i++) 
    { 
     double theta = i*dtheta; 
     x2 = int(x+r*cos(theta)); y2 = int(y+r*sin(theta)); 
     draw_line(x1, y1, x2, y2); 
     x1 = x2; y1 = y2; 
    } 
} 

이 점 로직 및 삼각 함수를 플로팅 광고 요소 가장 원 근사 알아낼 용도. 다소 조잡한 구현이지만 매우 큰 서클에서 효율적으로 수행하고자하는 구현은 이와 같이해야한다고 생각합니다.

정수 논리 만 사용할 수있는 경우 먼저 낮은 해상도의 정수 원을 그린 다음 선택한 각 픽셀을 작은 픽셀로 세분하고 원하는 하위 픽셀을 선택하면됩니다. 에. 이것은 N log N으로 확장되므로 위의 방법보다 여전히 느립니다. 그러나 당신은 죄와 코사인을 피할 수 있습니다.

+0

for 루프를 악용하는 방식에 만족하지 않는다고 말해야합니다. 그것은 이론적으로 좋게 보일지 모르지만, float/double이 정확하지 않다는 것을 알아야합니다. 그리고 더하기 정밀도가 더 많이 손실됩니다. 루프에는 곱셈과 정수를 사용하십시오. – Rookie

+0

이 구현은 theta를 부동 소수점 연산으로 지속적으로 증가시킴으로써 부동 소수점 오류를 누적하는 것이 옳습니다. 그러나이 경우이 오류는 완전히 무시할 수 있습니다. 하지만 어쨌든 다시 작성하겠습니다. – amaurea