質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

1802閲覧

クリックした点からベジェ曲線を描くプログラム

cawawa

総合スコア1

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/07/03 05:00

編集2020/07/10 04:55

前提・実現したいこと

2020/07/10 追記 修正したコードを反映しました

OpenGLを使って、クリックで四点を入力しベジェ曲線を描画するプログラムを作ろうとしています。

発生している問題・エラーメッセージ

クリックした座標を配列に格納することはできたのですが曲線に関して画面への反映がされません。
どこを修正したらよいか教えていただけると幸いです。

エラーメッセージ

該当のソースコード

c

1#include <GL/glut.h> 2#include <stdlib.h> 3#include<stdio.h> 4 5 6GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 }; 7GLfloat yellow[] = { 1.0, 1.0, 0.0, 1.0 }; 8 9GLfloat ctrlpoints[4][3]; 10int i = 0; 11 12void mouse(int button, int state, int x, int y) 13{ 14 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 15 { 16 float a = 30, b = 5, c = (float)x / a - b, d = (float)y / a - b; 17 if (i < 4) { 18 ctrlpoints[i][0] = { c }; 19 ctrlpoints[i][1] = { -d }; 20 ctrlpoints[i][2] = { 0.0 }; 21 printf("ctrlpoints[%d]:%lf %lf %lf\n", i, ctrlpoints[i][0], ctrlpoints[i][1], ctrlpoints[i][2]); 22 } 23 printf("(%d, %d)で左ボタンが押されました\n", x, y); 24 i++; 25 } 26 glutPostRedisplay(); 27} 28 29void display(void) 30{ 31 int i; 32 33 glClear(GL_COLOR_BUFFER_BIT); 34 35 glColor4fv(&white[0]); 36 glBegin(GL_LINE_STRIP); 37 for (i = 0; i <= 30; i++) 38 glEvalCoord1f((GLfloat)i / 30.0); 39 glEnd(); 40 41 /* 制御点を描く */ 42 glPointSize(5.0); 43 glColor4fv(&yellow[0]); 44 glBegin(GL_POINTS); 45 for (i = 0; i < 4; i++) 46 glVertex3fv(&ctrlpoints[i][0]); 47 glEnd(); 48 49 glFinish(); 50} 51 52void resize(int w, int h) 53{ 54 glViewport(0, 0, (GLsizei)w, (GLsizei)h); 55 glMatrixMode(GL_PROJECTION); 56 glLoadIdentity(); 57 if (w <= h) 58 glOrtho(-5.0, 5.0, -5.0 * (GLfloat)h / (GLfloat)w, 59 5.0 * (GLfloat)h / (GLfloat)w, -5.0, 5.0); 60 else 61 glOrtho(-5.0 * (GLfloat)w / (GLfloat)h, 62 5.0 * (GLfloat)w / (GLfloat)h, -5.0, 5.0, -5.0, 5.0); 63 glMatrixMode(GL_MODELVIEW); 64 glLoadIdentity(); 65} 66 67void keyboard(unsigned char key, int x, int y) 68{ 69 switch (key) { 70 case '\33': 71 case 'q': 72 case 'Q': 73 exit(0); 74 break; 75 default: 76 break; 77 } 78} 79 80void init(void) 81{ 82 glClearColor(0.0, 0.0, 0.0, 0.0); 83 if (ctrlpoints[3][0] != NULL) { 84 glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]); 85 glEnable(GL_MAP1_VERTEX_3); 86 } 87} 88 89int main(int argc, char** argv) 90{ 91 /* 初期化 */ 92 glutInit(&argc, argv); 93 94 /* ウィンドウの生成 */ 95 glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH); 96 glutInitWindowPosition(200, 50); 97 glutInitWindowSize(300, 300); 98 glutCreateWindow(argv[0]); 99 100 /* OpenGL 初期化ルーチンの呼出し */ 101 init(); 102 103 /* 描画ルーチンの設定 */ 104 glutDisplayFunc(display); 105 glutReshapeFunc(resize); 106 107 /* 入力処理ルーチンの設定 */ 108 glutKeyboardFunc(keyboard); 109 glutMouseFunc(mouse); //コールバック関数の登録 110 111 /* 無限ループ */ 112 glutMainLoop(); 113 114 return 0; 115}

##試したこと

あらかじめ配列の中身を宣言しておくとうまくいくのですが入力を受け付けると出力されません。

補足情報(FW/ツールのバージョンなど)

Windows10 最新のOSにアップデートしています
VScode2019 デバッグなしで実行でビルドしています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/07/10 04:31

何度も見た質問ですが、退会・入会を繰り返していますか?
cawawa

2020/07/10 06:13

はじめてアカウントを作りました、何度も見たのはベストアンサーがなかなか決まらないからではないでしょうか
Zuishin

2020/07/10 06:15

いいえ。コメントや回答がついていました。私も何か書いたと思います。
cawawa

2020/07/10 06:18

それなら他の方ではないでしょうか。
Zuishin

2020/07/10 06:20

違う人だとしたらクラスメイトじゃないですかね。友達に聞くのもいいんじゃないかと思います。
cawawa

2020/07/10 06:23

ちなみに質問するにあたってベジェ曲線に関する他の質問は拝見しましたが、今回のものと書き方や実装が異なっていたので新たに質問させていただきました。先述のものではオブジェクトを置いていたような覚えがあるのですが。
cawawa

2020/07/10 06:26

周りに聞いて解決できなかったのでこちらを利用しているのですが... いろいろタスクに追われていますので、回答にまつわることでなければこれで返信を終わらせていただきます。
Zuishin

2020/07/10 06:27

書きかけましたが、忙しいのでスルーします。
cawawa

2020/07/10 06:30

忙しいのにわざわざご報告有難うございます。では失礼します。
Zuishin

2020/07/10 07:56

いろいろタスクに追われているので、私に益のない返信はご遠慮ください。
cawawa

2020/07/10 08:16

すごいですねその熱意、完敗です 私は興味のない人間にそこまでリソース避けないので分けてほしいくらいです ちなみにそれを投稿するのには二秒くらいしかかかってないですね
Zuishin

2020/07/10 08:20

返信は結構と申し上げましたが、暇なんですね。
cawawa

2020/07/10 08:21 編集

お互い様ですね(苦笑)
Zuishin

2020/07/10 08:22

なぜ忙しいと嘘をついたんですか?
cawawa

2020/07/10 08:24

それまだ続けます?お互いにとって有益な時間だと思えないのですが、なにかどうしてもこだわりたい特別な事情があるのでしょうか... 課題に戻るので次回の返信は三年後にでもします
Zuishin

2020/07/10 08:26

返信はしないでください。迷惑です。
guest

回答1

0

ベストアンサー

関数 mouse 内にprintfが見えますが,そこできちんと
「クリックした座標」が表示されているのでしょうか?

  • 表示されていない場合

→ じゃあ,そもそも入力できてないよね.

  • 表示されている場合

ウィンドウ座標(x,y)と,3次元空間の座標は違うわけですが,そこらへんは大丈夫ですか?
試しに,ウィンドウの左上隅(x,y共に5以下になるような場所が良さそうかな)をクリックしてみたらどうなりますか?


[追記]
曲線が表示されないという件に関して,対応案を示します.
変更があるのはmouse()とinit()のみなので,そこだけを示します.

void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { float a = 30, b = 5, c = (float)x / a - b, d = (float)y / a - b; if (i < 4) { //※ここの右辺が{}で囲まれていたが,コンパイル通らないので{}を除去した ctrlpoints[i][0] = c; ctrlpoints[i][1] = -d; ctrlpoints[i][2] = 0.0; printf("ctrlpoints[%d]:%lf %lf %lf\n", i, ctrlpoints[i][0], ctrlpoints[i][1], ctrlpoints[i][2]); //ここの2行を追加した glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]); glEnable(GL_MAP1_VERTEX_3); } printf("(%d, %d)で左ボタンが押されました\n", x, y); i++; } glutPostRedisplay(); } void init(void) {//不要と思われるコードを除去した glClearColor(0.0, 0.0, 0.0, 0.0); }

投稿2020/07/03 13:59

編集2020/07/10 05:16
fana

総合スコア11632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cawawa

2020/07/03 15:03

表示されています。 関数の外で例えば --- GLfloat ctrlpoints[4][3]={適当なx,y,z 同様のカッコを残り3個続ける}; --- と定義してやると上手くいくので、次元の問題もクリアしているかと思われます 左上をクリックすると例えば ctrlpoints[1]= 0 2 0 (0,2)がクリックされました と出力されます
fana

2020/07/03 15:06

> 左上をクリックすると… そのとき,OpenGLによる制御点の描画は成されるのでしょうか?
fana

2020/07/03 15:16

要するに,mouse()の引数に入ってくる(x,y)は,ウィンドウの左上を原点とした「ピクセル」座標なのであって, display()の中で扱う3次元座標とは全く異なるものなので,「妥当な変換」が必要になるんじゃないか,ということです. 現状でウィンドウ内に描画される3次元座標の範囲って把握できていますか? 例えばウィンドウのサイズが640x480[pixel]のときに,右下隅をクリックしたら,mouse()には (640,480)付近の値が引数として入ってくるわけですが,それをそのまま「3次元座標のxとy」に用いても,そんなでかい値の座標は,描画される範囲に入ってないかもしれませんよね. …的なことが起こってないですか? という.
fana

2020/07/03 15:17

回答内の, > ウィンドウ座標(x,y)と,3次元空間の座標は違うわけですが,そこらへんは大丈夫ですか? というのは,そういう話です.
cawawa

2020/07/03 18:04 編集

なるほど、確かにそこは考えていませんでした。 クリックで代入される値については、表示される3次元座標の範囲を把握し次第修正したいのですが、どこを参照すればよいのか見当がついておらずまだできていません。
cawawa

2020/07/03 18:15

なんとか目視で範囲が-5~5だと確認できたため ctrlpoints[i][0] = { (float)x/30 }; ctrlpoints[i][1] = { (float)y/30 }; ctrlpoints[i][2] = { 0.0 }; と書き換えたのですがビルドエラーになってしまいます。どうやら30がint型として認識されているようなのですが30.0にすると今度はdoubleだと言われ、、
cawawa

2020/07/03 18:32 編集

下記のように書き換えたことで四点の描画ができるようになりましたが、曲線のみ出ません void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { float a = 30, b = 5, c = (float)x / a - b, d = (float)y / a - b; if (i < 4) { ctrlpoints[i][0] = { c }; ctrlpoints[i][1] = { -d }; ctrlpoints[i][2] = { 0.0 }; printf("ctrlpoints[%d]:%lf %lf %lf\n", i, ctrlpoints[i][0], ctrlpoints[i][1], ctrlpoints[i][2]); } printf("(%d, %d)で左ボタンが押されました\n", x, y); i++; } glutPostRedisplay(); }
fana

2020/07/04 03:16

とりあえず座標の問題が解決された(?)ようで何よりです. 曲線の方に関しては, 私は glMap1f() とか glEvalCoord1f() を使ったことがないのでわからんです.
cawawa

2020/07/04 16:03

ありがとうございました。 このページをご覧になった方でもしわかる方いらっしゃいましたらコメントまたは回答よろしくお願いします。
fana

2020/07/06 09:22

init()内の3行のうちの下側2行(glMap1f()とglEnable())を,「4点目がクリックされたとき」に実行するように,書く場所を変えたらどうなりますか?
cawawa

2020/07/08 17:06

返信が遅れてしまいすみません。 画面の描画は無限ループで実行されていると記憶しているのですが、この認識がそもそも間違いでしたらごめんなさい。 if文などで4点目が入力されるまでfalseにしておくということでしょうか。
fana

2020/07/09 09:49

想像ですが, 4点の座標値が定まってからglMap1f()に渡さないとダメなんじゃないかな?と.
cawawa

2020/07/10 04:31 編集

このように変更してみましたが結果変わらずでした #include <GL/glut.h> #include <stdlib.h> #include<stdio.h> GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat yellow[] = { 1.0, 1.0, 0.0, 1.0 }; GLfloat ctrlpoints[4][3]; int i = 0; void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { float a = 30, b = 5, c = (float)x / a - b, d = (float)y / a - b; if (i < 4) { ctrlpoints[i][0] = { c }; ctrlpoints[i][1] = { -d }; ctrlpoints[i][2] = { 0.0 }; printf("ctrlpoints[%d]:%lf %lf %lf\n", i, ctrlpoints[i][0], ctrlpoints[i][1], ctrlpoints[i][2]); } printf("(%d, %d)で左ボタンが押されました\n", x, y); i++; } glutPostRedisplay(); } void display(void) { int i; glClear(GL_COLOR_BUFFER_BIT); glColor4fv(&white[0]); glBegin(GL_LINE_STRIP); for (i = 0; i <= 30; i++) glEvalCoord1f((GLfloat)i / 30.0); glEnd(); /* 制御点を描く */ glPointSize(5.0); glColor4fv(&yellow[0]); glBegin(GL_POINTS); for (i = 0; i < 4; i++) glVertex3fv(&ctrlpoints[i][0]); glEnd(); glFinish(); } void resize(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-5.0, 5.0, -5.0 * (GLfloat)h / (GLfloat)w, 5.0 * (GLfloat)h / (GLfloat)w, -5.0, 5.0); else glOrtho(-5.0 * (GLfloat)w / (GLfloat)h, 5.0 * (GLfloat)w / (GLfloat)h, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keyboard(unsigned char key, int x, int y) { switch (key) { case '\33': case 'q': case 'Q': exit(0); break; default: break; } } void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); if (ctrlpoints[3][0] != NULL) { //4点入力されてから渡すように変更 glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]); glEnable(GL_MAP1_VERTEX_3); } } int main(int argc, char** argv) { /* 初期化 */ glutInit(&argc, argv); /* ウィンドウの生成 */ glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH); glutInitWindowPosition(200, 50); glutInitWindowSize(300, 300); glutCreateWindow(argv[0]); /* OpenGL 初期化ルーチンの呼出し */ init(); /* 描画ルーチンの設定 */ glutDisplayFunc(display); glutReshapeFunc(resize); /* 入力処理ルーチンの設定 */ glutKeyboardFunc(keyboard); glutMouseFunc(mouse); //コールバック関数の登録 /* 無限ループ */ glutMainLoop(); return 0; }
fana

2020/07/10 04:50

mouse()関数内で制御点を更新する箇所: > printf("ctrlpoints[%d]:%lf %lf %lf\n", i, ctrlpoints[i][0], ctrlpoints[i][1], ctrlpoints[i][2]); のあたり(例えば,このprintfの前か次の行として)に, > glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]); を追加しても何も変化は起きないでしょうか?
cawawa

2020/07/10 04:57

試してみましたが、やはり変わりません
fana

2020/07/10 05:18 編集

コメント欄にコード貼るのはきついので,回答の方に追記してみました. 3つ上のコメントに貼られたコードの,mouse()とinit()の中身を回答のコードに変更したら曲線が表示されませんでしょうか?
cawawa

2020/07/10 06:39

有難うございます。提示していただいたコードを参考に修正したところ、無事曲線が描画されるようになりました。後学のためにもしよければお聞きしたいのですが、コメント欄に貼ったコードで描画されなかった原因として何が考えられますでしょうか。こちらの環境ではコンパイルは通り点だけ反映されるという状態でした。
fana

2020/07/10 07:23

関数init()は最初ら辺に1回しか呼ばれていません. で,おそらく,その時にはif()の条件(この条件自体怪しいですが,それはそれとして)を満たさず,結果として, glEnable(GL_MAP1_VERTEX_3); が実行されなかったのでしょう. あとは,glMap1f()は,引数に渡された座標値を用いるだろうから,制御点の座標が変わったならばその座標値を glMap1f() に渡す必要があるだろう,という考えのもとで,mouse()内にglMap1f()を移動させました.
cawawa

2020/07/10 07:52

なるほど、理解できました。ありがとうございました。
fana

2020/07/10 08:20

こちらも glMap1f() のような関数の存在を知ることができて良かったです.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問