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

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

ただいまの
回答率

90.51%

  • C++

    4434questions

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

  • OpenGL

    204questions

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

法線ベクトルの単純平均について

受付中

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 910

windowsaa

score 9

同じような内容の連続投稿となってしまいすみません。

また新たな質問として質問することとしました。

頂点の法線を単純に頂点を共有するメッシュの面法線を平均して求めて陰影をつけたいと思っていますが書き方がわからず苦戦しています。

#include"stlreader.h"

#define STL_FILE "C:\\Users\\onower\\Desktop\\nsx_concept_LOW.stl"


using namespace std;

float light_pos[] = { -5.0, 5.0, 5.0, 1.0 };

//プロトタイプ宣言
void display(void);
void reshape(int w, int h);
void draw();
void init();
void DRAW_XYZ();
void MouseWheel(int wheel, int direction, int x, int y);
void mouse(int button, int state, int x, int y);
void motion(int x, int y);

Triangle *triangles;
int num;
STLreader stlreader;
int rate = 1.0;
double xAngle = 0.0, yAngle = 0.0;

int main(int argc, char *argv[])
{
    glutInitWindowPosition(128, 128);
    glutInitWindowSize(800, 800);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("argv[0]");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutMouseWheelFunc(MouseWheel);
    //    glutKeyboardFunc(keyboard);
    glutMainLoop();

        if (triangles)
            delete[] triangles;

    return 0;
}


void display(void)
{


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);



    glLoadIdentity();
    gluLookAt(10.0 * rate,15.0 * rate ,10.0 * rate, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //視点の設定

    //glLightfv(GL_LIGHT0, GL_POSITION, light_pos);

    glRotated(xAngle, 1, 0, 0);
    glRotated(yAngle, 0, 1, 0);


    draw();  //描画

    glutSwapBuffers();  //ウィンドウに出力



    //double* getNormalVert(Triangle trinangles);

}


void reshape(int w, int h)
{
    glViewport(0, 0, w, h);  //ビューポートの設定
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(30.0, (double)w / (double)h, 1.0, 100.0); //視野の設定
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();


}



void draw()
{


     DRAW_XYZ(); //XYZ軸の描画    

     glBegin(GL_TRIANGLES);

     glColor3f(1.0, 0.0, 0.0);


    for (int i = 0; i < num; i++)   //stlデータの描画
    {

        glNormal3dv(triangles[i].nornVec);
        glVertex3dv(triangles[i].pnt1);
        glVertex3dv(triangles[i].pnt2);
        glVertex3dv(triangles[i].pnt3);




    }

    glEnd();
    glFlush();


}


void init()
{

    if (triangles)
        delete[] triangles;

    num = stlreader.countTriangles(string(STL_FILE));  //stlデータを構成しているポリゴンの数のをカウント


    if (!(num = stlreader.countTriangles(string(STL_FILE))))

        return;

    triangles = new Triangle[num];

    stlreader.readASCIISTLFile(STL_FILE, triangles);

    stlreader.readBinarySTLFile(STL_FILE, triangles);

    glClearColor(1.0, 1.0, 1.0, 1.0);

}



void DRAW_XYZ()
{
    glDisable(GL_LIGHTING);
    glDisable(GL_LIGHT0);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_NORMALIZE);

    glBegin(GL_LINES);

    glColor3d(0, 1, 0);//x軸緑
    glVertex2d(-1000, 0);
    glVertex2d(1000, 0);

    glColor3d(1, 0, 0);//y軸赤
    glVertex2d(0, -1000);
    glVertex2d(0, 1000);

    glColor3d(0, 0, 1);//z軸青
    glVertex3d(0, 0, -1000);
    glVertex3d(0, 0, 1000);

    glEnd();




    glEnable(GL_DEPTH_TEST);
    glEnable(GL_NORMALIZE);
    //glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
}


void MouseWheel(int wheelnumber, int direction, int x, int y)
{

    if (direction > 0)
    {
        rate++;

    }
    else
    {
        rate--;

    }

    glutPostRedisplay();

}


int xStart, yStart;
bool mouseFlag = GL_FALSE;
void mouse(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON &&state == GLUT_DOWN)
    {
        xStart = x;
        yStart = y;
        mouseFlag = GL_TRUE;
    }
    else
    {
        mouseFlag = GL_FALSE;

    }

}

void motion(int x, int y)
{
    int xdis, ydis;
    double a = 0.5;

    if (mouseFlag == GL_FALSE)return;

    xdis = x - xStart;
    ydis = y - yStart;

    xAngle += (double)ydis * a;
    yAngle += (double)xdis * a;

    xStart = x;
    yStart = y;
    glutPostRedisplay();
}

ヘッダーファイル

#include <iostream>
#include <cmath>
#include <string>
#include <fstream>

using namespace std;

struct vert
{
    double pnt1[3];
    double pnt2[3];
    double pnt3[3];
};

struct vert4
{
    double pnt1[4];//x,y,z,w
    double pnt2[4];
    double pnt3[4];
};

struct Triangle {
    double nornVec[3];
    double pnt1[3];
    double pnt2[3];
    double pnt3[3];
    unsigned int index;
};


class STLreader
{

    unsigned int num_tmp_points;//一時的な変数
    unsigned int num_triangles;//三角形の数



public:
    static int countTriangles(string filename)
    {
        //STLファイルのオープン
        ifstream ifs;
        char line[80];
        ifs.open(filename);
        if (ifs.fail())
            return false;
        string str;
        int count = 0;
        int a;
        getline(ifs, str);
        //int h = str.find("solid");
        if (str.find("solid")==-1){
            ifs.close();
            ifs.open(filename, ios::binary);
            if (ifs.fail())
                return false;
            ifs.read(line, 80);
            ifs.read(line, 4);
            return *(int *)line;
        }
        while (getline(ifs, str)){
            a = str.find("normal");
            if (a > 0)
                count++;
        }
        ifs.close();
        return count;
    };

    bool readASCIISTLFile(string filename, Triangle *values)
    {

        //STLファイルのオープン
        ifstream ifs(filename);
        if (ifs.fail())
            return false;

        //vector<mesh> Stldata;
        string str;
        int index = 0, j;
        double x = 0, y = 0, z = 0;
        //tmp_point *tmp_pnt = new tmp_point;

        getline(ifs, str);
        if (0 < str.find("solid"))
            return false;
        //ファイルから座標値の読み込み
        printf("Tring text STL file ...");
        num_tmp_points = 0;
        num_triangles = 0;


        while (getline(ifs, str)){



            //vertexが見つかるまで読み飛ばす
            j = str.find("vertex");
            if (j<0)
                continue;
            //連続する3頂点の読み込みポリゴンを登録
            //tmp_pnt = (tmp_point *)malloc(sizeof(tmp_point));
            for (int c = 2; c >= 0; c--)
            {
                values[num_triangles].pnt1[c] = atof(str.substr(str.rfind(" ")).c_str());
                str.erase(str.rfind(" "));
                num_tmp_points++;
            }
            //point_array[num_tmp_points-1] = tmp_pnt;

            //tmp_pnt = (tmp_point *)malloc(sizeof(tmp_point));
            getline(ifs, str);

            for (int c = 2; c >= 0; c--)
            {
                values[num_triangles].pnt2[c] = atof(str.substr(str.rfind(" ")).c_str());
                str.erase(str.rfind(" "));
                //tmp_pnt->index = num_tmp_points;
                num_tmp_points++;
            }
            //point_array[num_tmp_points-1] = tmp_pnt;

            //tmp_pnt = (tmp_point *)malloc(sizeof(tmp_point));
            getline(ifs, str);

            for (int c = 2; c >= 0; c--)
            {
                values[num_triangles].pnt3[c] = atof(str.substr(str.rfind(" ")).c_str());
                str.erase(str.rfind(" "));
                //tmp_pnt->index = num_tmp_points;
                num_tmp_points++;
            }

            values[num_triangles].nornVec[0] = getNormalVert(values[num_triangles])[0];
            values[num_triangles].nornVec[1] = getNormalVert(values[num_triangles])[1];
            values[num_triangles].nornVec[2] = getNormalVert(values[num_triangles])[2];

            values[num_triangles].index = num_triangles;
            num_triangles++;

        }
        ifs.close();
        //fclose(in);
        if (num_triangles > 0)
            printf("Done.\n");
        else
            printf("Failed\n");
        return(num_triangles > 0);

    }

    bool readBinarySTLFile(string STL_file, Triangle *values)
    {
        char line[81];
        float *coord;
        int num;
        FILE *in;
        errno_t error;

        ifstream ifs(STL_file);
        if (ifs.fail())
            return false;


        if ((error = fopen_s(&in,STL_file.c_str(), "rb")) != 0)
        {
            // エラー処理
            //ofs << "Can't open file " << endl;
            fclose(in);
            return false;
        }

        //最初の84ビット分を読み飛ばす
        if (fread(line, 1, 80, in) != 80)
            return false;

        printf("Tring binary STL file ...");
        fread(line, 1, 4, in);
        num = *(int*)line;

        //ofs << "number of triangles: " << num<< endl;
        int j = 0;
        //ofs << "solid model" << endl;
        while (fread(line, 1, 50, in) == 50)
        {
            coord = (float *)line;
            //values[j].nornVec[0] = coord[0];
            //values[j].nornVec[1] = coord[1];
            //values[j].nornVec[2] = coord[2];

            values[j].pnt1[0] = coord[3];
            values[j].pnt1[1] = coord[4];
            values[j].pnt1[2] = coord[5];

            values[j].pnt2[0] = coord[6];
            values[j].pnt2[1] = coord[7];
            values[j].pnt2[2] = coord[8];

            values[j].pnt3[0] = coord[9];
            values[j].pnt3[1] = coord[10];
            values[j].pnt3[2] = coord[11];

            values[j].nornVec[0] = getNormalVert(values[j])[0];
            values[j].nornVec[1] = getNormalVert(values[j])[1];
            values[j].nornVec[2] = getNormalVert(values[j])[2];
            values[j].index = j;
            j++;

        }

        //ofs << "endsolid model" << endl;
        fclose(in);
        //ofs.close();
        if (num > 0)
            printf("Done.\n");
        else
            printf("Failed\n");
        return(num > 0);

    }


    //vec0とvec1の内積の計算
    double dot(double vec0[], double vec1[])
    {
        return (vec0[0] * vec1[0] + vec0[1] * vec1[1] + vec0[2] * vec1[2]);
    }

    void cross(double vec0[], double vec1[], double vec2[])
    {
        vec2[0] = vec0[1] * vec1[2] - vec0[2] * vec1[1];
        vec2[1] = vec0[2] * vec1[0] - vec0[0] * vec1[2];
        vec2[2] = vec0[0] * vec1[1] - vec0[1] * vec1[0];
    }

    void normVec(double vec[])
    {
        double norm;
        norm = sqrt((vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]));
        vec[0] /= norm; vec[1] /= norm; vec[2] /= norm;
    }

    double* getNormalVert(Triangle vertex)
    {
        double normalVec[3] = {};
        double vec1[3] = { vertex.pnt2[0] - vertex.pnt1[0],
                            vertex.pnt2[1] - vertex.pnt1[1],
                            vertex.pnt2[2] - vertex.pnt1[2] };
        double vec2[3] = { vertex.pnt3[0] - vertex.pnt2[0],
                            vertex.pnt3[1] - vertex.pnt2[1],
                            vertex.pnt3[2] - vertex.pnt2[2] };
        cross(vec1, vec2, normalVec);
        normVec(normalVec);//正規化

        return normalVec;
    }




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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    2017/11/14 16:50

    複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

回答 3

+1

やり方は前回の質問に書いたとおりです。
https://teratail.com/questions/100307

私が「やり方しか書かなかった」のは「慈善でコードを提供するには作業量が多すぎる」からです。技術の話であれば私は延々喋り続けられますが、正解がただ欲しいという人には厳しくあたります。ここはエンジニアがお互いの疑問に答え研鑽する場であり、他人にやってほしいことを頼む場ではないです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

3Dデータを扱いたいのであれば先ず基本となるベクトル演算に(空間幾何学)関する基礎を身に着けましょう。
それからでないと説明している言葉を理解していただくのが難しいと思います。

たとえば件の法線ですが、ベクトルの外積を計算すればよいわけですが、その意味が分からなければ説明自体を理解してもらうことが難しいと思います。

先ず基礎を身に着ける努力をして見ましょう。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

前回の質問に対する回答の一番最初の「自力で変換」のところで方針を示していただいていますが、
STLは位相情報がないポリゴンフォーマットですので、まずは、座標が一致==位相的に同一の頂点、
とみなして、頂点の共有状況を求めないことにはその先の計算に進めませんね。

座標の一致判定はトレランスを考慮すると難しくなりますが、パフォーマンスを気にしないので
あれば、単純に1点頂点を読むごとに、それまでに読んだ頂点を総当りでdouble値として完全一致
するものがないか調べるだけで良いと思います。
(内容やコードの質から察するに、大学のCG系の課題とかでは?、と推測したのですが、
そうであれば、大規模モデルとかパフォーマンスとかは、2の次でいいかもですし)

今更ですが、なめらかな表示ではなく、Trinagle単位でパキパキの表示で良いのであれば、STLの法線
&法線の指定はサボって、単にglEnable(GL_AUTO_NORMAL);を指定する、という手もありますね。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

  • C++

    4434questions

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

  • OpenGL

    204questions

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