您的位置:首页 > 编程语言

《基于MFC的OpenGL编程》Part 17 Shadows

2008-11-07 15:43 274 查看


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();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: