|
Posted on 2010-03-31 20:52 Shuffy 閱讀(421) 評論(0) 編輯 收藏 引用 所屬分類: MFC,OpenGL
Shadows
Conceptually drawing a shadow is quite simple. A shadow is produced when an object keeps light from a source from striking some object or surface behind the object, casting the shadow. The area on the shadowed object's surface outlined by the object casting the shadow appears dark. We can produce a shadow programatically by flattening the original object into the plane of the surface in which the object lies. The object is then drawn in black or some other color. This is a very simple method which works when casting shadows on a flat surface.
從這一篇開始將用到一個第三方庫PixieLib,本文先對這個庫的使用做簡單介紹,后續文章中將不再贅述。
Paul DiLascia是兼職軟件顧問和資深的 Web/UI 設計師。他是《Windows++: Writing Reusable Windows Code in C++》(Windows++:在 C++ 中編寫可重用 Windows 代碼)一書(Addison-Wesley,1992)的作者。Paul 在其業余時間里開發出了 PixieLib,可通過他的網站 www.dilascia.com 來獲取該 MFC 類庫。
將下載下來的源代碼編譯后會生成Lib目錄,我們需要用到的就是Include和Lib這兩個目錄,當然你也可以看看它自帶的Samples。由于使用的是最新PixieLib7.1版,因此接下來幾篇文章都在VS2005下進行開發。
1,將Lib和Include目錄拷貝到新建的MFC 項目目錄下,配置如下:
1)c/c++à附加包含目錄,這里加入”."include”。
2)鏈接器à附加庫目錄,這里加入”."lib”
3)輸入à附加依賴項,這里加入PixieLib71.lib
2,在stdafx.h中包含進PixieLib庫文件:
#include <PixieLib.h> //Pixel Library
3,在CCY457OpenGLView類中加入下述變量:
int m_PixelFormat; //Pixel Format
//Position and Direction
GLfloat m_PosX;
GLfloat m_PosY;
GLfloat m_PosZ;
GLfloat m_DirX;
GLfloat m_DirY;
GLfloat m_DirZ;
//Rotation
GLfloat m_xRot, m_yRot;//繞x,y軸旋轉的角度,隨時間不斷變化
//Increment for Keyboard Control
GLfloat m_PosIncr; //Positional Increment
GLfloat m_AngIncr; //Angular Increment
//Angle of Camera With X Axis
GLfloat m_AngleX;
GLdouble m_texWrap, m_texFilter, m_texMode;
GLfloat m_ShadowMat[4][4];
//All Texture Names
GLuint m_Texture[4];
并在構造函數中初始化如下:
CCY457OpenGLView::CCY457OpenGLView()
{
//Rotation
m_xRot = 0.0f;
m_yRot = 0.0f;
//Position Increment
m_PosIncr = 0.25f;
//Angle Increment
m_AngIncr = 5.0f;
//Set Initial Camera Position - looking down negative Z
m_PosX = 0.0f;
m_PosY = 0.5f;
m_PosZ = 2.5f;
//Set Initial Viewing Direction - Pointing Down the -ve Z Axis
m_DirX = m_PosX;
m_DirY = m_PosY;
m_DirZ = m_PosZ-m_PosIncr;
//Angle of Camera with X Axis
m_AngleX = 90.0f;
m_texWrap = GL_CLAMP;
m_texMode = GL_DECAL;
m_texFilter = GL_NEAREST;
}
4,InitializeOpenGL函數修改如下:
BOOL CCY457OpenGLView::InitializeOpenGL()
{
//Get a DC for the Client Area
m_pDC = new CClientDC(this);
//Failure to Get DC
if(m_pDC == NULL)
{
MessageBox("Error Obtaining DC");
return FALSE;
}
//Failure to set the pixel format
if(!SetupPixelFormat())
{
return FALSE;
}
//Create Rendering Context
m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ());
//Failure to Create Rendering Context
if(m_hRC == 0)
{
MessageBox("Error Creating RC");
return FALSE;
}
//Make the RC Current
if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE)
{
MessageBox("Error making RC Current");
return FALSE;
}
// specify black as clear color
::glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// specify the back of the buffer as clear depth
::glClearDepth(1.0f);
// enable depth testing
::glEnable(GL_DEPTH_TEST);
//Enable Color Tracking
::glEnable(GL_COLOR_MATERIAL);
::glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
::glShadeModel(GL_SMOOTH);
//Setup Lighting Here
SetupLighting();
LoadGLTextures();
//Effects
//Shadow
//Calulate Shadow Matrix
GLfloat lightPos[] = {1.0f,1.5f,-1.0f,0.0f};
GLfloat points[][3] = {
{-2.0f,0.0f,0.0f},
{2.0f,0.0f,0.0f},
{2.0f,0.0f,-2.0f}
};
MakeShadowMatrix(points, lightPos, m_ShadowMat);
return TRUE;
}
5,設置燈光的代碼修改如下:
void CCY457OpenGLView::SetupLighting ()
{
//Enable Lighting
glEnable(GL_LIGHTING);
//Set up the Light Model
//Infinite Viewer
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
//Single Sided Lighting
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
//Set up the lights
//Light 1
//Directional Light from Front
GLfloat m_SceneAmbient1[] = {0.5f,0.5f,0.5f,1.0f};
GLfloat m_SceneDiffuse1[] = {1.0f,1.0f,1.0f,1.0f};
GLfloat m_SceneSpecular1[] = {1.0f,1.0f,1.0f,1.0f};
GLfloat m_ScenePosition1[] = {1.0f,1.5f,-1.0f,1.0f};
GLfloat m_SceneDirection1[]= {0.0f,0.0f,-1.0f,1.0f};
glLightfv(GL_LIGHT0,GL_AMBIENT,m_SceneAmbient1);
glLightfv(GL_LIGHT0,GL_DIFFUSE,m_SceneDiffuse1);
glLightfv(GL_LIGHT0,GL_SPECULAR,m_SceneSpecular1);
glLightfv(GL_LIGHT0,GL_POSITION,m_ScenePosition1);
glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,75.0f);
glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,m_SceneDirection1);
glEnable(GL_LIGHT0);
}
6,繪制代碼修改如下:
void CCY457OpenGLView::RenderScene ()
{//繪制函數
//Position Camera
gluLookAt(m_PosX,m_PosY,m_PosZ,m_DirX,m_DirY,m_DirZ,0.0f,1.0f,0.0f);
//Draw the Scene
//Draw the floor
// Draw the ground,
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_Texture[3]);
glBegin(GL_POLYGON);
glColor3ub(0,255,0);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-2.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(2.0f,0.0f, 0.0f);
glColor3ub(0,100,0);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(2.0f, 0.0f, -2.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-2.0f,0.0f, -2.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
//Draw the Cube
// Save the matrix state and do the rotations
glPushMatrix();
glTranslatef(-1.0f,0.6f,-1.0f);
// Draw jet at new orientation, put light in correct position
// before rotating the jet
glRotatef(m_xRot,1.0f,0.0f,0.0f);
glRotatef(m_yRot,0.0f,1.0f,0.0f);
DrawCube(FALSE);
// Restore original matrix state
glPopMatrix();
// Get ready to draw the shadow and the ground
// First disable lighting and save the projection state
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glPushMatrix();
// Multiply by shadow projection matrix
glMultMatrixf((GLfloat *)m_ShadowMat);
glTranslatef(-1.0f,0.6f,-1.0f);
glRotatef(m_xRot,1.0f,0.0f,0.0f);
glRotatef(m_yRot,0.0f,1.0f,0.0f);
// Pass true to indicate drawing shadow
DrawCube(TRUE);
// Restore the projection to normal
glPopMatrix();
// Restore lighting state variables
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
// Draw the light source
glPushMatrix();
glTranslatef(1.5f,1.5f,-1.0f);
glColor3ub(255,255,0);
glutSolidSphere(0.01f,10,10);
glPopMatrix();
}
7,用來計算平面法向量,繪制物體,計算陰影矩陣的輔助函數:
 輔助函數 void CCY457OpenGLView::ReduceToUnit(GLfloat vector[3])
{
float length;
// Calculate the length of the vector
length = (float)sqrt((vector[0]*vector[0]) +
(vector[1]*vector[1]) +
(vector[2]*vector[2]));
// Keep the program from blowing up by providing an exceptable
// value for vectors that may calculated too close to zero.
if(length == 0.0f)
length = 1.0f;
// Dividing each element by the length will result in a
// unit normal vector.
vector[0] /= length;
vector[1] /= length;
vector[2] /= length;
}
void CCY457OpenGLView::CalcNormal(GLfloat v[3][3],GLfloat out[3])
{
float v1[3],v2[3];
static const int x = 0;
static const int y = 1;
static const int z = 2;
// Calculate two vectors from the three points
v1[x] = v[0][x] - v[1][x];
v1[y] = v[0][y] - v[1][y];
v1[z] = v[0][z] - v[1][z];
v2[x] = v[1][x] - v[2][x];
v2[y] = v[1][y] - v[2][y];
v2[z] = v[1][z] - v[2][z];
// Take the cross product of the two vectors to get
// the normal vector which will be stored in out
out[x] = v1[y]*v2[z] - v1[z]*v2[y];
out[y] = v1[z]*v2[x] - v1[x]*v2[z];
out[z] = v1[x]*v2[y] - v1[y]*v2[x];
// Normalize the vector (shorten length to one)
ReduceToUnit(out);
}
//Effects
//Shadow
// Create shadow matrix from the plane equation coeff's and pos of light
void CCY457OpenGLView::MakeShadowMatrix(GLfloat points[3][3], GLfloat lightPos[4], GLfloat destMat[4][4])
{
GLfloat planeCoeff[4];
GLfloat dot;
// Find the plane equation coefficients
// Find the first three coefficients the same way we
// find a normal.
CalcNormal(points,planeCoeff);
// Find the last coefficient by back substitutions
planeCoeff[3] = - (
(planeCoeff[0]*points[2][0]) + (planeCoeff[1]*points[2][1]) +
(planeCoeff[2]*points[2][2]));
// Dot product of plane and light position
dot = planeCoeff[0] * lightPos[0] +
planeCoeff[1] * lightPos[1] +
planeCoeff[2] * lightPos[2] +
planeCoeff[3] * lightPos[3];
// Now do the projection
// First column
destMat[0][0] = dot - lightPos[0] * planeCoeff[0];
destMat[1][0] = 0.0f - lightPos[0] * planeCoeff[1];
destMat[2][0] = 0.0f - lightPos[0] * planeCoeff[2];
destMat[3][0] = 0.0f - lightPos[0] * planeCoeff[3];
// Second column
destMat[0][1] = 0.0f - lightPos[1] * planeCoeff[0];
destMat[1][1] = dot - lightPos[1] * planeCoeff[1];
destMat[2][1] = 0.0f - lightPos[1] * planeCoeff[2];
destMat[3][1] = 0.0f - lightPos[1] * planeCoeff[3];
// Third Column
destMat[0][2] = 0.0f - lightPos[2] * planeCoeff[0];
destMat[1][2] = 0.0f - lightPos[2] * planeCoeff[1];
destMat[2][2] = dot - lightPos[2] * planeCoeff[2];
destMat[3][2] = 0.0f - lightPos[2] * planeCoeff[3];
// Fourth Column
destMat[0][3] = 0.0f - lightPos[3] * planeCoeff[0];
destMat[1][3] = 0.0f - lightPos[3] * planeCoeff[1];
destMat[2][3] = 0.0f - lightPos[3] * planeCoeff[2];
destMat[3][3] = dot - lightPos[3] * planeCoeff[3];
}
void CCY457OpenGLView::DrawCubeTex ()
{
glScalef(0.3f, 0.3f, 0.3f);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,m_Texture[0]);
//Front Face
glBegin(GL_POLYGON);
glTexCoord2f(0,0);
glVertex3f(-1.0f,-1.0f,0.0f);
glTexCoord2f(1,0);
glVertex3f( 1.0f,-1.0f,0.0f);
glTexCoord2f(1,1);
glVertex3f( 1.0f, 1.0f,0.0f);
glTexCoord2f(0,1);
glVertex3f(-1.0f, 1.0f,0.0f);
glEnd();
//Back Face
glBegin(GL_POLYGON);
glTexCoord2f(1,0);
glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2f(1,1);
glVertex3f(-1.0f, 1.0f,-1.0f);
glTexCoord2f(0,1);
glVertex3f( 1.0f, 1.0f,-1.0f);
glTexCoord2f(0,0);
glVertex3f( 1.0f,-1.0f,-1.0f);
glEnd();
glBindTexture(GL_TEXTURE_2D,m_Texture[1]);
//Left Face
glBegin(GL_POLYGON);
glTexCoord2f(1,0);
glVertex3f(-1.0f,-1.0f, 0.0f);
glTexCoord2f(1,1);
glVertex3f(-1.0f, 1.0f, 0.0f);
glTexCoord2f(0,1);
glVertex3f(-1.0f, 1.0f,-1.0f);
glTexCoord2f(0,0);
glVertex3f(-1.0f,-1.0f,-1.0f);
glEnd();
//Right Face
glBegin(GL_POLYGON);
glTexCoord2f(0,0);
glVertex3f(1.0f,-1.0f, 0.0f);
glTexCoord2f(1,0);
glVertex3f(1.0f,-1.0f,-1.0f);
glTexCoord2f(1,1);
glVertex3f(1.0f, 1.0f,-1.0f);
glTexCoord2f(0,1);
glVertex3f(1.0f, 1.0f, 0.0f);
glEnd();
glBindTexture(GL_TEXTURE_2D,m_Texture[2]);
//Top Face
glBegin(GL_POLYGON);
glTexCoord2f(0,0);
glVertex3f(-1.0f, 1.0f, 0.0f);
glTexCoord2f(0,1);
glVertex3f( 1.0f, 1.0f, 0.0f);
glTexCoord2f(1,1);
glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(1,0);
glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
//Botton Face
glBegin(GL_POLYGON);
glTexCoord2f(0,1);
glVertex3f(-1.0f, -1.0f, 0.0f);
glTexCoord2f(0,0);
glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1,0);
glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1,1);
glVertex3f( 1.0f, -1.0f, 0.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
}
void CCY457OpenGLView::DrawCubeNoTex ()
{
glScalef(0.3f, 0.3f, 0.3f);
//Front Face
glBegin(GL_POLYGON);
glVertex3f(-1.0f,-1.0f,0.0f);
glVertex3f( 1.0f,-1.0f,0.0f);
glVertex3f( 1.0f, 1.0f,0.0f);
glVertex3f(-1.0f, 1.0f,0.0f);
glEnd();
//Back Face
glBegin(GL_POLYGON);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
glEnd();
//Left Face
glBegin(GL_POLYGON);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glEnd();
//Right Face
glBegin(GL_POLYGON);
glVertex3f(1.0f,-1.0f, 0.0f);
glVertex3f(1.0f,-1.0f,-1.0f);
glVertex3f(1.0f, 1.0f,-1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glEnd();
//Top Face
glBegin(GL_POLYGON);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
//Botton Face
glBegin(GL_POLYGON);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, 0.0f);
glEnd();
}
原文鏈接:
|