読み込んだSTL形式の3Dオブジェクトと、作成した立方体の3DオブジェクトをAR表示するプログラムを作っています。
その立方体の3Dオブジェクトの半透明化処理でつまづいております。
ARを行うプログラミングにおいて立方体を半透明化したいのですが、半透明化する関数(glColor4f())がうまく適応されていないみたいです。
現在のプログラムではコンパイルは通っており、半透明化されていない立方体を表示できる状態です。
環境光などの部分を変更してみましたが上手くいきませんでした。
どのようにすれば立方体を半透明化できるかご教示いただきたいです。
お手数をおかけしますがよろしくお願いします。
【環境】
OS:Windows
コンパイラ:Visual studio2022 C言語
またARToolKit・OpenGL・GLUTを使用してます。
C言語は大学で勉強しており、1年半ほどC++をメインで使用しておりました。
現在は時々使う程度です。
【プログラム】
3Dオブジェクトの描画部分の関数
static void draw(int mid,double patt_trans[3][4])
{
double gl_para[16];
GLfloat mat_ambient1[] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat mat_flash1[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_flash_shiny[] = { 50.0 };
GLfloat light_position[] = { 100.0,-200.0,200.0,0.0 };
GLfloat ambi[] = { 0.1, 0.1, 0.1, 0.1 };
GLfloat lightZeroColor[] = { 0.9 ,0.9,0.9,1.0 };
GLfloat mat_ambient2[] = { 1.0 ,1.0, 1.0, 0.0 };
GLfloat mat_flash2[] = { 1.0, 1.0, 1.0, 0.0 };
GLfloat mat_flash_shiny2[] = { 0.0 };
GLfloat ambi2[] = { 1.0, 1.0, 1.0, 0.0 };
GLfloat lightZeroColor2[] = { 1.0 ,1.0,1.0,0.0 };
/*3Dオブジェクトの描画準備*/
argDrawMode3D();
argDraw3dCamera(0, 0);
// glClearDepth(1.0);
//glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST); //隠面消去・有効
glDepthFunc(GL_LEQUAL); //デプス・テスト
/* 座標変換行列の読み込み */
argConvGlpara(patt_trans, gl_para); //ARToolkit->OpenGL
glMatrixMode(GL_MODELVIEW); //行列変換モード・モデルビュー
glLoadMatrixd(gl_para); //読み込む行列を指定
/*ライティング*/
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambi);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0, 0.0, 25.0);
switch(mid) {
case OBJ1_MARK_ID:
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_flash1);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient1);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny);
glCallList(listid); //モデルの描画
break;
case OBJ2_MARK_ID:
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_flash1);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient1);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny);
glCallList(listid); //モデルの描画
break;
case OBJ3_MARK_ID:
//glMaterialfv(GL_FRONT, GL_SPECULAR, mat_flash2);
//glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient2);
//glLightfv(GL_LIGHT0, GL_AMBIENT,ambi2);
//glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor2);
//glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny2);
glColor4f(1.0, 1.0, 1.0, 0.5);
glTranslatef(0.0,0.0,-120.0);
glutSolidCube(120.0); // 100.0[mm]の立方体を描画
}
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
}
プログラム全体
#ifdef _WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <io.h> //テクスチャ
#include <fcntl.h> //stl用に追加
#include <math.h> //stl用に追加
#ifndef __APPLE__
#include <GL/gl.h>
#include <GL/glut.h>
#else
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#endif
#include <AR/gsub.h>
#include <AR/video.h>
#include <AR/param.h>
#include <AR/ar.h>
/*パターンファイル マーカーの数を2つにする*/
#define OBJ_NUM 3 //使用するマーカーの個数
//-----
#define OBJ1_MARK_ID 1 // マーカーID
#define OBJ1_PATT_NAME "Data/patt.hiro" // パターンファイル名
#define OBJ1_SIZE 80.0 //バターンの幅(80mm)
//-----
#define OBJ2_MARK_ID 2 // マーカーID
#define OBJ2_PATT_NAME "Data/patt.Kanji" // パターンファイル名
#define OBJ2_SIZE 80.0 //バターンの幅(80mm)
//-----
#define OBJ3_MARK_ID 3 // マーカーID
#define OBJ3_PATT_NAME "Data/patt.sample1" // パターンファイル名
#define OBJ3_SIZE 80.0 //バターンの幅(80mm)
typedef struct {
char* patt_name; //パターンファイル名
int patt_id; //パターンID
int mark_id; //マーカーID
int visible; //検出フラグ
double width; //パターンの幅(mm単位)
double center[3]; //パターンの中心座標
double trans[3][4]; //座標変換行列
}OBJECT_T;
//-----
OBJECT_T object[OBJ_NUM] = {
{OBJ1_PATT_NAME, -1, OBJ1_MARK_ID, 0, OBJ1_SIZE, {0.0, 0.0} },
{OBJ2_PATT_NAME, -1, OBJ2_MARK_ID, 0, OBJ2_SIZE, {0.0, 0.0} },
{OBJ3_PATT_NAME, -1, OBJ3_MARK_ID, 0, OBJ3_SIZE, {0.0, 0.0} }
};
//
// Camera configuration.
//
#ifdef _WIN32
char* vconf = "Data\\WDM_camera_flipV.xml";
#else
char* vconf = "";
#endif
#pragma warning(disable : 4996) //fopen エラーを受け付けない
int xsize, ysize;
int thresh = 100;
int count = 0;
char* cparam_name = "Data/my_camera_para_kotei.dat"; //後でmy_camera_para.datに変更する
ARParam cparam;
//char* patt_name = "Data/patt.hiro";
//int patt_id;
//double patt_width = 80.0;
//double patt_center[2] = { 0.0, 0.0 };
//double patt_trans[3][4];
/* 3次元データ */
GLuint listid;// ディスプレイ・リストのID
char* filename = "3D/Sheep.stl";// STLファイル
static GLfloat exDt[1000000][3];// 頂点の座標
static int exNo[1000000][3];// 面を構成する頂点
static GLfloat exVec[1000000][3];// 法線ベクトル
static void init(void);
static void cleanup(void);
static void keyEvent(unsigned char key, int x, int y);
static void mainLoop(void);
static void draw(int mid,double patt_trans[3][4]);
static void readStlData(void);
int main(int argc, char** argv)
{
/* GLUTの初期化 */
glutInit(&argc, argv);
/*ARアプリケーションの初期化*/
init();
/* STLデータの読み込み */
readStlData();
arVideoCapStart();
argMainLoop(NULL, keyEvent, mainLoop);
return (0);
}
static void keyEvent(unsigned char key, int x, int y)
{
/* quit if the ESC key is pressed */
if (key == 0x1b) {
printf("*** %f (frame/sec)\n", (double)count / arUtilTimer());
cleanup();
exit(0);
}
}
/* main loop */
static void mainLoop(void)
{
ARUint8* dataPtr;
ARMarkerInfo* marker_info;
int marker_num;
int i, j, k;
/* カメラ画像の取得 */
if ((dataPtr = (ARUint8*)arVideoGetImage()) == NULL) {
arUtilSleep(2);
return;
}
if (count == 0) arUtilTimerReset();
count++;
/*キャプチャした画像の表示*/
argDrawMode2D();
argDispImage(dataPtr, 0, 0);
/* マーカーの検出 */
if (arDetectMarker(dataPtr, thresh, &marker_info, &marker_num) < 0) {
cleanup();
exit(0);
}
/*次の画像をキャプチャ*/
arVideoCapNext();
/*デプス・バッファの初期化*/
glClearDepth(1.0); //デプス・バッファの消去値
glClear(GL_DEPTH_BUFFER_BIT); //デプス・バッファの初期化
/* マーカーの一致度を判定 */
for (i = 0; i < OBJ_NUM; i++) {
k = -1;
for (j = 0; j < marker_num; j++) {
if (object[i].patt_id == marker_info[j].id) {
if (k == -1) k = j;
else if (marker_info[k].cf < marker_info[j].cf) k = j;
}
}
//マーカーが見つからなかったとき
if (k == -1) {
object[i].visible = 0;
continue;
}
/* 座標変換行列を取得 */
else {
arGetTransMat(&marker_info[k], object[i].center, object[i].width, object[i].trans);
object[i].visible = 1;
}
draw(object[i].mark_id,object[i].trans);
}
argSwapBuffers();
}
static void init(void)
{
ARParam wparam;
int i; //ループカウンタ
/* ビデオデバイスの設定 */
if (arVideoOpen(vconf) < 0) exit(0);
/* ウィンドウサイズの取得 */
if (arVideoInqSize(&xsize, &ysize) < 0) exit(0);
printf("Image size (x,y) = (%d,%d)\n", xsize, ysize);
/* カメラパラメーターの読み込み */
if (arParamLoad(cparam_name, 1, &wparam) < 0) {
printf("Camera parameter load error !!\n");
exit(0);
}
/*カメラパラメーターの初期化*/
arParamChangeSize(&wparam, xsize, ysize, &cparam);
arInitCparam(&cparam);
printf("*** Camera Parameter ***\n");
arParamDisp(&cparam);
/*パターンファイルの読み込み*/
for (i = 0; i < OBJ_NUM; i++) {
if ((object[i].patt_id = arLoadPatt(object[i].patt_name)) < 0) {
printf("pattern load error !!\n", object[i].patt_name);
exit(0);
}
}
/* gsubライブラリの初期化 */
argInit(&cparam, 1.0, 0, 0, 0, 0);
}
/* cleanup function called when program exits */
static void cleanup(void)
{
arVideoCapStop();
arVideoClose();
argCleanup();
}
static void draw(int mid,double patt_trans[3][4])
{
double gl_para[16];
GLfloat mat_ambient1[] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat mat_flash1[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_flash_shiny[] = { 50.0 };
GLfloat light_position[] = { 100.0,-200.0,200.0,0.0 };
GLfloat ambi[] = { 0.1, 0.1, 0.1, 0.1 };
GLfloat lightZeroColor[] = { 0.9 ,0.9,0.9,1.0 };
GLfloat mat_ambient2[] = { 1.0 ,1.0, 1.0, 0.0 };
GLfloat mat_flash2[] = { 1.0, 1.0, 1.0, 0.0 };
GLfloat mat_flash_shiny2[] = { 0.0 };
GLfloat ambi2[] = { 1.0, 1.0, 1.0, 0.0 };
GLfloat lightZeroColor2[] = { 1.0 ,1.0,1.0,0.0 };
/*3Dオブジェクトの描画準備*/
argDrawMode3D();
argDraw3dCamera(0, 0);
// glClearDepth(1.0);
//glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST); //隠面消去・有効
glDepthFunc(GL_LEQUAL); //デプス・テスト
/* 座標変換行列の読み込み */
argConvGlpara(patt_trans, gl_para); //ARToolkit->OpenGL
glMatrixMode(GL_MODELVIEW); //行列変換モード・モデルビュー
glLoadMatrixd(gl_para); //読み込む行列を指定
/*ライティング*/
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambi);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0, 0.0, 25.0);
switch(mid) {
case OBJ1_MARK_ID:
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_flash1);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient1);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny);
glCallList(listid); //モデルの描画
break;
case OBJ2_MARK_ID:
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_flash1);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient1);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny);
glCallList(listid); //モデルの描画
break;
case OBJ3_MARK_ID:
//glMaterialfv(GL_FRONT, GL_SPECULAR, mat_flash2);
//glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient2);
//glLightfv(GL_LIGHT0, GL_AMBIENT,ambi2);
//glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor2);
//glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny2);
glColor4f(1.0, 1.0, 1.0, 0.5);
glTranslatef(0.0,0.0,-120.0);
glutSolidCube(120.0); // 100.0[mm]の立方体を描画
}
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
}
// STLデータの読み込み
static void readStlData(void)
{
FILE* handle; //ファイル ハンドル
char buf[256]; //ファイルから読み込んだデータ
int v; //頂点の数
int f; //面の数
long p1, p2, p3; //面を構成する頂点
int L; //ファセットの個数
WORD m; //空白データ
float x1, y1, z1; //頂点1
float x2, y2, z2; //頂点2
float x3, y3, z3; //頂点3
float vx, vy, vz; //法線ベクトル
float cx, cy, cz; //オブジェクトの中心
float len; //原点から頂点までの空間距離
float maxlen; //空間距離の最大値
GLfloat scale = 100.0;//1単位の長さ(mm单位)
GLfloat zmin; //z軸方向の最小値
int i; //ループカウンタ
/*--STLファイルの読み込みーー*/
handle = fopen(filename, "rb");
//ファイルヘッダーの読み込み
if ((fread(buf, sizeof(char), 80, handle) == -1)) {
fclose(handle);
return;
}
//ファセットの個数を取得
if ((fread(&L, sizeof(int), 1, handle) == -1)) {
fclose(handle);
return;
}
//ファセットの読み込み
v = 0;
f = 0;
for (i = 0; i < L; i++) {
if (v >= 100000) break;
//法線ベクトル
fread(&vx, sizeof(float), 1, handle);
fread(&vy, sizeof(float), 1, handle);
fread(&vz, sizeof(float), 1, handle);
//頂点1
fread(&x1, sizeof(float), 1, handle);
fread(&y1, sizeof(float), 1, handle);
fread(&z1, sizeof(float), 1, handle);
//頂点2
fread(&x2, sizeof(float), 1, handle);
fread(&y2, sizeof(float), 1, handle);
fread(&z2, sizeof(float), 1, handle);
//頂点3
fread(&x3, sizeof(float), 1, handle);
fread(&y3, sizeof(float), 1, handle);
fread(&z3, sizeof(float), 1, handle);
//空白データ
fread(&m, sizeof(WORD), 1, handle);
//配列に入れる
exDt[v][0] = x1; //頂点1 x
exDt[v][1] = y1; // y
exDt[v][2] = z1; // z
v++;
exDt[v][0] = x2; //頂点2 x
exDt[v][1] = y2; // y
exDt[v][2] = z2; // z
v++;
exDt[v][0] = x3; //頂点3 x
exDt[v][1] = y3; // y
exDt[v][2] = z3; // z
v++;
exNo[i][0] = v - 3; //面を構成する頂点x
exNo[i][1] = v - 2; //面を構成する頂点y
exNo[i][2] = v - 1; //面を構成する頂点z
exVec[i][0] = vx; // 法線ベクトルx
exVec[i][1] = vy; // 法線ベクトルy
exVec[i][2] = vz; // 法線ベクトルz
f++;
}
fclose(handle);
//頂点の数が足りないとき
if (v < 3) return;
/*--オブジェクトの中心を調整--*/
//座標の平均を求める
cx = 0.0;
cy = 0.0;
cz = 0.0;
for (i = 0; i < v; i++) {
cx = cx + exDt[i][0];
cy = cy + exDt[i][1];
cz = cz + exDt[i][2];
}
cx = cx / v;
cy = cy / v;
cz = cz / v;
//オブジェクトの中心を原点に移動
for (i = 0; i < v; i++) {
exDt[i][0] = exDt[i][0] - cx;
exDt[i][1] = exDt[i][1] - cy;
exDt[i][2] = exDt[i][2] - cz;
}
/*--オブジェクトの大きさを調整--*/
//空間距離の最大値を求める
maxlen = 0.0;
for (i = 0; i < v; i++) {
len = sqrt(exDt[i][0] * exDt[i][0] +
exDt[i][1] * exDt[i][1] +
exDt[i][2] * exDt[i][2]);
if (len > maxlen) maxlen = len;
}
//オブジェクトを指定したサイズに変更
zmin = 100000.0;
for (i = 0; i < v; i++) {
exDt[i][0] = (exDt[i][0] / maxlen) * scale;
exDt[i][1] = (exDt[i][1] / maxlen) * scale;
exDt[i][2] = (exDt[i][2] / maxlen) * scale;
if (exDt[i][2] < zmin) zmin = exDt[i][2];
}
/*-- ディスプレイ・リストの作成--*/
listid = glGenLists(1);
glNewList(listid, GL_COMPILE);
//z軸方向の移動
glTranslatef(0.0, 0.0, -zmin);
for (i = 0; i < f; i++) {
//面を構成する頂点の取得
p1 = exNo[i][0];
p2 = exNo[i][1];
p3 = exNo[i][2];
//多角形の描画
glBegin(GL_POLYGON);
glNormal3f(exVec[i][0], exVec[i][1], exVec[i][2]);
glVertex3f(exDt[p1][0], exDt[p1][1], exDt[p1][2]);
glVertex3f(exDt[p2][0], exDt[p2][1], exDt[p2][2]);
glVertex3f(exDt[p3][0], exDt[p3][1], exDt[p3][2]);
glEnd();
}
glEndList();
}