Director 偶而上來逛逛的過客
註冊時間: 2013-11-04 文章: 13
381.66 果凍幣
|
發表於: 2013-11-29, PM 4:42 星期五 文章主題: GLSL&GLUT 從環境設定開始的基礎教學(04) - 光線模擬 |
|
|
引言回覆: |
※2015/7/5補充:
其實已經過很久了,GLee似乎已經沒再繼續更新,我在寫了這篇教學不久後也改用了GLEW取代Glee,它們的功能及函式名稱其實是幾乎一樣的,安裝方式同其他函式庫
所以只需要將glee.h及glee.lib改為glew.h及glew.lib就好,這是下載的地方,抓Binaries那個http://glew.sourceforge.net/。
lib用 lib\Release\Win32 裡面的。
|
那麼我們今天來談談怎麼做出光線吧
看看這精美的反射光點。
要如何讓3D的場景看起來很有立體感呢?
答案就是加上陰影、光線,來進一步模擬真實世界,如果有唸過還是零分大大的OpenGL入門系列教學,應該就已經會用GL_LIGHT0來設置內建的光線了!
那今天,我們就是要利用Shader以及數學來把光線客製化,是不是很令人興奮呢
引言回覆: |
在開始之前要先提到一個概念,即便是用GL_LIGHT0設置的光線,應該也會有人注意到,實作上一般的設置方法,光線的位置會隨著移動視角而變動。
這是因為用來設置光座標的這行。
代碼: | glLightfv( GL_LIGHT0, GL_POSITION, light_position ); |
這樣設置光源,在一般情況下,光座標會是獨立於modelView之外的。
什麼意思呢?
就是說你的光不會跟著你創造的3D場景旋轉移動,而是與你的視角保持一定相對位置,如果你看過我寫的上上篇(02 - 關於矩陣),那我的意思就是說,這樣子設置的光線不是世界座標。
結果就是,你的光像是你用2D畫在螢幕上的一個圖形,無論你怎麼改變視角,他都是定在那裡
那要怎麼讓光定在一點照物體呢? 你必須一直維持光與物體的相對位置。
作法很簡單,把你的光座標用modelViewMatrix處理過之後,在你每次要畫物體之前重新設置就好。
那我們來回顧一下第二章,希望你已經安裝好glm函式庫了
代碼: | // gluLookAt版本
// 假設這是你的gluLookAt
gluLookAt( 0, 0, 2, 0, 0, 0, 0, 1, 0);
// 用第二章提到的方法
// 利用glm來製作modelViewMatrix
glm::vec3 lsite( 0, 0, 2 );
glm::vec3 lpoint( 0, 0, 0 );
glm::vec3 lnvector( 0, 1, 0 );
glm::mat4 modelViewMatrix = glm::lookAt( lsite, lpoint, lnvector );
// light_position是你預先設定的光座標
// 最尾的1只是用來補齊glm::vec4, 沒特別意思, 放什麼都可以
// 為了讓座標能跟四維矩陣相乘, 我們才需要把光座標補齊成四維向量
// light_p就是補齊後的光座標
// light_wp就是利用modelViewMatrix校正後的光座標
glm::vec4 light_p( light_position.x, light_position.y, light_position.z, 1 );
glm::vec4 light_wp = modelViewMatrix * light_p;
// 為了能夠放進去glLightfv, 轉成float的陣列
GLfloat worldlight_position[3];
worldlight_position[0] = light_wp.x;
worldlight_position[1] = light_wp.y;
worldlight_position[2] = light_wp.z;
// 每次畫圖前都重新設置座標
glLightfv( GL_LIGHT0, GL_POSITION, worldlight_position ); |
突然想到有一點我之前忘了提,學過線性代數的朋友應該會覺得modelViewMatrix * light_p這行很奇怪。
照我第二章給的矩陣樣子,應該是要寫light_p * modelViewMatrix,反過來乘才對,這是因為:
OpenGL裡面的矩陣型態,是我圖中那種矩陣的轉置矩陣><
所以說,因為是轉置矩陣,所以要反過來乘 。
我想表達的是,順序很重要QQ
一定要先矩陣後座標!
最後,假如你用來調整視野的是我上一章貼的camera class,你可以打開cpp看看裡面是怎麼調整modelViewMatrix的。
代碼: | // camera class版本
// 調整的作法都一樣, 只是取Matrix的方法變成這樣
glm::mat4 modelViewMatrix =
glm::rotate( -MainCamera.getPitch(), 1.0f, 0.0f, 0.0f ) *
glm::rotate( -MainCamera.getYaw(), 0.0f, 1.0f, 0.0f ) *
glm::translate( MainCamera.getLocation().x, MainCamera.getLocation().y, MainCamera.getLocation().z ); |
|
那麼,我想前情提要這樣就夠了,來看Code吧!
這篇我們沿用上一章的程式碼,要做出開頭圖片那樣子的反射光點(雖然不太自然 ),要讓光點很自然就要等到介紹normal mapping的時候了。
這次比較麻煩的是在Shader上面寫的數學。
先簡單敘述一下步驟:
Step1: 製作modelViewMatrix,然後即時調整光座標
Step2: 把光座標、顏色傳入Shader
Step3: 調整渲染的材質顏色,做出光線的效果
引言回覆: | Step1
這部分在前情提要應該講得差不多了,就設定一個光座標下去調整吧!
代碼: | vector3 lightPosition;
lightPosition.x = 0;
lightPosition.y = 0;
lightPosition.z = 2;
glm::mat4 modelViewMatrix =
glm::rotate( -MainCamera.getPitch(), 1.0f, 0.0f, 0.0f ) *
glm::rotate( -MainCamera.getYaw(), 0.0f, 1.0f, 0.0f ) *
glm::translate( MainCamera.getLocation().x, MainCamera.getLocation().y, MainCamera.getLocation().z );
glm::vec4 worldLightPosition = modelViewMatrix * glm::vec4( lightPosition.x, lightPosition.y, lightPosition.z, 1.0f ); |
|
引言回覆: | Step2
這部分也很簡單,我們這次要傳入的Shader的參數就五個
代碼: | // 渲染平面的材質
glUniform1i( glGetUniformLocation( program, "tex" ), 0 );
// 校正後的光的世界座標
glUniform3f( glGetUniformLocation( program, "lightPosition" ), worldLightPosition.x, worldLightPosition.y, worldLightPosition.z );
// 光的顏色
glUniform4f( glGetUniformLocation( program, "lambient" ), 0.4, 0.4, 0.4, 1.0 );
glUniform4f( glGetUniformLocation( program, "ldiffuse" ), 0.7, 0.7, 0.7, 1.0 );
glUniform4f( glGetUniformLocation( program, "lspecular" ), 1.0, 1.0, 1.0, 1.0 ); |
|
那我們來看這次的Shader。
引言回覆: | Step3
vertex shader和fragment shader的部分還是一如既往,用第一章的程式碼讀取,只修改這兩個檔案的內容。
代碼: | // vertex.vs
varying vec2 texcoord;
varying vec3 outNormal;
varying vec3 position;
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
position = vec3( gl_ModelViewMatrix * gl_Vertex );
outNormal = gl_NormalMatrix * gl_Normal;
texcoord = gl_MultiTexCoord0.st;
} |
代碼: | // fragment.frag
uniform sampler2D tex;
uniform vec3 lightPosition;
uniform vec4 lambient;
uniform vec4 ldiffuse;
uniform vec4 lspecular;
varying vec2 texcoord;
varying vec3 outNormal;
varying vec3 position;
void main()
{
vec4 texcolor = texture2D( tex, texcoord );
vec3 normal = normalize( outNormal );
vec3 surf2light = normalize( lightPosition - position );
vec3 surf2camera = normalize( -position );
vec3 reflection = -reflect( surf2camera, normal );
vec3 ambient = vec3( lambient * texcolor );
float diffuseContribution = max( 0.0, dot( normal, surf2light ) );
vec3 diffuse = vec3( diffuseContribution * ldiffuse * texcolor );
float specularContribution = pow( max( 0.0, dot( reflection, surf2light ) ), 32.0);
vec3 specular = vec3( specularContribution * lspecular );
gl_FragColor = vec4( ambient + diffuse + specular, 1.0 );
//gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
} |
各位應該可以明顯看出這次的fragment shader變長了不少,我們一行一行來看
先從vertex.vs開始,與上次不同的多了兩行
代碼: | position = vec3( gl_ModelViewMatrix * gl_Vertex );
outNormal = gl_NormalMatrix * gl_Normal; |
position和outNormal都是varying屬性的變數,也就是我們之後要傳給fragment用的。
position是把modelViewMatrix乘上vertex之後得到的,各點的世界座標。
gl_Normal大家可能比較陌生,還記得我們之前在加上光線模擬之後,都要在面上設置法向量嗎? 這個gl_Normal就是那個法向量(glNormal3f(x,y,z)<-這個東西)
gl_NormalMatrix,再者,又出現了一個新矩陣,它又是什麼? 它其實就是modelViewMatrix去掉最右排跟最下排的3x3矩陣,為什麼要乘上它呢?
引言回覆: | gl_NormalMatrix
是這樣的:
透過這張圖應該就很清楚了,一個平面若只是平移還無妨,若是旋轉還是變形,你原本設定的那個法向量也要跟著旋轉變形才行。
那又為什麼normalMatrix是modelViewMatrix去掉最右排跟最下排的3x3矩陣?
還記得第二章我說到modelViewMatrix是長這樣的嗎?
去掉最右排跟最下排就是把Translate的部分拿掉,因為沒有用到,平面如何平移都不會影響法向量。
我想應該足夠清楚了
|
那終於可以開始講fragment shader了。
texcolor我就不提了。
代碼: | vec3 normal = normalize( outNormal ); |
這行用到的normalize,是把向量的長度等比縮為1的函式,為了讓之後用到的其他函式可以正常操作的預先初始動作
normal就是處理過的法向量。
代碼: | vec3 surf2light = normalize( lightPosition - position ); |
surf2light是處理過後的,vertex到光座標的向量
代碼: | vec3 surf2camera = normalize( -position ); |
surf2camera是處理過後的,vertex到攝影機的向量。
※這個要記住,攝影機的位置永遠都在(0, 0, 0),不可以被gluLookAt給迷惑,當你在改變視野,其實是全部場景的物體一起在旋轉而已! 你的位置是不動的,是世界在旋轉。
代碼: | vec3 reflection = -reflect( surf2camera, normal ) |
reflect是OpenGL在Shader內建的運算函數,會回傳反射向量,可參照http://www.opengl.org/sdk/docs/manglsl/xhtml/reflect.xml
reflection就是我們的視角對於那個平面的反射向量(物理在教入射角等於反射角時,畫的那兩條向量)。
再來,我們的光線是來自三個顏色相加,就是大家常聽到的環境光、散射光以及反射光,我也簡單介紹一下。
環境光(ambient),在實作上的意義就是,讓你即便不開燈也能看到東西的那個光,換句話說,照不到光的東西你要讓它有多少能見度就是環境光的功能。
散射光(diffuse),讓圖形有立體感就靠它了,它只會加在照的到光的地方,讓照到光的地方更亮,顯出跟沒照到光的地方的對比。
反射光(specular),在一個平面上面看到的光點就是它。
代碼: | vec3 ambient = vec3( lambient * texcolor ); |
ambient就是把環境光的顏色和材質顏色混和後的顏色。
代碼: | float diffuseContribution = max( 0.0, dot( normal, surf2light ) ); |
dot是點積,我們可以透過它的值來判斷兩向量的夾角,可參照http://www.csie.ntnu.edu.tw/~u91029/PointLinePlane.html。
※用IE瀏覽這個網頁如果都是亂碼,把網頁編碼改成Unicode就可以了
diffuseContribution,是我們要來判斷散射光要多亮的依據,dot( normal, surf2light )算出來的結果如果小於0,表示法向量和點到光向量夾角大於90度,那這個面肯定照不到光,就設成0.0黑色,像這樣。
代碼: | vec3 diffuse = vec3( diffuseContribution * ldiffuse * texcolor ); |
diffuse就是把光顏色、計算後的光參數還有原先材質顏色混和後的顏色。
代碼: | float specularContribution = pow( max( 0.0, dot( reflection, surf2light ) ), 32.0); |
specularContribution則是把剛剛取得的反射向量和點到光向量做點積,同diffuse背光面不會有反射光,而面光那一面的話,兩個向量夾角愈小(點積值愈大),能看到的光反射面愈大,這個大家可以拿一面鏡子,對著電燈嘗試看看。
至於為什麼要做pow也就是次方運算,這是為了凝聚出中間那顆最亮的光點,在0~1的小數,以0.5為界,它們的次方數愈高差值會愈大。
例如說原本是0.5和0.6,相差0.1,但平方後變成0.25及0.36,差值變成0.11,可以增加亮點跟稍微亮的點之間的對比度。
再者,數字愈接近1的值,次方後還是會趨近於1,例如0.999平方後是0.998001,於是結論就是:
讓亮的還是那麼亮,稍微暗點的會變得更暗,增加對比度的意思。
我想這樣說明應該差不多了
代碼: | vec3 specular = vec3( specularContribution * lspecular ); |
specular就是光參數乘上反射光顏色,應該不用多解釋了。
代碼: | gl_FragColor = vec4( ambient + diffuse + specular, 1.0 ); |
最後把所有顏色加起來傳給gl_FragColor就結束了
|
照這樣做,就能夠做出光線的模擬,我想應該沒有什麼還需要介紹的,那麼最後附上範例程式碼。
Example in VC++2012
代碼: | // allheader.h
#ifndef ALLHEADER_H
#define ALLHEADER_H
#include <GL\glm\glm.hpp>
#include <GL\glm\gtc\matrix_transform.hpp>
#include <GL\glm\gtx\transform.hpp>
#include <GL\glm\gtc\type_ptr.hpp>
#include <GL\GLee.h>
#include <GL\freeglut.h>
#include <iostream>
#include <fstream>
#include <string>
#include <math.h>
#define ILUT_USE_OPENGL
#include <IL/il.h>
#include <IL/ilu.h>
#include <IL/ilut.h>
#define PI 3.14159265 // 圓周率
struct vector3
{
float x, y, z;
};
#endif |
代碼: | // camera.h
#ifndef CAMERA_H
#define CAMERA_H
#include "allheader.h"
enum inputType{
CAM_NO_MOUSE_INPUT = 0,
CAM_MOUSE_LEFT,
CAM_MOUSE_RIGHT,
CAM_WHEELMOUSE_UP,
CAM_WHEELMOUSE_DOWN,
CAM_MOUSE_MOTION_LEFT,
CAM_MOUSE_MOTION_RIGHT
};
class camera{
vector3 loc;
float camPitch, camYaw;
float moveRate;
float mouseRate;
void lockCamera();
void moveCameraHori( float dir );
void moveCameraVert( float dir );
public:
camera();
camera( vector3 loc);
camera( vector3 loc, float yaw, float pitch );
camera( vector3 loc, float yaw, float pitch, float moveR, float mouseR );
void Control( bool* stateKeyboard, int stateMouse, int windowSizeW = NULL, int windowSizeH = NULL, int bufferX = NULL, int bufferY = NULL );
void UpdateCamera( );
vector3 getVector();
vector3 getLocation();
float getPitch();
float getYaw();
float getMoveRate();
float getMouseRate();
void setLocation(vector3 vec);
void lookAt(float pitch,float yaw);
void setSpeed( float moveR, float mouseR );
void showLocation();
};
#endif |
代碼: | // camera.cpp
#include "camera.h"
camera::camera()
{
loc.x = 0.0;
loc.y = 0.0;
loc.z = 0.0;
camPitch = 0;
camYaw = 0;
moveRate = 0.2;
mouseRate = 0.2;
}
camera::camera( vector3 l )
{
loc.x = l.x;
loc.y = l.y;
loc.z = l.z;
camPitch = 0;
camYaw = 0;
moveRate = 0.2;
mouseRate = 0.2;
}
camera::camera( vector3 l, float yaw, float pitch )
{
loc.x = l.x;
loc.y = l.y;
loc.z = l.z;
camPitch = pitch;
camYaw = yaw;
moveRate = 0.2;
mouseRate = 0.2;
}
camera::camera( vector3 l, float yaw, float pitch, float moveR, float mouseR )
{
loc.x = l.x;
loc.y = l.y;
loc.z = l.z;
camPitch = pitch;
camYaw = yaw;
moveRate = moveR;
mouseRate = mouseR;
}
void camera::lockCamera()
{
if(camPitch > 90)
camPitch = 90;
if(camPitch < -90)
camPitch = -90;
if(camYaw < 0.0)
camYaw += 360.0;
if(camYaw > 360.0)
camYaw -= 360;
}
void camera::moveCameraHori( float dir )
{
float rad = (camYaw+dir)*PI/180.0;
loc.x += sin(rad)*moveRate;
loc.z += cos(rad)*moveRate;
}
void camera::moveCameraVert( float dir )
{
float rad = (camPitch+dir)*PI/180.0;
loc.y -= sin(rad)*moveRate;
}
void camera::Control( bool* stateKeyboard, int stateMouse, int windowSizeW, int windowSizeH, int bufferX, int bufferY )
{
// mouse
if( stateMouse != CAM_NO_MOUSE_INPUT )
{
if( stateMouse == CAM_MOUSE_MOTION_LEFT ){
camYaw += mouseRate*(bufferX/2.0);
camPitch += mouseRate*(bufferY/2.0);
}
if( stateMouse == CAM_WHEELMOUSE_UP ){
if( camPitch != 90 && camPitch != -90 )
moveCameraHori(0.0);
moveCameraVert(0.0);
}
if( stateMouse == CAM_WHEELMOUSE_DOWN ){
if( camPitch != 90 && camPitch != -90 )
moveCameraHori(180.0);
moveCameraVert(180.0);
}
if( stateMouse == CAM_MOUSE_MOTION_RIGHT ){
if( bufferX > 0 )
moveCameraHori(90.0);
else
moveCameraHori(270.0);
}
lockCamera();
}
// keyboard
if( stateKeyboard[(unsigned int)'w'] )
{
if( camPitch != 90 && camPitch != -90 )
moveCameraHori(0.0);
moveCameraVert(0.0);
}
if( stateKeyboard[(unsigned int)'s'] )
{
if( camPitch != 90 && camPitch != -90 )
moveCameraHori(180.0);
moveCameraVert(180.0);
}
if( stateKeyboard[(unsigned int)'a'] )
{
moveCameraHori(90.0);
}
if( stateKeyboard[(unsigned int)'d'] )
{
moveCameraHori(270.0);
}
if( stateKeyboard[(unsigned int)'h'] )
{
showLocation();
}
// result
glRotatef( -camPitch, 1.0, 0.0, 0.0 );
glRotatef( -camYaw, 0.0, 1.0, 0.0 );
}
void camera::UpdateCamera()
{
glTranslatef( loc.x, loc.y, loc.z );
}
vector3 camera::getVector()
{
vector3 tmp;
tmp.x = -cos(camPitch*PI/180.0)*sin(camYaw*PI/180.0);
tmp.y = sin(camPitch*PI/180.0);
tmp.z = -cos(camPitch*PI/180.0)*cos(camYaw*PI/180.0);
return tmp;
}
vector3 camera::getLocation()
{
return loc;
}
float camera::getPitch()
{
return camPitch;
}
float camera::getYaw()
{
return camYaw;
}
float camera::getMoveRate()
{
return moveRate;
}
float camera::getMouseRate()
{
return mouseRate;
}
void camera::setLocation( vector3 vec )
{
loc.x = vec.x;
loc.y = vec.y;
loc.z = vec.z;
}
void camera::lookAt( float pitch, float yaw )
{
camPitch = pitch;
camYaw = yaw;
}
void camera::setSpeed( float moveR, float mouseR )
{
moveRate = moveR;
mouseRate = mouseR;
}
void camera::showLocation()
{
std::cout << "Location: " << loc.x << ", " << loc.y << ", " << loc.z << std::endl
<< "Direction: " << camPitch << ", " << camYaw << std::endl;
} |
代碼: | // main.cpp
//---------------------------------------------------------
// 作者: DR
// 2013/11/29
//
// GLSL&GLUT 從環境設定開始的基礎教學(04) - 光線模擬
//---------------------------------------------------------
//
#include "allheader.h"
#include "camera.h"
#define WINDOW_SIZE_W 500 // 起始視窗寬度
#define WINDOW_SIZE_H 500 // 起始視窗高度
#define WINDOW_VISION_ANGLE 45 // 視角
#define WINDOW_VISION_NEAR 1 // 最近視野
#define WINDOW_VISION_FAR 10001 // 最遠視野
bool stateKeyboard[256] = { false };
GLuint windowHandle;
int win_size_w = WINDOW_SIZE_W,
win_size_h = WINDOW_SIZE_H;
camera MainCamera;
GLuint myTex, myTex2;
// 光座標
vector3 lightPosition;
void loadFile( const char* filename, std::string &string )
{
std::ifstream fp(filename);
if( !fp.is_open() ){
std::cout << "Open <" << filename << "> error." << std::endl;
return;
}
char temp[300];
while( !fp.eof() ){
fp.getline( temp, 300 );
string += temp;
string += '\n';
}
fp.close();
}
GLuint loadShader(std::string &source, GLenum type)
{
GLuint ShaderID;
ShaderID = glCreateShader( type ); // 告訴OpenGL我們要創的是哪種shader
const char* csource = source.c_str(); // 把std::string結構轉換成const char*
glShaderSource( ShaderID, 1, &csource, NULL ); // 把程式碼放進去剛剛創建的shader object中
glCompileShader( ShaderID ); // 編譯shader
char error[1000] = "";
glGetShaderInfoLog( ShaderID, 1000, NULL, error ); // 這是編譯過程的訊息, 錯誤什麼的把他丟到error裡面
std::cout << "Complie status: \n" << error << std::endl; // 然後輸出出來
return ShaderID;
}
GLuint vs, fs, program; // 用來儲存shader還有program的id
void initShader(const char* vname, const char* fname)
{
std::string source;
loadFile( vname, source ); // 把程式碼讀進source
vs = loadShader( source, GL_VERTEX_SHADER ); // 編譯shader並且把id傳回vs
source = "";
loadFile( fname, source );
fs = loadShader( source, GL_FRAGMENT_SHADER );
program = glCreateProgram(); // 創建一個program
glAttachShader( program, vs ); // 把vertex shader跟program連結上
glAttachShader( program, fs ); // 把fragment shader跟program連結上
glLinkProgram( program ); // 根據被連結上的shader, link出各種processor
glUseProgram( program ); // 然後使用它
}
void clean()
{
glDetachShader( program, vs );
glDetachShader( program, fs );
glDeleteShader( vs );
glDeleteShader( fs );
glDeleteProgram( program );
}
void Initialize()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( WINDOW_VISION_ANGLE, (float)WINDOW_SIZE_W/(float)WINDOW_SIZE_H, WINDOW_VISION_NEAR, WINDOW_VISION_FAR );
glEnable( GL_DEPTH_TEST );
ilInit();
iluInit();
ilutInit();
ilutRenderer(ILUT_OPENGL);
myTex = ilutGLLoadImage( (wchar_t*)"example.jpg" );
initShader( "vertex.vs", "fragment.frag" );
glEnable( GL_TEXTURE_2D );
MainCamera.setSpeed( 0.1, 0.2 );
lightPosition.x = 0;
lightPosition.y = 0;
lightPosition.z = 2;
}
void Display()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glClearColor( 0.0, 0.0, 0.0, 1.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
MainCamera.Control( stateKeyboard, CAM_NO_MOUSE_INPUT );
MainCamera.UpdateCamera();
// camera class版本
// 調整的作法都一樣, 只是取Matrix的方法變成這樣
glm::mat4 modelViewMatrix =
glm::rotate( -MainCamera.getPitch(), 1.0f, 0.0f, 0.0f ) *
glm::rotate( -MainCamera.getYaw(), 0.0f, 1.0f, 0.0f ) *
glm::translate( MainCamera.getLocation().x, MainCamera.getLocation().y, MainCamera.getLocation().z );
glm::vec4 worldLightPosition = modelViewMatrix * glm::vec4( lightPosition.x, lightPosition.y, lightPosition.z, 1.0f );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, myTex );
// 渲染平面的材質
glUniform1i( glGetUniformLocation( program, "tex" ), 0 );
// 校正後的光的世界座標
glUniform3f( glGetUniformLocation( program, "lightPosition" ), worldLightPosition.x, worldLightPosition.y, worldLightPosition.z );
// 光的顏色
glUniform4f( glGetUniformLocation( program, "lambient" ), 0.4, 0.4, 0.4, 1.0 );
glUniform4f( glGetUniformLocation( program, "ldiffuse" ), 0.7, 0.7, 0.7, 1.0 );
glUniform4f( glGetUniformLocation( program, "lspecular" ), 1.0, 1.0, 1.0, 1.0 );
glBegin(GL_QUADS);
glNormal3f( 0, 0, 1 );
glTexCoord2f( 1, 1 );
glVertex3f(1, 1, -5);
glTexCoord2f( 0, 1 );
glVertex3f(-1, 1, -5);
glTexCoord2f( 0, 0 );
glVertex3f(-1, -1, -5);
glTexCoord2f( 1, 0 );
glVertex3f(1, -1, -5);
glEnd();
glutSwapBuffers();
}
void Reshape( int w, int h )
{
glViewport( 0, 0, w, h );
if( h == 0 ) h = 1;
win_size_w = w;
win_size_h = h;
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( WINDOW_VISION_ANGLE, (float)w/(float)h, WINDOW_VISION_NEAR, WINDOW_VISION_FAR );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
bool MOUSE_LEFT = false, MOUSE_RIGHT = false;
int mouse_x = 0, mouse_y = 0, old_mouse_x = 0, old_mouse_y = 0;
void Mouse( int button, int state, int x, int y )
{
switch( button ){
case GLUT_LEFT_BUTTON:
if( state ){
MOUSE_LEFT = false;
mouse_x = 0;
mouse_y = 0;
}
else{
MainCamera.Control( stateKeyboard, CAM_MOUSE_LEFT, win_size_w, win_size_h, x, y );
MOUSE_LEFT = true;
old_mouse_x = x;
old_mouse_y = y;
}
break;
case GLUT_RIGHT_BUTTON:
if( state ){
MOUSE_RIGHT = false;
mouse_x = 0;
mouse_y = 0;
}
else{
MainCamera.Control( stateKeyboard, CAM_MOUSE_RIGHT, win_size_w, win_size_h, x, y );
MOUSE_RIGHT = true;
old_mouse_x = x;
old_mouse_y = y;
}
break;
}
}
void MouseWheel( int wheel, int direction, int x, int y )
{
switch( direction ){
case 1:
MainCamera.Control( stateKeyboard, CAM_WHEELMOUSE_UP );
break;
case -1:
MainCamera.Control( stateKeyboard, CAM_WHEELMOUSE_DOWN );
break;
}
}
void MotionMouse( int x, int y )
{
if( MOUSE_LEFT ){
mouse_x = x - old_mouse_x;
mouse_y = y - old_mouse_y;
MainCamera.Control( stateKeyboard, CAM_MOUSE_MOTION_LEFT, win_size_w, win_size_h, mouse_x, mouse_y );
old_mouse_x = x;
old_mouse_y = y;
}
if( MOUSE_RIGHT ){
mouse_x = x - old_mouse_x;
mouse_y = y - old_mouse_y;
MainCamera.Control( stateKeyboard, CAM_MOUSE_MOTION_RIGHT, win_size_w, win_size_h, mouse_x, mouse_y );
old_mouse_x = x;
old_mouse_y = y;
}
}
void Keyboard( unsigned char key, int x, int y )
{
stateKeyboard[key] = true;
}
void KeyboardUp( unsigned char key, int x, int y )
{
stateKeyboard[key] = false;
}
void Timer( int t )
{
glutPostRedisplay();
glutTimerFunc( 1000/60, Timer, 1 );
}
int main( int argc, char** argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
glutInitWindowPosition( 0, 0 );
glutInitWindowSize( WINDOW_SIZE_W, WINDOW_SIZE_H );
windowHandle = glutCreateWindow( "GLUT&GLSL example" );
Initialize();
glutDisplayFunc( Display );
glutReshapeFunc( Reshape );
glutMouseFunc( Mouse );
glutMouseWheelFunc( MouseWheel );
glutMotionFunc( MotionMouse );
glutKeyboardFunc( Keyboard );
glutKeyboardUpFunc( KeyboardUp );
glutTimerFunc( 1000/60, Timer, 0 );
glutMainLoop();
return 0;
} |
描述: |
|
下載 |
檔名: |
ch4.rar |
附件大小: |
103.34 KB |
下載次數: |
共 442 次 |
Director 在 2015-7-5, AM 6:06 星期日 作了第 2 次修改 |
|