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

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

ただいまの
回答率

88.78%

OpenGLを用いて点を描画することでシュミレーション結果を可視化したい

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,490

muton

score 31

オープンソースコードのカーシュミレーションソフトにおいてある座標位置にOpenGLを用いて、点をシミュレーション画面上に描画したいと考えています。

初めにx座標=74,y座標=171,z座標=0に点を描画するプログラミングを以下の様に組みました。
しかし、ビルドは通るのですが、シミュレーション画面上に点が確認できません。
アドバイスを頂けると嬉しいです。

void grDrawCar(tCarElt *car, tCarElt *curCar, int dispCarFlag, int dispDrvFlag, double curTime, class cGrPerspCamera *curCam)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3d(1.0, 0.0, 0.0);
    glPointSize(500);
    glBegin(GL_POINTS);
    glVertex3d(74, 171, 0);
    glEnd();
    glFlush();
}

試したこと

1.チュートリアルを参考に、新しいプロジェクトを立ち上げ、二次元図形を描くことでOpenGLの理解を深めました。

2.シュミレーションゲームの背景の色を変更することはできました。

void grDrawCar(tCarElt *car, tCarElt *curCar, int dispCarFlag, int dispDrvFlag, double curTime, class cGrPerspCamera *curCam)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(0.0, 0.0, 1.0, 1.0);
}

使用環境

GLUTによる「手抜き」OpenGL入門を参考にし、
GLUT を用いた OpenGLを使用しています。

GLUT を用いるためにfreeglut をコンパイルし、
freeglutd.lib, freeglut_staticd.lib,freeglutd.dll
glut.h freeglut.h freeglut_std.h freeglut_ext.h
を用いています。

windows8.1/visual studio2017/C++

解答用の画像

イメージ説明

現状

イメージ説明
イメージ説明
描画させたい箇所:赤い丸(コース上の位置座標:x座標=74,y座標=171,z座標=0)
現在実際に描画されている箇所:黄色い丸(背景??コース上ではない)

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

+2

点を描画しようとしている座標(74, 171, 0)というのは、もしかしてピクセル単位のスクリーン座標でしょうか。
描画時の変換行列が正しく設定されているかどうかが気になりますね。仮に描画領域が幅640ピクセル、高さ480ピクセル、原点を左上隅とすると、下記のようにした場合...

void grDrawCar(tCarElt *car, tCarElt *curCar, int dispCarFlag, int dispDrvFlag, double curTime, class cGrPerspCamera *curCam)
{
    glClear(GL_COLOR_BUFFER_BIT);

    // プロジェクション行列は単位行列とする
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // モデルビュー行列は上下反転、横0〜680・縦0〜480とする
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glScaled(1.0, -1.0, 1.0);
    glOrtho(
            0.0,
            640.0,
            0.0,
            480.0,
            -1.0,
            1.0);

    glColor3d(1.0, 0.0, 0.0);
    glPointSize(500);
    glBegin(GL_POINTS);
    glVertex3d(74, 171, 0);
    glEnd();
    glFlush();
}


下図のようになるでしょうか?
結果

追記
TORCSのall-in-oneをダウンロード、まずはサイトのWindows向けガイドに従ってビルドし(Windows 10 バージョン1803、Visual Studio Community 2019 バージョン16.0.3を使用したため、ソリューションを私の環境に合わせてアップグレード、ビルドを通すためいくつか泥縄的改修を加えました...過去のご投稿を拝見しますと、ご質問者さんもいろいろ工夫されたご様子ですね)、ひとまずそのままでちゃんと動くか確認したのち改造案を検討してみました。

glClearで全面を塗りつぶしてみると背景だけが塗られたり、点を描こうとすると前景に隠れてしまったり...といった現象があるとのことですが、見た感じgrDrawCarのタイミングでは車の描画は行われておらず、PLIBのSSGとかいう機能(これも初めて知りましたもので知識がなく、突っ込んだご質問は勘弁願います...)を使って構築された階層構造内の情報を更新しているだけのようです。
前景部分...つまりサーキットや車など諸々の3Dオブジェクト実際の描画はgrscreen.cppcGrScreen::camDraw末尾にあるgrDrawScene();が起点となっているようで、その内部ではssgCullAndDraw(TheScene);TheScenessgRootオブジェクトで、これがシーン上の3Dオブジェクトが所属するヒエラルキーの頂点にいるっぽいですね)によってシーン全体が描画されるように思われました。

SSGにはヒエラルキー上のエンティティが描画される前とか後のタイミングでコールバックを実行する機能があるようでしたので、それを使ってgrDrawCar内ではなくTheScene描画後のタイミングで追加描画を行った方がいいんじゃないか...と思い、下記のようにしてみました(TheScene描画後にはさらに反射?やダッシュボードのようなUI類の描画が入るようですが、ダッシュボードよりは奥に描画された方がよさそうということと、反射の後に追加描画を仕込むのは面倒そうという理由から、手軽にアクセスできるTheSceneを選びました)。

grcar.cpp

/***************************************************************************

    file                 : grcar.cpp
    created                 : Mon Aug 21 18:24:02 CEST 2000
    copyright             : (C) 2000 by Eric Espie
    email                 : torcs@free.fr
    version                 : $Id: grcar.cpp,v 1.42.2.9 2012/06/06 13:56:39 berniw Exp $

***************************************************************************/

/***************************************************************************
 *                                                                           *
 *     This program is free software; you can redistribute it and/or modify  *
 *     it under the terms of the GNU General Public License as published by  *
 *     the Free Software Foundation; either version 2 of the License, or       *
 *     (at your option) any later version.                                   *
 *                                                                           *
 ***************************************************************************/

// 省略

// 後述のコールバックとして使用する関数を適当な位置に用意する
int drawMarker(ssgEntity *entity, int traversal_mask) {
    // まずアトリビュートを保存
    glPushAttrib(GL_ALL_ATTRIB_BITS);

    // 各種設定を適宜無効化(または使用したい機能があれば有効化)
    glDisable(GL_CULL_FACE);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_LIGHTING);
    glDisable(GL_DEPTH_TEST);

    // 点を描画
    // パースペクティブ行列はこの時点ですでに適正に設定されているでしょうから操作せず、
    // モデルビュー行列もワールド空間をメインカメラでとらえるような形になっていると思いますので
    // gluLookAtなどを駆使して調整してやる必要はなさそうです
    glColor3d(1.0, 0.0, 0.0);
    glPointSize(60);
    glBegin(GL_POINTS);
    glVertex3d(602.849609, 1167.055908, 3.845393); // Forzaサーキットのスタート地点の座標はこの辺?
    glEnd();

    // アトリビュートを復元
    glPopAttrib();

    return TRUE;
}

void grDrawCar(tCarElt * car, tCarElt * curCar, int dispCarFlag, int dispDrvFlag, double curTime, class cGrPerspCamera* curCam)
{
    sgCoord wheelpos;
    int index, i, j;
    static float maxVel[3] = { 20.0, 40.0, 70.0 };
    float lod;

    TRACE_GL("cggrDrawCar: start");

    // 省略

    /* push the car at the end of the display order */
    CarsAnchorTmp->addKid(grCarInfo[index].carTransform);
    CarsAnchor->removeKid(grCarInfo[index].carTransform);
    CarsAnchor->addKid(grCarInfo[index].carTransform);
    CarsAnchorTmp->removeKid(grCarInfo[index].carTransform);

    // もしTheScene描画後のタイミングにまだコールバックが仕込まれていなければ...
    if (!(TheScene->getTravCallback(SSG_CALLBACK_POSTTRAV))) {
        // コールバックとしてdrawMarkerを仕込む
        TheScene->setTravCallback(SSG_CALLBACK_POSTTRAV, drawMarker);
    }

    TRACE_GL("cggrDrawCar: end");
}

上記のようにしたところ、下図のように路上の地点を示す赤四角が現れました。すみませんが、上で申し上げたように手抜きして描画タイミングにTheScene描画後を選んだため、車の窓ガラス・テールランプなどの映り込みが四角の上に重ね描きされてしまいました。

結果1

せっかくですので、点以外も描いてみようと思ってdrawMarkerを下記のようにしたところ...

int drawMarker(ssgEntity *entity, int traversal_mask) {
    // まずアトリビュートを保存
    glPushAttrib(GL_ALL_ATTRIB_BITS);

    // 表面材質その他を設定
    static const GLfloat diffuse[] = {1.0, 0.0, 0.0, 1.0};
    static const GLfloat specular[] = {1.0, 1.0, 1.0, 1.0};
    glCullFace(GL_FRONT);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_COLOR_MATERIAL);
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, specular);

    // 点を打つだけなら行列操作の必要はないでしょうが、
    // 現在のモデルビュー行列にさらに変換を重ねる場合は
    // 操作前の行列を保存しておくべきでしょう
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();

    // モデル原点をスタート地点付近に向きを合わせて据えて...
    glTranslated(602.849609, 1167.055908, 3.845393);
    glRotated(90, 1, 0, 0);
    glRotated(90, 0, 1, 0);
    glTranslated(0, 2, 0);

    // ティーポットを描く
    glutSolidTeapot(3);

    // モデルビュー行列を復元
    glPopMatrix();

    // アトリビュートを復元
    glPopAttrib();

    return TRUE;
}

下図のように路上にティーポットが現れました。もちろん物理的形状は持っていませんので、車は貫通してしまいますが...

結果2

おまけ
点のサイズを奥行きに反比例して変化させても面白いように思います。点の遠さを把握しやすくなるんじゃないでしょうか?

int drawMarker(ssgEntity *entity, int traversal_mask) {
    glPushAttrib(GL_ALL_ATTRIB_BITS);

    // デプステストを無効化しないでおくと
    // 点より手前のオブジェクトによって点が隠れるようになる
    glDisable(GL_CULL_FACE);
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_LIGHTING);

    // 現在のモデルビュー行列を取得
    GLfloat mvMat[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, mvMat);

    // 描画先の座標を...
    double worldX = 602.849609;
    double worldY = 1167.055908;
    double worldZ = 3.845393;

    // Z成分だけでいいので、ビュー座標に変換する
    // ついでに正負反転し、遠いほど大きい値になるようにする
    double viewZ = -(mvMat[2] * worldX + mvMat[6] * worldY + mvMat[10] * worldZ + mvMat[14]);

    // 奥行き10でサイズ50ピクセルになるものとすると...
    double refPointSize = 50;
    double refViewZ = 10;

    // 距離の最小値を0.1としたら、点のサイズはこうなる
    // ただし1ピクセル未満にはならないようにした
    double pointSize = max((refPointSize * refViewZ) / max(viewZ, 0.1), 1);

    glColor3d(1.0, 0.0, 0.0);
    glPointSize((int)pointSize);
    glBegin(GL_POINTS);
    glVertex3d(worldX, worldY, worldZ);
    glEnd();

    glPopAttrib();

    return TRUE;
}


結果3

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/29 18:11

    回答ありがとうございます。
    説明不足で申し訳ございません。
    提示いただいたURLのTORCSで間違いないです。

    デフォルトで、ミニマップ上に車を表す描画機能はついています。
    追記に示した通り、赤い丸で示す位置(コース上)に点を描画したいということになります。

    何度も申し訳ございません。宜しくお願い致します。

    キャンセル

  • 2019/05/30 18:30

    なるほど誤解していました。地平線の向こうで動いている赤黒い四角が描画した点だったんですね...
    `(74, 171, 0)`というのはサーキット空間(ワールド空間?)内の一点を表していて、そこに描画することでサーキットの路上に赤い点が置いてあるように見せたいというわけですね。
    TORCSをダウンロードしていじってみた結果を追記しましたが、ご参考になりそうでしょうか?

    キャンセル

  • 2019/06/14 17:00

    ご丁寧な回答感謝いたします。
    教えていただいたことを基に、試行錯誤を行った結果、やりたいことができました。
    本当にありがとうございます。

    キャンセル

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

  • ただいまの回答率 88.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る