GLSL:テクスチャマッピング

GLSLでテクスチャを描画します。

vertex.shader

  //フラグメントシェーダーに渡す変数
  varying vec3 P;//位置ベクトル
  varying vec3 N;//法線ベクトル
 
 void main(void)
  {
    P = vec3(gl_ModelViewMatrix * gl_Vertex);
    N = normalize(gl_NormalMatrix * gl_Normal).xyz;
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = ftransform();
  }

flagment.shader

  //頂点シェーダーから受け取る変数
  varying vec3 P;//位置ベクトル
  varying vec3 N;//法線ベクトル
  uniform sampler2D sampler;
 
 void main(void)
  {
   vec3 L = normalize(gl_LightSource[0].position.xyz - P);//光源ベクトル
   N = normalize(N);
 
   vec4 ambient = gl_FrontLightProduct[0].ambient;
   float dotNL = dot(N, L);//max(0.0, dot(N, L));
   vec4 diffuse = gl_FrontLightProduct[0].diffuse * max(0.0, dotNL);
   vec3 V = normalize(-P);
   vec3 H = normalize(L + V);
   float powNH = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
   if(dotNL <= 0.0) powNH = 0.0;
   vec4 specular = gl_FrontLightProduct[0].specular * powNH;
   //テクスチャの色
   vec4 texColor = texture2D(sampler, gl_TexCoord[0].st);
   //GL_MODULATEモード
   gl_FragColor = (ambient + diffuse) * texColor + specular;
   }

GLSL.h

#pragma once
 #include <stdio.h>
 
//GLSLクラス
 class GLSL{
 public:
  GLuint ShaderProg;
  GLuint VertexShader, FragmentShader;
  void ReadShaderCompile(GLuint Shader, const char *File);//shader fileを読み込みコンパイルする
  void Link( GLuint Prog );//リンクする
  void InitGLSL(const char *VertexFile);//GLSLの初期化
  void InitGLSL(const char *VertexFile, const char *FragmentFile);//GLSLの初期化
  void ON();//シェーダー描画に切り替え
  void OFF();//シェーダー解除
  ~GLSL();
 };
 
 void GLSL::ReadShaderCompile(GLuint Shader, const char *File){
    FILE *fp;
    char *buf;
    GLsizei size, len;
    GLint compiled;
 
    fopen_s(&fp,File, "rb");
    if(!fp) printf("ファイルを開くことができません %s\n", File);
 
    fseek(fp, 0, SEEK_END);
    size = ftell(fp);
 
   buf = (GLchar *)malloc(size);
    if (buf == NULL) {
      printf("メモリが確保できませんでした \n");
    }
 
    fseek(fp, 0, SEEK_SET);
    fread(buf, 1, size, fp);
    glShaderSource(Shader, 1, (const GLchar **)&buf, &size);
    free(buf);
    fclose(fp);
 
    glCompileShader(Shader);
    glGetShaderiv( Shader, GL_COMPILE_STATUS, &compiled );
 
   if ( compiled == GL_FALSE )
    {
     printf( "コンパイルできませんでした!!: %s \n ", File);
     glGetProgramiv( Shader, GL_INFO_LOG_LENGTH, &size );
     if ( size > 0 )
     {
      buf = (char *)malloc(size);
      glGetShaderInfoLog( Shader, size, &len, buf);
      printf(buf);
      free(buf);
     }
    }
  }
 
 void GLSL::Link( GLuint Prog ){
    GLsizei size, len;
    GLint linked;
    char *infoLog ;
 
   glLinkProgram( Prog );
 
   glGetProgramiv( Prog, GL_LINK_STATUS, &linked );
 
   if ( linked == GL_FALSE ){
    printf("リンクできませんでした!! \n");
    
    glGetProgramiv( Prog, GL_INFO_LOG_LENGTH, &size );
    if ( size > 0 ){
     infoLog = (char *)malloc(size);
     glGetProgramInfoLog( Prog, size, &len, infoLog );
     printf(infoLog);
     free(infoLog);
    }
   }
 }
 
void GLSL::InitGLSL(const char *VertexFile){
    GLenum err = glewInit();
    if (err != GLEW_OK)
    {
     printf("Error: %s\n", glewGetErrorString(err));
    }
    printf("VENDOR= %s \n", glGetString(GL_VENDOR));
    printf("GPU= %s \n", glGetString(GL_RENDERER));
    printf("OpenGL= %s \n", glGetString(GL_VERSION));
    printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));
    VertexShader = glCreateShader(GL_VERTEX_SHADER);
    ReadShaderCompile(VertexShader, VertexFile);
    ShaderProg = glCreateProgram();
    glAttachShader(ShaderProg, VertexShader);
    glDeleteShader(VertexShader);
    Link(ShaderProg);
  }
 
 
void GLSL::InitGLSL(const char *VertexFile, const char *FragmentFile){
    GLenum err = glewInit();
    if (err != GLEW_OK)
    {
     printf("Error: %s\n", glewGetErrorString(err));
    }
    printf("VENDOR= %s \n", glGetString(GL_VENDOR));
    printf("GPU= %s \n", glGetString(GL_RENDERER));
    printf("OpenGL= %s \n", glGetString(GL_VERSION));
    printf("GLSL= %s \n", glGetString(GL_SHADING_LANGUAGE_VERSION));
 
   VertexShader = glCreateShader(GL_VERTEX_SHADER);
    FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 
   ReadShaderCompile(VertexShader, VertexFile);
    ReadShaderCompile(FragmentShader, FragmentFile);
 
   ShaderProg = glCreateProgram();
 
    glAttachShader(ShaderProg, VertexShader);
    glAttachShader(ShaderProg, FragmentShader);
 
    glDeleteShader(VertexShader);
    glDeleteShader(FragmentShader);
    Link(ShaderProg);
  }
 
void GLSL::ON(){
  glUseProgram(ShaderProg);
 }
 
void GLSL::OFF(){
  glUseProgram(0);
 }
 
GLSL::~GLSL(){
  glDeleteProgram(ShaderProg);
 }
 

PNG.h

 #pragma once
 #include "lodepng.h"
 
//テクスチャクラス
 class TEXTURE{
 protected:
  LodePNG_Decoder decoder;//デコーダ
  unsigned char* buffer;//バッファ
  size_t buffersize, imagesize;//サイズ
 public:
  TEXTURE();
  TEXTURE(const char* FileName);//コンストラクタ
  void LOAD_PNG(const char* FileName);//PNG読み込み
  unsigned char* image;//イメージポインタ
  unsigned int Width,Height;//画像サイズ
 };
 TEXTURE::TEXTURE(){
 }
 TEXTURE::TEXTURE(const char* FileName){
  LOAD_PNG(FileName);
 }
 void TEXTURE::LOAD_PNG(const char* FileName){
  LodePNG_Decoder_init(&decoder);
  //ロード
  LodePNG_loadFile(&buffer, &buffersize, FileName);
  //デコード
  LodePNG_decode(&decoder, &image, &imagesize, buffer, buffersize);
  //幅,高さ
  Width = decoder.infoPng.width;Height = decoder.infoPng.height;
 }

main.cpp

#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
#pragma comment(lib, "glew32.lib")
 
#include <GL/glew.h>
#include <GL/freeglut/freeglut.h>
#include "GLSL.h"
#include <math.h>
#include "PNG.h"
 
#define PAI 3.141592f
 
#define WIDTH 640
#define HEIGHT 480
 
GLSL glsl;
 
//回転用
float anglex = 0.0f;
//ライトの位置
GLfloat lightpos[] = { 10.0f, 15.0f, 0.0f, 1.0f };
 
float Ambient[] = {1.0f, 1.0f, 1.0f, 1.0f};
float Diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
float Specular[]= { 0.4f, 0.4f, 0.4f, 1.0f};//鏡面反射
 
float AmbientLight[] = { 0.5f, 0.5f, 0.5f, 1.0f};
float DiffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f};
float SpecularLight[] = {1.0f, 1.0f, 1.0f, 1.0f};//鏡面光
 
float lightDiffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; //拡散光
float lightSpecular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; //鏡面光
float pos[] = {0.0f, 2.0f, 0.0f};//位置
bool flag = true;
 
//影のマテリアル
float shadowDiffuse[] =  {0.0f,0.0f,0.0f,0.3f};//影の拡散光
float shadowSpecular[] = {0.0f,0.0f,0.0f,1.0f};//影の鏡面光
GLuint texID;
TEXTURE *texture;

void drawTexPlate(float size, int nRepeatS, int nRepeatT){//x-y平面
 float sz = 0.5f * size;
 static float p[4][3] = {//z:上方向
  { sz,-sz, 0.0}, { sz, sz, 0.0},
  {-sz, sz, 0.0}, {-sz,-sz, 0.0}
 };
 float s = (float)nRepeatS;
 float t = (float)nRepeatT;
 glEnable(GL_TEXTURE_2D);
 glBegin(GL_QUADS);
 glNormal3f(0.0, 0.0, 1.0); //z方向の法線
 //テクスチャー座標と頂点番号との対応付け
 glTexCoord2f(0.0, 0.0); glVertex3fv(p[3]);
 glTexCoord2f( s , 0.0); glVertex3fv(p[0]);
 glTexCoord2f( s ,  t ); glVertex3fv(p[1]);
 glTexCoord2f(0.0,  t ); glVertex3fv(p[2]);
 glEnd();
 glDisable(GL_TEXTURE_2D);
}

void draw(bool flag){
 if(flag){
   glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,shadowDiffuse);
   glMaterialfv(GL_FRONT,GL_SPECULAR,shadowSpecular);
  }else{ 
   glMaterialfv(GL_FRONT,GL_AMBIENT,Ambient);
   glMaterialfv(GL_FRONT,GL_DIFFUSE,Diffuse);
   glMaterialfv(GL_FRONT,GL_SPECULAR,Specular);
   glMaterialf(GL_FRONT,GL_SHININESS,100);
  }
  glPushMatrix();
  glTranslatef(pos[0], pos[1], pos[2]);
  glRotatef( anglex, 1.0f, 0.0f, 0.0f);//x軸回転
  //オブジェクト形状
  if(!flag){
   drawTexPlate(2.0f,1,1);
  }else{
   drawTexPlate(2.0f,1,1);
  }
  glPopMatrix();
 }
 
void drawFloor(float widthX, float widthZ, int nx, int nz){
   int i, j;
   //Floor1枚当たりの幅
   float wX = widthX / (float)nx;
   float wZ = widthZ / (float)nz;
 
  float diffuse[][4] = {
  { 0.9f, 0.9f, 0.9f, 1.0f}, { 0.1f, 0.1f, 0.1f, 1.0f} };
   float ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f};
   float specular[]= { 0.5f, 0.5f, 0.5f, 1.0f};
 
  glMaterialfv(GL_FRONT,GL_AMBIENT,ambient);
   glMaterialfv(GL_FRONT,GL_SPECULAR,specular);
   glMaterialf(GL_FRONT,GL_SHININESS,100);
 
  glNormal3d(0.0, 1.0, 0.0);
   glPushMatrix();
   for (j = 0; j < nz; j++) {
     float z1 = -widthZ / 2.0f + wZ * j; float z2 = z1 + wZ;
     for (i = 0; i < nx; i++) {
       float x1 = -widthX / 2.0f + wX * i; float x2 = x1 + wX;
 
      glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse[(i + j) & 1]);
    glBegin(GL_QUADS);
       glVertex3d(x1, 0.0, z1);
       glVertex3d(x1, 0.0, z2);
       glVertex3d(x2, 0.0, z2);
       glVertex3d(x2, 0.0, z1);
    glEnd();
     }
   }
   glPopMatrix();
 }

void CalcShadowMat(float* mat){
  float ex, ey, ez;//光源の方向
  float s; //object中心から光源までの距離
  float x, y, z;
  x = lightpos[0] - pos[0];
  y = lightpos[1] - pos[1];
  z = lightpos[2] - pos[2];
  //光源の方向ベクトル
  s = sqrt(x * x + y * y + z * z);
  ex = x / s;
  ey = y / s;
  ez = z / s;
  //shadow matrix
  mat[0] = ey;
  mat[1] = 0.0f;
  mat[2] = 0.0f;
  mat[3] = 0.0f;
  mat[4] = -ex;
  mat[5] = 0.0f;
  mat[6] = -ez;
  mat[7] = 0.0f;
  mat[8] = 0.0f;
  mat[9] = 0.0f;
  mat[10] = ey;
  mat[11] = 0.0f;
  mat[12] = 0.0f;
  mat[13] = 0.001f * ey;
  mat[14] = 0.0f;
  mat[15] = ey;
 }
 
void drawShadow(){
  float mat[16];
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  glDepthMask(GL_FALSE);
  CalcShadowMat( mat);
  glPushMatrix();
  glMultMatrixf(mat);
  draw(true);
  glPopMatrix();
  glDepthMask(GL_TRUE);
  glDisable(GL_BLEND);
 }
 
void setLight(){
  glLightfv(GL_LIGHT0, GL_AMBIENT, AmbientLight);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseLight);
  glLightfv(GL_LIGHT0, GL_SPECULAR, SpecularLight);
  glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  glEnable(GL_LIGHT0);
  glEnable(GL_LIGHTING);
 }

 void display(void){
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glViewport(0, 0, WIDTH, HEIGHT);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  //視野角,アスペクト比(ウィンドウの幅/高さ),描画する範囲(最も近い距離,最も遠い距離)
  gluPerspective(30.0, (double)WIDTH / (double)HEIGHT, 1.0, 1000.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  //視点の設定
  gluLookAt(0.0,10.0,-10.0, //カメラの座標
        0.0,0.0,0.0, // 注視点の座標
       0.0,1.0,0.0); // 画面の上方向を指すベクトル
  //ライトの設定
  setLight();
  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_2D, texID);
  glsl.ON();
  GLint samplerLoc = glGetUniformLocation(glsl.ShaderProg, "sampler");
  glUniform1i(samplerLoc, 1);//GL_TEXTURE1を適用
  draw(false);
  glsl.OFF();
  drawFloor(10.0, 10.0, 10, 10);
  drawShadow();
  glutSwapBuffers();
 }

 void idle(void){
  glutPostRedisplay();
 }

 void Init(){
  glsl.InitGLSL("vertex.shader","flagment.shader");
  glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_NORMALIZE);
  //テクスチャー
  glGenTextures(1, &texID);//テクスチャオブジェクトの名前付け
  texture = new TEXTURE("tip.png");

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  //テクスチャオブジェクトの作成
  glBindTexture(GL_TEXTURE_2D, texID);
  //テクスチャの指定
  glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,texture->Width,texture->Height,0,GL_RGBA,GL_UNSIGNED_BYTE,texture->image);
  //テクスチャの繰り返し方法の指定
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);//GL_CLAMP);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);//GL_CLAMP);
  //テクスチャを拡大・縮小する方法の指定
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//NEAREST);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//NEAREST);
  glBindTexture(GL_TEXTURE_2D, 0);
 }

 //タイマー
 void timer(int value){
  anglex+=1.0f;
  glutTimerFunc(100 , timer , 0);
 }

 void main(int argc, char *argv[]){
   glutInitWindowPosition(100, 100);
   glutInitWindowSize(WIDTH, HEIGHT);
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
   glutCreateWindow("テクスチャ");
   glutDisplayFunc(display);
   glutIdleFunc(idle);
   glutTimerFunc(100 , timer , 0);
   Init();
   glutMainLoop();
   return;
 }

 

 

 

 

 

最終更新:2014年05月01日 18:31
添付ファイル