Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

C言語 モデル移動

解決したいこと

"wireframe.txt"を読み取り、x,y,z方向各2倍に拡大し,y軸まわりに20度回転し,x方向に100,y方向に50,
z 方向に100平行移動したものを描画するプログラムを作成しなさい。ただし,視点は(0.0, 0.0, 500.0)とする。
自分で書いたコードだと何も表示されなかったです。
原因は何でしょうか?また、改善すべきはどこでしょうか?

該当するソースコード

#include
#include
#include
#define MAXPOINT 100
#define MAXLINE 100

const double zv = 100.0;

// 3次元座標構造体
typedef struct {
double x, y, z;
} POINT3D;

// 描画用2次元座標構造体
typedef struct {
double x, y;
} POINT2D;

// 稜線構造体
typedef struct {
int n0, n1;
} LINE;

// ファイル読み込み用のグローバル変数
POINT3D p[MAXPOINT];
LINE r[MAXLINE];
int np, nl;

// ワイヤフレームモデルを読み込む関数
int ReadWireframeData(void) {
FILE* fp;
// ファイルオープン
if ((fp = fopen("wireframe.txt", "r")) == NULL) {
return -1;
}
// 3次元空間の座標を読み込み
// 点の個数を読み込む
fscanf(fp, "%d", &np);

// 座標を読み込む
for (int i = 0; i < np; i++) {
    fscanf(fp, "%lf,%lf,%lf", &(p[i].x), &(p[i].y), &(p[i].z));
    // Apply transformations: scaling, rotation, and translation
    p[i].x *= 2.0;
    p[i].y *= 2.0;
    p[i].z *= 2.0;
    // Rotate 20 degrees around the y-axis
    double angle = 20.0 * M_PI / 180.0;  // Convert degrees to radians
    double new_x = cos(angle) * p[i].x - sin(angle) * p[i].z;
    double new_z = sin(angle) * p[i].x + cos(angle) * p[i].z;
    p[i].x = new_x;
    p[i].z = new_z;
    // Translate
    p[i].x += 100.0;
    p[i].y += 50.0;
    p[i].z += 100.0;
}

// 稜線の個数を読み込む
fscanf(fp, "%d", &nl);
// 稜線データを読み込む
for (int i = 0; i < nl; i++) {
    fscanf(fp, "%d,%d", &(r[i].n0), &(r[i].n1));
}

// ファイルクローズ
fclose(fp);

return 0;

}

// 投資投影変換を行う関数
POINT2D Transform(POINT3D p) {
POINT2D ans = {0.0, 0.0};
ans.x = (zv / (zv - p.z)) * p.x;
ans.y = (zv / (zv - p.z)) * p.y;
return ans;
}

// 点の描画関数
void DrawPoint(POINT2D p) {
glBegin(GL_POINTS);
glVertex2d(p.x, p.y);
glEnd();
}

// 読み込んだ線の描画関数
void DrawLine(LINE line) {
glBegin(GL_LINES);

POINT2D p0, p1;

// Transformation
p0 = Transform(p[line.n0]);
p1 = Transform(p[line.n1]);

// 描画する2点を指定
glVertex2d(p0.x, p0.y);
glVertex2d(p1.x, p1.y);

glEnd();

}

// 描画を行うコールバック関数
void myDisplay() {
glClear(GL_COLOR_BUFFER_BIT); // 描画内容の消去
glColor3d(1.0, 1.0, 1.0); // 描画の色の設定(白)

// Set up transformation matrices (scaling, rotation, translation)
glMatrixMode(GL_MODELVIEW); // Use the modelview matrix
glLoadIdentity(); // Reset the transformation matrix to the identity matrix

// Apply transformations
glScaled(2.0, 2.0, 2.0); // Scaling by 2 in all directions
glTranslated(100.0, 50.0, 100.0); // Translation
glRotated(20.0, 0.0, 1.0, 0.0); // Rotation around the y-axis by 20 degrees

// Translate to the viewer's position
glTranslated(0.0, 0.0, 500.0);

for (int i = 0; i < nl; i++) {
    DrawLine(r[i]);
}

glFlush(); // 描画の実行

}

// ウィンドウ再作成を行うコールバック関数
void myReshape(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); // Use the projection matrix
glLoadIdentity();
glOrtho(-width / 2.0, width / 2.0, -height / 2.0, height / 2.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW); // Switch back to the modelview matrix
}

int main(int argc, char* argv[]) {
// ファイル読み込み
if (ReadWireframeData() == -1) {
printf("ファイルが読み込めません!!\n");
return -1;
}

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glClearColor(0.0, 0.0, 0.0, 0.0);
glutMainLoop();
return 0;

}

自分で試したこと

上のコードを書いたのですが、何も表示されません。

0

1Answer

まず include欠損、ネストなしで読みにくいです。

原因は何でしょうか?

図形がビューに入っていないからと考えます。
また、肝心の座標データが提供されてないので、ビューに入らなかった原因を調べる事はできません。

改善すべきはどこでしょうか?

プログラムからは、
1.プログラムで2D変換して描画してOPENGLで2D表示
2.3Dで描画してOPENGLで2D表示
の2つの処理が混ざっていてどう考えて作成したか読み取れません。

1.のプログラムで2D変換して描画してOPENGLで2D表示したいとして答えます。

・ファイル入力で視点分のオフセットがないので追加
int ReadWireframeData(void)

// 座標を読み込む
for (int i = 0; i < np; i++) {
    fscanf(fp, "%lf,%lf,%lf", &(p[i].x), &(p[i].y), &(p[i].z));
    // Apply transformations: scaling, rotation, and translation
    p[i].x *= 2.0;
    p[i].y *= 2.0;
    p[i].z *= 2.0;
    // Rotate 20 degrees around the y-axis
    double angle = 20.0 * M_PI / 180.0;  // Convert degrees to radians
    double new_x = cos(angle) * p[i].x - sin(angle) * p[i].z;
    double new_z = sin(angle) * p[i].x + cos(angle) * p[i].z;
    p[i].x = new_x;
    p[i].z = new_z;
    // Translate
    p[i].x += 100.0;
    p[i].y += 50.0;
-   p[i].z += 100.0;
+   p[i].z += 100.0 -500;

}

・ファイル入力で座標の変換(拡大・回転・移動)しているので3Dでの変換を削除
void myDisplay()

// Set up transformation matrices (scaling, rotation, translation)
glMatrixMode(GL_MODELVIEW); // Use the modelview matrix
glLoadIdentity(); // Reset the transformation matrix to the identity matrix

-// Apply transformations
-glScaled(2.0, 2.0, 2.0); // Scaling by 2 in all directions
-glTranslated(100.0, 50.0, 100.0); // Translation
-glRotated(20.0, 0.0, 1.0, 0.0); // Rotation around the y-axis by 20 degrees
-
-// Translate to the viewer's position
-glTranslated(0.0, 0.0, 500.0);

・0割およびマイナス値での座標クリップ( 適当に0.1で制限してます )
・本来視点とスクリーン位置を加味して計算すると思いますが、それは質問者殿にまかせます。
POINT2D Transform(POINT3D p)

-// 投資投影変換を行う関数
+// 透視投影変換を行う関数
POINT2D Transform(POINT3D p) {
POINT2D ans = {0.0, 0.0};
-ans.x = (zv / (zv - p.z)) * p.x;
-ans.y = (zv / (zv - p.z)) * p.y;
+    double dz = zv - p.z;
+    if( dz < 0.1 )
+    {
+        dz = 0.1;
+    }
+    ans.x = (zv / dz) * p.x;
+    ans.y = (zv / dz) * p.y;
return ans;
}

wireframe.txt が以下の場合で表示できました。

8
 100.0,  100.0,   100.0
 100.0, -100.0,   100.0
-100.0, -100.0,   100.0
-100.0,  100.0,   100.0
 100.0,  100.0,  -100.0
 100.0, -100.0,  -100.0
-100.0, -100.0,  -100.0
-100.0,  100.0,  -100.0
12
 0, 1
 1, 2
 2, 3
 3, 0
 4, 5
 5, 6
 6, 7
 7, 4
 0, 4
 1, 5
 2, 6
 3, 7

スクリーンショット 2023-10-29 16.21.47.png
どうでしょう。

1Like

Your answer might help someone💌