opengl 漫游

/*
 * This code was writen by zhaojian (ken2006)
 * The motivation of this code is to show how to set up a viewing system in opengl
 * If You've found this code useful or have something to optimize, Please mail to
 * me.  My mail add is : just_for_freedom@163.dom
 * further more ,我将尽可能的注释每行代码,以便你阅读,呵呵,我很好吧!
*/  
#define WIN32_LEAN_AND_MEAN  // 不许加入MFC 的内容
#include <windows.h>  // win32 程序的头文件

//---- 以下为 opengl 头文件,不用多说
#include <gl/gl.h>   
#include <gl/glu.h>  
#include <gl/glaux.h> 
 
#include <math.h>        //用到 cos() and sin()
#include <stdio.h>       //文件打开超作时用到
#include <malloc.h>      //清理内存 free() 用到

//加入opengl 的一些连接库
#pragma comment( lib, "opengl32.lib") 
#pragma comment( lib, "glu32.lib")  
#pragma comment( lib, "glaux.lib") 
// 键盘处理宏
#define KEY_DOWN(vk_code)((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)

HDC   hDC=NULL;  //  全局设备描述表句柄(handle)
HGLRC  hRC=NULL;  //  渲染描述表(Render Context)句柄
HWND  hWnd=NULL;  //  窗口(window) 句柄
HINSTANCE hInstance;  //  应用程序句柄


bool fullscreen = true;     // 全屏标识
GLfloat speed = 1.0f;       //移动速度
int SCREEN_WIDTH =800;       //屏幕的宽高
int SCREEN_HEIGHT =600;
GLuint  texture[1];  // 存储一个纹理
GLfloat MAP_SIZE = 200;      //地图的大小
GLfloat theta = 0.0f;       //旋转的角度
GLfloat viewUp = 0.0f;      //向上和向下看的程度

// 3D向量结构
struct Vector3{
 GLfloat x;
 GLfloat y;
 GLfloat z;
};

Vector3 eyePosition ={0.0f, 4.0, 0.0f};   //视点坐标
Vector3 viewAtPosition ={0.0f, 4.0,-1.0};  // 参考点的坐标

//函数声明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // 消息处理函数
GLvoid DrawScene();                                     //画周围场景
GLvoid SetViewByMouse();                                //通过鼠标控制旋转   

GLvoid ReSizeGL(GLsizei width, GLsizei height)  // 设置opengl窗口
{
 if (height==0)          // 防止除零
 {
  height=1;         
 }

 glViewport(0,0,width,height);      // 设置视口

 glMatrixMode(GL_PROJECTION);      // 设当前变换为投影变换
 glLoadIdentity();         // 当前矩阵初始为单位阵

 // 设置透视投影取景器
 gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,1000.0f);

 glMatrixMode(GL_MODELVIEW);       //  设当前变换为模型变换
 glLoadIdentity();        
}

// 读取纹理文件,并返回 AUX_RGBImageRec *
AUX_RGBImageRec *LoadBMP(char *Filename)    
{
 FILE *File=NULL;         // File 句柄

 //注意一定要判断文件是否存在,因为auxDIBImageLoad() 错误处理能力很差
 if (!Filename)          
 {
  return NULL;         
 }

 File=fopen(Filename,"r");       // 打开文件

 if (File)           // 如果存在
 {
  fclose(File);         // 关闭文件
  return auxDIBImageLoad(Filename);    // 并返回AUX_RGBImageRec指针
 }

 return NULL;          // 失败了,返回NULL
}
//以下为载入纹理
int LoadGLTextures()        
{
 int Status=FALSE;         // 状态标志

 AUX_RGBImageRec *TextureImage[1];     //  用来保存纹理数据
 memset(TextureImage,0,sizeof(void *)*1);            // 数据内容清零

 //载入位图 并判断成功否?
 if (TextureImage[0]=LoadBMP("floor2.bmp"))
 {
  Status=TRUE;         // 成功

  glGenTextures(1, &texture[0]);     // 创建一个纹理

  // 纹理设置
  glBindTexture(GL_TEXTURE_2D, texture[0]);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
 }

 if (TextureImage[0])         // 释放TextureImage 空间
 {
  if (TextureImage[0]->data)       
  {
   free(TextureImage[0]->data);     
  }

  free(TextureImage[0]);       
 }

 return Status;          //返回
}


//opengl 初始化
int InitGL(GLvoid)         
{
 if (!LoadGLTextures())       //载入纹理
 {
  return FALSE;       
 }

 glEnable(GL_TEXTURE_2D);
 glShadeModel(GL_SMOOTH);      
 glClearColor(0.0f, 0.0f, 0.0f, 0.5f);   
 glClearDepth(1.0f);       
 glEnable(GL_DEPTH_TEST);      
 glDepthFunc(GL_LEQUAL);       
 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
// 加入光照
 GLfloat light0Pos[4] = {1.0,1.0,1.0,0.0};
 GLfloat light1Pos[4] = {-1.0f,1.0f,-1.0f,0.0f};

 GLfloat lightAmbient[4] ={0.0,0.5,1.0,1.0};
 glLightfv(GL_LIGHT0,GL_POSITION,light0Pos);
 glLightfv(GL_LIGHT1,GL_POSITION,light1Pos);
 glLightfv(GL_LIGHT0,GL_AMBIENT,lightAmbient);
 glLightfv(GL_LIGHT1,GL_AMBIENT,lightAmbient);
 glEnable(GL_LIGHT0);
 glEnable(GL_LIGHT1);
 glEnable(GL_LIGHTING);
 
 return TRUE;         
}

/核心所在///
GLvoid Camera(){
 SetViewByMouse();        //通过鼠标进行旋转变换
 if (KEY_DOWN(VK_LEFT)||KEY_DOWN('A')) {     // 向左走
     eyePosition.x+=(viewAtPosition.z-eyePosition.z)*speed;
     eyePosition.z+= -(viewAtPosition.x-eyePosition.x)*speed;
 }

 if (KEY_DOWN(VK_RIGHT)||KEY_DOWN('D')){    //向右走
   eyePosition.x-=(viewAtPosition.z-eyePosition.z)*speed;
      eyePosition.z-= -(viewAtPosition.x-eyePosition.x)*speed; 
 }
if(theta>360)       //显然角度不能大于360度
  theta=0.0f;

  if (KEY_DOWN(VK_PRIOR)) viewUp +=0.02f;  //抬头看
  if (KEY_DOWN(VK_NEXT)) viewUp -=0.02f;   //低头看
  if (viewUp> 0.5f) viewUp  = 0.5f;         //不要抬得太高
   if (viewUp<-0.6f) viewUp =-0.6f;         

  if (KEY_DOWN(VK_UP)||KEY_DOWN('W'))        //前进
  {
  eyePosition.x+= (viewAtPosition.x-eyePosition.x)*speed;
  eyePosition.z+= (viewAtPosition.z-eyePosition.z)*speed;
  }

  if(KEY_DOWN(VK_DOWN)||KEY_DOWN('S'))     //后退
  {
   eyePosition.x-=(viewAtPosition.x-eyePosition.x)*speed;
   eyePosition.z-=(viewAtPosition.z-eyePosition.z)*speed;
  }

  if (eyePosition.x<-(MAP_SIZE-10))       //别走出边界了
    eyePosition.x= -(MAP_SIZE-10);
  if (eyePosition.x> (MAP_SIZE-10))
   eyePosition.x=  (MAP_SIZE-10);
  if (eyePosition.z<-(MAP_SIZE-10))
   eyePosition.z= -(MAP_SIZE-10);
  if (eyePosition.z> (MAP_SIZE-10))
    eyePosition.z=  (MAP_SIZE-10);

// 新的参考点的位置
viewAtPosition.x = float(eyePosition.x + cos(theta));     
viewAtPosition.z = float(eyePosition.z + sin(theta));
viewAtPosition.y = eyePosition.y;

gluLookAt( eyePosition.x,eyePosition.y ,eyePosition.z,                     // 视点位置
     viewAtPosition.x, viewAtPosition.y + viewUp, viewAtPosition.z , //参考点位置
    0.0,1.0,0.0);                                                 //向上
  return ;
}

GLvoid SetViewByMouse(){        //通过此函数来通过鼠标控制旋转和上下观察
 POINT mousePos;              //鼠标位置
 POINT middlePos;             //屏幕中心位置
 middlePos.x =SCREEN_WIDTH/2; // SCREEN_WIDHT 为屏幕宽度,全局变量,可改。
 middlePos.y =SCREEN_HEIGHT/2;  
  
 GetCursorPos(&mousePos);      //得到鼠标当前位置

 if(mousePos.x==middlePos.x&&mousePos.y==middlePos.y)    //如果鼠标没有动,返回。
  return ;
 SetCursorPos(middlePos.x, middlePos.y);                 //如果鼠标动了,则恢复到屏幕中心
       theta += GLfloat(-middlePos.x +mousePos.x)/500;      //旋转改变量
       viewUp +=GLfloat( middlePos.y - mousePos.y)/500;     //上下改变量
    return ;                                             
}


int RenderScene(GLvoid)         //  画图的主函数
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清理屏幕和深度缓冲区
 glLoadIdentity();         //  使当前矩阵为单位矩阵
    Camera();                                          //视点变换函数
    DrawScene();                                        //画环境
 return TRUE;          //返回
}
 
//画场景
GLvoid DrawScene()

 glBegin(GL_QUADS);  //地面 ,加入纹理坐标
    glTexCoord2f(0.0f,0.0f); glVertex3f(-MAP_SIZE, 0.0f, -MAP_SIZE);
 glTexCoord2f(1.0f,0.0f); glVertex3f(MAP_SIZE,  0.0f, -MAP_SIZE);
 glTexCoord2f(1.0f,1.0f); glVertex3f(MAP_SIZE,  0.0f, MAP_SIZE);
 glTexCoord2f(0.0f,1.0f); glVertex3f(-MAP_SIZE, 0.0F, MAP_SIZE);
 glEnd();

//画四根柱子,作为边界(天边)
glPushMatrix() ;        
glTranslatef(MAP_SIZE,59,MAP_SIZE);
//auxSolidSphere(0.2);
auxSolidCylinder(1.0f,60);
glTranslatef(-MAP_SIZE*2,0.0,0.0F);
auxSolidCylinder(1.0f,60);
glTranslatef(0.0f,0.0f,-MAP_SIZE*2);
auxSolidCylinder(1.0,60.0);
glTranslatef(2*MAP_SIZE,0.0f,0.0);
auxSolidCylinder(1.0f,60.0f);
glPopMatrix();
}


BOOL SetPFormat(HDC hDC)//检测安装OpenGL
{ int nPixelFormat;       // 象素点格式
 //hDC=hDC0;
 PIXELFORMATDESCRIPTOR pfd = {
     sizeof(PIXELFORMATDESCRIPTOR),    // pfd结构的大小
     1,                                // 版本号
     PFD_DRAW_TO_WINDOW |              // 支持在窗口中绘图
     PFD_SUPPORT_OPENGL |              // 支持 OpenGL
     PFD_DOUBLEBUFFER,                 // 双缓存模式
     PFD_TYPE_RGBA,                    // RGBA 颜色模式
     16,                               // 24 位颜色深度
     0, 0, 0, 0, 0, 0,                 // 忽略颜色位
     0,                                // 没有非透明度缓存
     0,                                // 忽略移位位
     0,                                // 无累加缓存
     0, 0, 0, 0,                       // 忽略累加位
     16,                               // 32 位深度缓存    
     0,                                // 无模板缓存
     0,                                // 无辅助缓存
     PFD_MAIN_PLANE,                   // 主层
     0,                                // 保留
     0, 0, 0                           // 忽略层,可见性和损毁掩模
 };
 if (!(nPixelFormat = ChoosePixelFormat(hDC, &pfd)))
  { MessageBox(NULL,"没找到合适的显示模式","Error",MB_OK|MB_ICONEXCLAMATION);
       return FALSE;
  }
 SetPixelFormat(hDC,nPixelFormat,&pfd);//设置当前设备的像素点格式
 hRC = wglCreateContext(hDC);          //获取渲染描述句柄
 wglMakeCurrent(hDC, hRC);             //激活渲染描述句柄
 return TRUE;
}

void CleanGL(){
    wglMakeCurrent(hDC, NULL);                       //清除OpenGL
    wglDeleteContext(hRC);                           //清除OpenGL
}


//以下copy自 NEHE TUTORIAL,用来创建窗口
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
// GLuint  PixelFormat;   // Holds The Results After Searching For A Match
 WNDCLASS wc;      // Windows Class Structure
 DWORD  dwExStyle;    // Window Extended Style
 DWORD  dwStyle;    // Window Style
 RECT  WindowRect;    // Grabs Rectangle Upper Left / Lower Right Values
 WindowRect.left=(long)0;   // Set Left Value To 0
 WindowRect.right=(long)width;  // Set Right Value To Requested Width
 WindowRect.top=(long)0;    // Set Top Value To 0
 WindowRect.bottom=(long)height;  // Set Bottom Value To Requested Height

 fullscreen=fullscreenflag;   // Set The Global Fullscreen Flag

 hInstance   = GetModuleHandle(NULL);    // Grab An Instance For Our Window
 wc.style   = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window.
 wc.lpfnWndProc  = (WNDPROC) WndProc;     // WndProc Handles Messages
 wc.cbClsExtra  = 0;         // No Extra Window Data
 wc.cbWndExtra  = 0;         // No Extra Window Data
 wc.hInstance  = hInstance;       // Set The Instance
 wc.hIcon   = LoadIcon(NULL, IDI_WINLOGO);   // Load The Default Icon
 wc.hCursor   = LoadCursor(hInstance,"crosshair");   // Load The Arrow Pointer
 wc.hbrBackground = NULL;         // No Background Required For GL
 wc.lpszMenuName  = NULL;         // We Don't Want A Menu
 wc.lpszClassName = "OpenGL";        // Set The Class Name

 if (!RegisterClass(&wc))         // Attempt To Register The Window Class
 {
  MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;           // Return FALSE
 }
 
 if (fullscreen)            // Attempt Fullscreen Mode?
 {
  DEVMODE dmScreenSettings;        // Device Mode
  memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
  dmScreenSettings.dmSize=sizeof(dmScreenSettings);  // Size Of The Devmode Structure
  dmScreenSettings.dmPelsWidth = width;    // Selected Screen Width
  dmScreenSettings.dmPelsHeight = height;    // Selected Screen Height
  dmScreenSettings.dmBitsPerPel = bits;     // Selected Bits Per Pixel
  dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

  // Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
  if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
  {
   // If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
   if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By/nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
   {
    fullscreen=FALSE;  // Windowed Mode Selected.  Fullscreen = FALSE
   }
   else
   {
    // Pop Up A Message Box Letting User Know The Program Is Closing.
    MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
    return FALSE;         // Return FALSE
   }
  }
 }

 if (fullscreen)            // Are We Still In Fullscreen Mode?
 {
  dwExStyle=WS_EX_APPWINDOW;        // Window Extended Style
  dwStyle=WS_POPUP;          // Windows Style
  ShowCursor(FALSE);          // Hide Mouse Pointer
 }
 else
 {
  dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;   // Window Extended Style
  dwStyle=WS_OVERLAPPEDWINDOW;       // Windows Style
 }

 AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);  // Adjust Window To True Requested Size

 // Create The Window
 if (!(hWnd=CreateWindowEx( dwExStyle,       // Extended Style For The Window
        "OpenGL",       // Class Name
        title,        // Window Title
        dwStyle |       // Defined Window Style
        WS_CLIPSIBLINGS |     // Required Window Style
        WS_CLIPCHILDREN,     // Required Window Style
        0, 0,        // Window Position
        WindowRect.right-WindowRect.left, // Calculate Window Width
        WindowRect.bottom-WindowRect.top, // Calculate Window Height
        NULL,        // No Parent Window
        NULL,        // No Menu
        hInstance,       // Instance
        NULL)))        // Dont Pass Anything To WM_CREATE
 {
  
  MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
  return FALSE;        // Return FALSE
 }

 

 ShowWindow(hWnd,SW_SHOW);      // Show The Window
 SetForegroundWindow(hWnd);      // Slightly Higher Priority
 SetFocus(hWnd);         // Sets Keyboard Focus To The Window
   ShowCursor(true);
 return TRUE;         // Success
}


// 消息处理函数
LRESULT CALLBACK WndProc( HWND hWnd,   //窗口句柄
       UINT Msg,   // 消息
       WPARAM wParam,   // 附加信息1
       LPARAM lParam)   // 附加信息2
{
 switch (Msg)         //检测是何消息
 {
 
  case WM_CREATE:          
                hDC = GetDC(hWnd);                          
    SetPFormat(hDC);
    return 0;

  case WM_CLOSE:       
  {
   PostQuitMessage(0);     
   return 0;        
  }

  case WM_SIZE:        
  {
   ReSizeGL(LOWORD(lParam),HIWORD(lParam)); 
   return 0;        
  }
 }

 
 return DefWindowProc(hWnd,Msg,wParam,lParam);
}


/程序入口
int WINAPI WinMain( HINSTANCE hInstance,   //程序句柄
     HINSTANCE hPrevInstance,  // 上一个程序句柄(已经没用了)
     LPSTR  lpCmdLine,   // 控制行参数
     int   nCmdShow)   //  窗口显示模式
{
  MSG msg;
   
if(MessageBox(NULL,"全屏模式吗?" ,"full screen mode", MB_YESNO)==IDNO)
    fullscreen = false;
if (!CreateGLWindow("viewing system",800,600,32,fullscreen)) //创建窗口
 {
  return 0;      
 }
 
 InitGL();                                                 //初始化opengl
 
 while(true)                     //主循环
 {
  if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // 有消息吗?
  {
   if (msg.message==WM_QUIT)    // 退出消息
         break;
        
    TranslateMessage(&msg);    // Translate The Message
    DispatchMessage(&msg);    // 调用处理函数WndProc()
  }
  if(KEY_DOWN(VK_ESCAPE))                     //如果按ESC则退出程序
   SendMessage(hWnd,WM_CLOSE,0,0);

    RenderScene();     // 进行render
    SwapBuffers(hDC);    // 双缓冲 
 }                                              //结束主循环

 
     CleanGL();                                      //清理OpenGL
 return (msg.wParam);      
}  // 结束程序
/

OpenGL是一个开源的图形库,可以用来创建各种精美的3D图形场景和效果。而OpenGL漫游代码是指利用OpenGL库中的函数来实现对3D场景的漫游或漫步,使得用户能够在3D场景中自由移动和观察。 在OpenGL中,实现漫游效果的关键在于设置相机的位置、朝向和投影方式。首先,我们需要定义相机的位置、观察目标和上方向,并使用OpenGL的函数来设置这些参数。然后,通过OpenGL的变换函数来设置投影方式,如透视投影或正交投影,以及相机的视野角度。接着,我们需要定义键盘或鼠标事件处理函数,用来响应用户输入,控制相机的移动和旋转。最后,我们在渲染循环中使用OpenGL的矩阵和变换函数来更新相机的位置和朝向,并绘制3D场景。 下面是一个简单的OpenGL漫游代码示例: ```c #include <GL/glut.h> float cameraX = 0.0, cameraY = 0.0, cameraZ = 5.0; float targetX = 0.0, targetY = 0.0, targetZ = 0.0; float upX = 0.0, upY = 1.0, upZ = 0.0; void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(cameraX, cameraY, cameraZ, targetX, targetY, targetZ, upX, upY, upZ); // 在这里绘制3D场景 glutSwapBuffers(); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 'w': cameraZ -= 0.1; break; case 's': cameraZ += 0.1; break; // 其他按键控制相机的移动 } glutPostRedisplay(); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(800, 600); glutCreateWindow("OpenGL 漫游示例"); glutDisplayFunc(display); glutKeyboardFunc(keyboard); glEnable(GL_DEPTH_TEST); glutMainLoop(); return 0; } ``` 以上是一个简单的OpenGL漫游代码示例,实现了基本的相机控制和3D场景绘制。希望能帮助你理解如何使用OpenGL库来实现漫游效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值