簡易輪郭線描画

普通に描画したモデルの後に少し大きくしたモデルの裏面を黒で描画すると
輪郭線の様に見えます。

ファイル
main.cpp

main.cpp

#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")

#include <math.h>
#include <GL/freeglut/freeglut.h>

#define PAI 3.14159

//光源
float lightPos[] =  {10.0, 15.0, 10.0, 1.0};//光源位置

//カメラと視体積
struct View{
  //カメラ
    float pos[3];//位置(視点)
    float cnt[3];//注視点
  float dist;  //注視点から視点までの距離
  float theta; //仰角(水平面との偏角)
  float phi;   //方位角
  //視体積
  float fovY;  //視野角
  float nearZ; //前方クリップ面(近平面)
  float farZ;  //後方クリップ面(遠平面)
};
View view = { 
    0.0, 0.0, 0.0,//pos(仮設定)
  0.0, 1.0, 0.0,//cnt 
    10.0, 30.0, 20.0,//dist, theta, phi
    30.0, 1.0, 100.0//fovY,nearZ, farZ
};
View view0 = view;

//Windowのサイズ
int width = 320;
int height = 240;
//アフィン変換
enum SELECT_KEY {ROTATE, SCALE, TRANSLATE, LIGHT};
SELECT_KEY sKey = TRANSLATE;
//マウス操作
int xStart, yStart;
bool flagMouse = false;
float Line_Size = 0.1f;

//緑
GLfloat green[] = { 0.0, 1.0, 0.0, 1.0 };
//黒
GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 };

void setLight(){
  float lightAmbient0[] = {0.5, 0.5, 0.5, 1.0}; //環境光
  float lightDiffuse0[] = {1.0, 1.0, 1.0, 1.0}; //拡散光
  float lightSpecular0[] = {1.0, 1.0, 1.0, 1.0};//鏡面光
  glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient0);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse0);
  glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular0);
  glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

  glEnable(GL_LIGHT0);
  glEnable(GL_LIGHTING);
}

void resize(int w, int h){
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(view.fovY, (double)w/(double)h, view.nearZ, view.farZ);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  width = w;
  height = h;
}

void setCamera(){
  double pp = PAI / 180.0;
  view.pos[2] = view.cnt[2] + view.dist * cos(pp * view.theta) * cos(pp * view.phi);//z
  view.pos[0] = view.cnt[0] + view.dist * cos(pp * view.theta) * sin(pp * view.phi);//x
  view.pos[1] = view.cnt[1] + view.dist * sin(pp * view.theta);//y
  resize(width, height);
}

void idle(void){
  glutPostRedisplay();
}

void init(void){
  glClearColor(1.0, 1.0, 1.0, 1.0);
  setCamera();
  setLight();
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  glEnable(GL_CULL_FACE);
  glCullFace(GL_FRONT);
}

void display(void){

  //カラーバッファ,デプスバッファのクリア
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();
 
  if(cos(PAI * view.theta /180.0) >= 0.0)//カメラ仰角90度でビューアップベクトル切替
      gluLookAt(view.pos[0], view.pos[1], view.pos[2], view.cnt[0], view.cnt[1], view.cnt[2], 0.0, 1.0, 0.0);
  else
      gluLookAt(view.pos[0], view.pos[1], view.pos[2], view.cnt[0], view.cnt[1], view.cnt[2], 0.0, -1.0, 0.0);
  //光源設定//'l'を押した後光源位置可変
  glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

  glEnable(GL_TEXTURE_2D);
  glCullFace(GL_BACK);
  //マテリアルの設定
  glMaterialfv(GL_FRONT, GL_DIFFUSE, green);
  glutSolidTorus(1.0,1.5,16,16);
  glDisable(GL_TEXTURE_2D);

  glCullFace(GL_FRONT);
  glMaterialfv(GL_FRONT, GL_DIFFUSE, black);
  glutSolidTorus(1.0+Line_Size,1.5,16,16);

  //終了
  glutSwapBuffers();
}

 

//以下の3個の関数はマウス操作による視点の変更に必要
void mouse(int button, int state, int x, int y){
  double pp = PAI / 180.0;

  if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
      xStart = x; yStart = y;
      flagMouse = true;
      if(x > width/4 && x < 3*width/4 && y > height/4 && y < 3*height/4)//dolly
      {
      }
  }else if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){
      if(x > width/4 && x < 3*width/4 && y > height/4 && y < 3*height/4)//dolly
      {
      }else if(( x < width/4 || x > 3*width/4) && (y > height/4 && y < 3*height/4)){
          if(x < width/4 ) view.phi -= 1.0;
          else view.phi += 1.0;
          view.cnt[2] = view.pos[2] - view.dist * cos(pp * view.phi) * cos(pp * view.theta);
          view.cnt[0] = view.pos[0] - view.dist * sin(pp * view.phi) * cos(pp * view.theta);
      }else if((x > width/4 && x < 3*width/4) && (y < height/4 || y > 3*height/4)){
          if( y < height/4)
              view.theta += 1.0; 
          else
              view.theta -= 1.0;

          view.cnt[2] = view.pos[2] - view.dist * cos(pp * view.theta) * cos(pp * view.phi);
          view.cnt[0] = view.pos[0] - view.dist * cos(pp * view.theta) * sin(pp * view.phi);
          view.cnt[1] = view.pos[1] - view.dist * sin(pp * view.theta);
      }
      else if(x < width/8 && y > 7*height/8) view.fovY -= 1.0;//zoom in
      else if(x > 7*width/8 && y > 7*height/8) view.fovY += 1.0;//zoom out
  }
  else flagMouse = false;
  if(state == GLUT_DOWN) setCamera();
}

void motion(int x, int y){
  if(!flagMouse) return;
  if(cos(PAI * view.theta /180.0) >= 0.0)
    view.phi -= 0.5 * (float)(x - xStart) ;//tumble
  else
    view.phi += 0.5 * (float)(x - xStart) ;//tumble

  view.theta += 0.5 * (float)(y - yStart) ;//crane

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

void main(int argc, char** argv){
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
  glutInitWindowSize(width, height);
  glutInitWindowPosition(100, 100);
  glutCreateWindow("簡易輪郭線描画");
  glutReshapeFunc(resize);
  glutDisplayFunc(display);
  glutMouseFunc(mouse);
  glutMotionFunc(motion);
  glutIdleFunc(idle);
  init();
  glutMainLoop();
}

 

最終更新:2015年05月24日 16:13
添付ファイル