#include <Windows.h>
LRESULT CALLBACK WndProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
HDC hDC;
PAINTSTRUCT ps;
// 座標の配列
static POINT pt [ 3 ];
switch ( uMsg )
{
case WM_CREATE:
// 座標値の設定
pt [ 0 ].x = 0;
pt [ 0 ].y = 0;
pt [ 1 ].x = 150;
pt [ 1 ].y = 350;
pt [ 2 ].x = 400;
pt [ 2 ].y = 100;
pt [ 3 ].x = 800;
pt [ 3 ].y = 600;
break;
case WM_PAINT:
// 曲線の描画
hDC = BeginPaint ( hWnd , &ps );
MoveToEx ( hDC , pt [ 0 ].x , pt [ 0 ].y , NULL );
PolyBezier ( hDC , pt , 4 );
// 描画終了
EndPaint ( hWnd , &ps );
break;
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
{
UINT nID = MessageBox ( NULL , "ウィンドウを閉じますか?" , "Message" , MB_YESNO );
if ( nID == IDYES )
{
DestroyWindow ( hWnd );
}
else if ( nID == IDNO )
{
MessageBox ( NULL , "OK" , "Message" , MB_OK );
}
}
break;
case WM_DESTROY:
PostQuitMessage ( 0 );
break;
}
return DefWindowProc ( hWnd , uMsg , wParam , lParam );
}
int WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , PSTR IpCmdLine , int nCmdShow )
{
UNREFERENCED_PARAMETER ( hPrevInstance );
UNREFERENCED_PARAMETER ( IpCmdLine );
HWND hWnd;
MSG msg;
WNDCLASS winc;
winc.style = CS_HREDRAW | CS_VREDRAW;
winc.lpfnWndProc = WndProc;
winc.cbClsExtra = winc.cbWndExtra = 0;
winc.hInstance = hInstance;
winc.hIcon = LoadIcon ( NULL , IDI_APPLICATION );
winc.hCursor = LoadCursor ( NULL , IDC_ARROW );
winc.hbrBackground = ( HBRUSH ) GetStockObject ( WHITE_BRUSH );
winc.lpszMenuName = NULL;
winc.lpszClassName = TEXT ( "ベジエ" );
if ( !RegisterClass ( &winc ) )
{
return -1;
}
// ウィンドウスタイル定義
const int wStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
// ウィンドウ生成
hWnd = CreateWindow (
TEXT ( "ベジエ" ) ,
TEXT ( "ベジエ曲線" ) ,
wStyle ,
USEDEFAULT ,
USEDEFAULT ,
USEDEFAULT ,
USEDEFAULT,
NULL ,
NULL ,
hInstance ,
NULL
);
if ( hWnd == NULL )
{
return -1;
}
while ( GetMessage ( &msg , NULL , 0 , 0 ) )
{
DispatchMessage ( &msg );
}
return msg.wParam;
}
//==================== EOF ====================//
DirectXでの曲線描画について
DirectXでの曲線描画について
DirectXで曲線(ベジエ曲線)を描画しているのですが、いきなり曲線全体を描画するのではなく、時間の経過に従って描画したいのですが、どのようにすればよいのでしょうか?
Re: DirectXでの曲線描画について
とりあえず、いきなり曲線全体を描画してもいいのでDirectXで曲線(ベジエ曲線)を描画するコードを書いてみるといいでしょう。kloud さんが書きました:DirectXで曲線(ベジエ曲線)を描画しているのですが、いきなり曲線全体を描画するのではなく、時間の経過に従って描画したいのですが、どのようにすればよいのでしょうか?
その後、「時間の経過に従って描画」するコードの改良するといいでしょう。
ベジェ曲線の書き方はベジェ曲線 - Wikipediaなどが参考になるでしょう。
また、ここに貼ってあるコードは21行目で確保された領域の範囲外にアクセスし、未定義動作を起こすので、修正または削除するといいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: DirectXでの曲線描画について
3次のベジエ曲線を描画したい場合、始点P1、制御点P2、制御点P3、終点P4とし、tを0~1まで変化させるとすると、ベジエ曲線C(t)は
C(t) = (1-t^3)P1 + 3t(1-t^2)P2 + 3t^2(1-t)P3 + t^3P4
で表せますよね?
これを元にプログラムしてみたのですが、描画の仕方が分からなくなってしまいました。また、計算もこれでいいのか不安です。
C(t) = (1-t^3)P1 + 3t(1-t^2)P2 + 3t^2(1-t)P3 + t^3P4
で表せますよね?
これを元にプログラムしてみたのですが、描画の仕方が分からなくなってしまいました。また、計算もこれでいいのか不安です。
#include <Windows.h>
#define SCREEN_WIDTH ( 800 )
#define SCREEN_HEIGHT ( 600 )
#define X1 ( 0 )
#define Y1 ( 0 )
#define X4 ( 800 )
#define Y4 ( 600 )
#define X2 ( 200 )
#define Y2 ( 350 )
#define X3 ( 600 )
#define Y3 ( 500 )
int WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpCmdLine , int nCmdShow )
{
UNREFERENCED_PARAMETER ( hPrevInstance );
UNREFERENCED_PARAMETER ( lpCmdLine );
WNDCLASSEX wcex =
{
sizeof ( WNDCLASSEX ) ,
CS_CLASSDC ,
WndProc ,
0 ,
0 ,
hInstance ,
NULL ,
LoadCursor ( NULL , IDC_ARROW ) ,
( HBRUSH ) ( COLOR_WINDOW + 1 ) ,
NULL ,
CLASS_NAME ,
NULL
};
RegisterClassEx ( &wcex );
static HWND hWnd;
static MSG msg;
// ウィンドウスタイル定義
const int wstyle = WS_OVERLAPPEDWINDOW &~ WS_MINIMIZEBOX &~ WS_MAXIMIZEBOX &~ WS_THICKFRAME ;
// ウィンドウを作成
hWnd = CreateWindowEx ( 0 ,
CLASS_NAME ,
WINDOW_NAME ,
wstyle ,
CW_USEDEFAULT,
CW_USEDEFAULT,
SCREEN_WIDTH,
SCREEN_HEIGHT,
NULL ,
NULL ,
hInstance ,
NULL
);
ShowWindow ( hWnd , nCmdShow );
UpdateWindow ( hWnd );
while ( GetMessage ( &msg , NULL , 0 , 0 ) )
{
TranslateMessage ( &msg );
DispatchMessage ( &msg );
}
return msg.wParam;
}
LRESULT CALLBACK WndProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
static HDC hDC;
static float a , b , c , d;
static float t = 0.0f;
static float px , py = 0.0f;
PAINTSTRUCT ps;
a = ( 1 - t * t * t );
b = 3 * t * ( 1 - t * t );
c = 3 * t * t * ( 1 - t );
d = t * t * t;
switch ( uMsg )
{
case WM_CREATE:
px = X1 * a + X2 * b + X3 * c + X4 * d;
py = Y1 * a + Y2 * b + Y3 * c + Y4 * d;
break;
case WM_PAINT:
{
// 曲線描画
hDC = BeginPaint ( hWnd , &ps );
// 描画方法がわからない
// 描画終了
EndPaint ( hWnd , &ps );
if ( t < 1.0f )
{
t++;
}
if ( t > 1.0f )
{
t = 1.0f;
}
break;
}
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
{
UINT nID = MessageBox ( NULL , "ウィンドウを閉じますか?" , "Message" , MB_YESNO );
if ( nID == IDYES )
{
DestroyWindow ( hWnd );
}
else if ( nID == IDNO )
{
MessageBox ( NULL , "OK" , "Message" , MB_OK );
}
}
break;
case WM_DESTROY:
PostQuitMessage ( 0 );
break;
}
return DefWindowProc ( hWnd , uMsg , wParam , lParam );
}
//==================== EOF ====================//
Re: DirectXでの曲線描画について
返信が遅くなり、申し訳ありません。
DirectXへの移植は後で考えるとして、とりあえずベジェ曲線を描画しましょう。
線分A-Bをt:(1-t)に内分する点は A+(B-A)*t/(t+(1-t)) すなわち (1-t)*A + t*B であることを利用して式変形をすると、
C(t) = (1-t)^3P1 + 3t(1-t)^2P2 + 3t^2(1-t)P3 + t^3P4
となりました。
従って、例えば t=0.5 、各点のある成分が P1=1, P2=2, P3=3, P4=4 とすると、kloudさんの式は4.75、求めた式は2.5となり、一致しません。
従って、このkloudさんの式では、
ベジェ曲線 - Wikipedia (2016年6月27日 (月) 14:05; Glayhours による版)
に載っている3次のベジェ曲線(4個の制御点で示される曲線)は表せないと考えられます。
「時間の経過に従って描画」するには、例えば時間によって描画する範囲を変えるといいでしょう。
DirectXへの移植は後で考えるとして、とりあえずベジェ曲線を描画しましょう。
あなたの言う「3次のベジエ曲線」が何のことかよくわからないですが、前述のWikipediaの「作図法」をもとに、kloud さんが書きました:3次のベジエ曲線を描画したい場合、始点P1、制御点P2、制御点P3、終点P4とし、tを0~1まで変化させるとすると、ベジエ曲線C(t)は
C(t) = (1-t^3)P1 + 3t(1-t^2)P2 + 3t^2(1-t)P3 + t^3P4
で表せますよね?
線分A-Bをt:(1-t)に内分する点は A+(B-A)*t/(t+(1-t)) すなわち (1-t)*A + t*B であることを利用して式変形をすると、
C(t) = (1-t)^3P1 + 3t(1-t)^2P2 + 3t^2(1-t)P3 + t^3P4
となりました。
従って、例えば t=0.5 、各点のある成分が P1=1, P2=2, P3=3, P4=4 とすると、kloudさんの式は4.75、求めた式は2.5となり、一致しません。
従って、このkloudさんの式では、
ベジェ曲線 - Wikipedia (2016年6月27日 (月) 14:05; Glayhours による版)
に載っている3次のベジェ曲線(4個の制御点で示される曲線)は表せないと考えられます。
適切な計算をすると曲線中の1点の座標が得られるので、適当な数の点を計算して繋ぐことで描画できます。kloud さんが書きました:これを元にプログラムしてみたのですが、描画の仕方が分からなくなってしまいました。
#include <Windows.h>
#define SCREEN_WIDTH ( 800 )
#define SCREEN_HEIGHT ( 600 )
#define MAX ( 256 ) // 曲線の分割数
#define X1 ( 0 )
#define Y1 ( 0 )
#define X4 ( 800 )
#define Y4 ( 600 )
#define X2 ( 200 )
#define Y2 ( 350 )
#define X3 ( 600 )
#define Y3 ( 500 )
#define CLASS_NAME "ベジェ"
#define WINDOW_NAME "ベジェ曲線"
LRESULT CALLBACK WndProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam );
int WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpCmdLine , int nCmdShow )
{
UNREFERENCED_PARAMETER ( hPrevInstance );
UNREFERENCED_PARAMETER ( lpCmdLine );
WNDCLASSEX wcex =
{
sizeof ( WNDCLASSEX ) ,
CS_CLASSDC ,
WndProc ,
0 ,
0 ,
hInstance ,
NULL ,
LoadCursor ( NULL , IDC_ARROW ) ,
( HBRUSH ) ( COLOR_WINDOW + 1 ) ,
NULL ,
CLASS_NAME ,
NULL
};
RegisterClassEx ( &wcex );
static HWND hWnd;
static MSG msg;
// ウィンドウスタイル定義
const int wstyle = WS_OVERLAPPEDWINDOW &~ WS_MINIMIZEBOX &~ WS_MAXIMIZEBOX &~ WS_THICKFRAME ;
// ウィンドウを作成
hWnd = CreateWindowEx ( 0 ,
CLASS_NAME ,
WINDOW_NAME ,
wstyle ,
CW_USEDEFAULT,
CW_USEDEFAULT,
SCREEN_WIDTH,
SCREEN_HEIGHT,
NULL ,
NULL ,
hInstance ,
NULL
);
ShowWindow ( hWnd , nCmdShow );
UpdateWindow ( hWnd );
while ( GetMessage ( &msg , NULL , 0 , 0 ) )
{
TranslateMessage ( &msg );
DispatchMessage ( &msg );
}
return msg.wParam;
}
void calcCurve(float* px, float* py, float t)
{
#if 1
float mt = 1 - t;
float a , b , c , d;
a = mt * mt * mt;
b = 3 * t * mt * mt;
c = 3 * t * t * mt;
d = t * t * t;
*px = X1 * a + X2 * b + X3 * c + X4 * d;
*py = Y1 * a + Y2 * b + Y3 * c + Y4 * d;
#else
float p5 , p6 , p7 , p8 , p9;
p5 = X1 * (1 - t) + X2 * t;
p6 = X2 * (1 - t) + X3 * t;
p7 = X3 * (1 - t) + X4 * t;
p8 = p5 * (1 - t) + p6 * t;
p9 = p6 * (1 - t) + p7 * t;
*px = p8 * (1 - t) + p9 * t;
p5 = Y1 * (1 - t) + Y2 * t;
p6 = Y2 * (1 - t) + Y3 * t;
p7 = Y3 * (1 - t) + Y4 * t;
p8 = p5 * (1 - t) + p6 * t;
p9 = p6 * (1 - t) + p7 * t;
*py = p8 * (1 - t) + p9 * t;
#endif
}
LRESULT CALLBACK WndProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
HDC hDC;
int i;
float px , py;
PAINTSTRUCT ps;
switch ( uMsg )
{
case WM_CREATE:
break;
case WM_PAINT:
{
// 曲線描画
hDC = BeginPaint ( hWnd , &ps );
calcCurve ( &px , &py , 0.0f );
MoveToEx ( hDC , (int)px , (int)py , NULL );
for (i = 1; i <= MAX; i++)
{
calcCurve ( &px , &py , i / (float)MAX );
LineTo ( hDC , (int)px , (int)py );
}
// 描画終了
EndPaint ( hWnd , &ps );
break;
}
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
{
UINT nID = MessageBox ( NULL , "ウィンドウを閉じますか?" , "Message" , MB_YESNO );
if ( nID == IDYES )
{
DestroyWindow ( hWnd );
}
else if ( nID == IDNO )
{
MessageBox ( NULL , "OK" , "Message" , MB_OK );
}
}
break;
case WM_DESTROY:
PostQuitMessage ( 0 );
break;
}
return DefWindowProc ( hWnd , uMsg , wParam , lParam );
}
//==================== EOF ====================//
#include <Windows.h>
#define SCREEN_WIDTH ( 800 )
#define SCREEN_HEIGHT ( 600 )
#define MAX ( 256 ) // 曲線の分割数
#define X1 ( 0 )
#define Y1 ( 0 )
#define X4 ( 800 )
#define Y4 ( 600 )
#define X2 ( 200 )
#define Y2 ( 350 )
#define X3 ( 600 )
#define Y3 ( 500 )
#define CLASS_NAME "ベジェ"
#define WINDOW_NAME "ベジェ曲線"
LRESULT CALLBACK WndProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam );
int WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpCmdLine , int nCmdShow )
{
UNREFERENCED_PARAMETER ( hPrevInstance );
UNREFERENCED_PARAMETER ( lpCmdLine );
WNDCLASSEX wcex =
{
sizeof ( WNDCLASSEX ) ,
CS_CLASSDC ,
WndProc ,
0 ,
0 ,
hInstance ,
NULL ,
LoadCursor ( NULL , IDC_ARROW ) ,
( HBRUSH ) ( COLOR_WINDOW + 1 ) ,
NULL ,
CLASS_NAME ,
NULL
};
RegisterClassEx ( &wcex );
static HWND hWnd;
static MSG msg;
// ウィンドウスタイル定義
const int wstyle = WS_OVERLAPPEDWINDOW &~ WS_MINIMIZEBOX &~ WS_MAXIMIZEBOX &~ WS_THICKFRAME ;
// ウィンドウを作成
hWnd = CreateWindowEx ( 0 ,
CLASS_NAME ,
WINDOW_NAME ,
wstyle ,
CW_USEDEFAULT,
CW_USEDEFAULT,
SCREEN_WIDTH,
SCREEN_HEIGHT,
NULL ,
NULL ,
hInstance ,
NULL
);
ShowWindow ( hWnd , nCmdShow );
UpdateWindow ( hWnd );
while ( GetMessage ( &msg , NULL , 0 , 0 ) )
{
TranslateMessage ( &msg );
DispatchMessage ( &msg );
}
return msg.wParam;
}
void calcCurve(float* px, float* py, float t)
{
#if 1
float mt = 1 - t;
float a , b , c , d;
a = mt * mt * mt;
b = 3 * t * mt * mt;
c = 3 * t * t * mt;
d = t * t * t;
*px = X1 * a + X2 * b + X3 * c + X4 * d;
*py = Y1 * a + Y2 * b + Y3 * c + Y4 * d;
#else
float p5 , p6 , p7 , p8 , p9;
p5 = X1 * (1 - t) + X2 * t;
p6 = X2 * (1 - t) + X3 * t;
p7 = X3 * (1 - t) + X4 * t;
p8 = p5 * (1 - t) + p6 * t;
p9 = p6 * (1 - t) + p7 * t;
*px = p8 * (1 - t) + p9 * t;
p5 = Y1 * (1 - t) + Y2 * t;
p6 = Y2 * (1 - t) + Y3 * t;
p7 = Y3 * (1 - t) + Y4 * t;
p8 = p5 * (1 - t) + p6 * t;
p9 = p6 * (1 - t) + p7 * t;
*py = p8 * (1 - t) + p9 * t;
#endif
}
LRESULT CALLBACK WndProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
HDC hDC;
RECT rt;
int i;
float px , py;
static unsigned int startTime;
unsigned int elapsedTime;
int drawMin, drawMax;
PAINTSTRUCT ps;
switch ( uMsg )
{
case WM_CREATE:
startTime = GetTickCount();
SetTimer ( hWnd, 0 , 20 , NULL );
break;
case WM_TIMER:
InvalidateRect ( hWnd , NULL , FALSE );
break;
case WM_PAINT:
{
// 時刻によって描画する曲線の範囲を決める
elapsedTime = GetTickCount() - startTime;
drawMin = elapsedTime % 4000 < 2000 ? 0 : MAX * (elapsedTime % 2000) / 2000;
drawMax = elapsedTime % 4000 < 2000 ? MAX * (elapsedTime % 2000) / 2000 : MAX;
// 背景を塗りつぶす
hDC = BeginPaint ( hWnd , &ps );
GetClientRect ( hWnd , &rt );
FillRect ( hDC , &rt , GetStockObject ( WHITE_BRUSH ) );
// 曲線描画
calcCurve( &px , &py , drawMin / (float)MAX );
MoveToEx( hDC , (int)px , (int)py , NULL );
for (i = drawMin + 1; i <= drawMax ; i++)
{
calcCurve( &px , &py , i / (float)MAX );
LineTo ( hDC , (int)px , (int)py );
}
// 描画終了
EndPaint ( hWnd , &ps );
break;
}
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
{
UINT nID = MessageBox ( NULL , "ウィンドウを閉じますか?" , "Message" , MB_YESNO );
if ( nID == IDYES )
{
DestroyWindow ( hWnd );
}
else if ( nID == IDNO )
{
MessageBox ( NULL , "OK" , "Message" , MB_OK );
}
}
break;
case WM_DESTROY:
PostQuitMessage ( 0 );
break;
}
return DefWindowProc ( hWnd , uMsg , wParam , lParam );
}
//==================== EOF ====================//
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)