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


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-Wesley1992)的作者。Paul 在其业余时间里开发出了 PixieLib,可通过他的网站 www.dilascia.com 来获取该 MFC 类库。

将下载下来的源代码编译后会生成Lib目录,我们需要用到的就是IncludeLib这两个目录,当然你也可以看看它自带的Samples。由于使用的是最新PixieLib7.1版,因此接下来几篇文章都在VS2005下进行开发。

1,LibInclude目录拷贝到新建的MFC项目目录下,配置如下:

1)c/c++à附加包含目录,这里加入”."include”

2)链接器à附加库目录,这里加入”."lib”

3)输入à附加依赖项,这里加入PixieLib71.lib

2,在stdafx.h中包含进PixieLib库文件:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> #include < PixieLib.h > // PixelLibrary

3,在CCY457OpenGLView类中加入下述变量:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> int m_PixelFormat; // PixelFormat

// PositionandDirection

GLfloatm_PosX;

GLfloatm_PosY;

GLfloatm_PosZ;

GLfloatm_DirX;

GLfloatm_DirY;

GLfloatm_DirZ;

// Rotation

GLfloatm_xRot,m_yRot;
// 绕x,y轴旋转的角度,随时间不断变化

// IncrementforKeyboardControl

GLfloatm_PosIncr;
// PositionalIncrement

GLfloatm_AngIncr;
// AngularIncrement

// AngleofCameraWithXAxis

GLfloatm_AngleX;

GLdoublem_texWrap,m_texFilter,m_texMode;

GLfloatm_ShadowMat[
4 ][ 4 ];

// AllTextureNames

GLuintm_Texture[
4 ];

并在构造函数中初始化如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> CCY457OpenGLView::CCY457OpenGLView()

{

// Rotation

m_xRot
= 0.0f ;

m_yRot
= 0.0f ;

// PositionIncrement

m_PosIncr
= 0.25f ;

// AngleIncrement

m_AngIncr
= 5.0f ;

// SetInitialCameraPosition-lookingdownnegativeZ

m_PosX
= 0.0f ;

m_PosY
= 0.5f ;

m_PosZ
= 2.5f ;

// SetInitialViewingDirection-PointingDownthe-veZAxis

m_DirX
= m_PosX;

m_DirY
= m_PosY;

m_DirZ
= m_PosZ - m_PosIncr;

// AngleofCamerawithXAxis

m_AngleX
= 90.0f ;

m_texWrap
= GL_CLAMP;

m_texMode
= GL_DECAL;

m_texFilter
= GL_NEAREST;

}

4InitializeOpenGL函数修改如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> BOOLCCY457OpenGLView::InitializeOpenGL()

{

// GetaDCfortheClientArea

m_pDC
= new CClientDC( this );

// FailuretoGetDC

if (m_pDC == NULL)

{

MessageBox(
" ErrorObtainingDC " );

return FALSE;

}

// Failuretosetthepixelformat

if ( ! SetupPixelFormat())

{

return FALSE;

}

// CreateRenderingContext

m_hRC
= ::wglCreateContext(m_pDC -> GetSafeHdc());

// FailuretoCreateRenderingContext

if (m_hRC == 0 )

{

MessageBox(
" ErrorCreatingRC " );

return FALSE;

}

// MaketheRCCurrent

if (::wglMakeCurrent(m_pDC -> GetSafeHdc(),m_hRC) == FALSE)

{

MessageBox(
" ErrormakingRCCurrent " );

return FALSE;

}

// specifyblackasclearcolor

::glClearColor(
0.0f , 0.0f , 0.0f , 0.0f );

// specifythebackofthebufferascleardepth

::glClearDepth(
1.0f );

// enabledepthtesting

::glEnable(GL_DEPTH_TEST);

// EnableColorTracking

::glEnable(GL_COLOR_MATERIAL);

::glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);

::glShadeModel(GL_SMOOTH);

// SetupLightingHere

SetupLighting();

LoadGLTextures();

// Effects

// Shadow

// CalulateShadowMatrix

GLfloatlightPos[]
= { 1.0f , 1.5f , - 1.0f , 0.0f };

GLfloatpoints[][
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,设置灯光的代码修改如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> void CCY457OpenGLView::SetupLighting()

{

// EnableLighting

glEnable(GL_LIGHTING);

// SetuptheLightModel

// InfiniteViewer

glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_FALSE);

// SingleSidedLighting

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_FALSE);

// Setupthelights

// Light1

// DirectionalLightfromFront

GLfloatm_SceneAmbient1[]
= { 0.5f , 0.5f , 0.5f , 1.0f };

GLfloatm_SceneDiffuse1[]
= { 1.0f , 1.0f , 1.0f , 1.0f };

GLfloatm_SceneSpecular1[]
= { 1.0f , 1.0f , 1.0f , 1.0f };

GLfloatm_ScenePosition1[]
= { 1.0f , 1.5f , - 1.0f , 1.0f };

GLfloatm_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,绘制代码修改如下:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> void CCY457OpenGLView::RenderScene()

{
// 绘制函数

// PositionCamera

gluLookAt(m_PosX,m_PosY,m_PosZ,m_DirX,m_DirY,m_DirZ,
0.0f , 1.0f , 0.0f );

// DrawtheScene

// Drawthefloor

// Drawtheground,

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

// DrawtheCube

// Savethematrixstateanddotherotations

glPushMatrix();

glTranslatef(
- 1.0f , 0.6f , - 1.0f );

// Drawjetatneworientation,putlightincorrectposition

// beforerotatingthejet

glRotatef(m_xRot,
1.0f , 0.0f , 0.0f );

glRotatef(m_yRot,
0.0f , 1.0f , 0.0f );

DrawCube(FALSE);

// Restoreoriginalmatrixstate

glPopMatrix();

// Getreadytodrawtheshadowandtheground

// Firstdisablelightingandsavetheprojectionstate

glDisable(GL_DEPTH_TEST);

glDisable(GL_LIGHTING);

glPushMatrix();

// Multiplybyshadowprojectionmatrix

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

// Passtruetoindicatedrawingshadow

DrawCube(TRUE);

// Restoretheprojectiontonormal

glPopMatrix();

// Restorelightingstatevariables

glEnable(GL_DEPTH_TEST);

glEnable(GL_LIGHTING);

// Drawthelightsource

glPushMatrix();

glTranslatef(
1.5f , 1.5f , - 1.0f );

glColor3ub(
255 , 255 , 0 );

glutSolidSphere(
0.01f , 10 , 10 );

glPopMatrix();

}

7,用来计算平面法向量,绘制物体,计算阴影矩阵的辅助函数:

ContractedBlock.gif ExpandedBlockStart.gif 辅助函数
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->voidCCY457OpenGLView::ReduceToUnit(GLfloatvector[3])

{

floatlength;

//Calculatethelengthofthevector

length
=(float)sqrt((vector[0]*vector[0])+

(vector[
1]*vector[1])+

(vector[
2]*vector[2]));

//Keeptheprogramfromblowingupbyprovidinganexceptable

//valueforvectorsthatmaycalculatedtooclosetozero.

if(length==0.0f)

length
=1.0f;

//Dividingeachelementbythelengthwillresultina

//unitnormalvector.

vector[
0]/=length;

vector[
1]/=length;

vector[
2]/=length;

}

voidCCY457OpenGLView::CalcNormal(GLfloatv[3][3],GLfloatout[3])

{

floatv1[3],v2[3];

staticconstintx=0;

staticconstinty=1;

staticconstintz=2;

//Calculatetwovectorsfromthethreepoints

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];

//Takethecrossproductofthetwovectorstoget

//thenormalvectorwhichwillbestoredinout

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];

//Normalizethevector(shortenlengthtoone)

ReduceToUnit(
out);

}

//Effects

//Shadow

//Createshadowmatrixfromtheplaneequationcoeff'sandposoflight

voidCCY457OpenGLView::MakeShadowMatrix(GLfloatpoints[3][3],GLfloatlightPos[4],GLfloatdestMat[4][4])

{

GLfloatplaneCoeff[
4];

GLfloatdot;

//Findtheplaneequationcoefficients

//Findthefirstthreecoefficientsthesamewaywe

//findanormal.

CalcNormal(points,planeCoeff);

//Findthelastcoefficientbybacksubstitutions

planeCoeff[
3]=-(

(planeCoeff[
0]*points[2][0])+(planeCoeff[1]*points[2][1])+

(planeCoeff[
2]*points[2][2]));

//Dotproductofplaneandlightposition

dot
=planeCoeff[0]*lightPos[0]+

planeCoeff[
1]*lightPos[1]+

planeCoeff[
2]*lightPos[2]+

planeCoeff[
3]*lightPos[3];

//Nowdotheprojection

//Firstcolumn

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];

//Secondcolumn

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];

//ThirdColumn

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];

//FourthColumn

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];

}

voidCCY457OpenGLView::DrawCubeTex()

{

glScalef(
0.3f,0.3f,0.3f);

glEnable(GL_TEXTURE_2D);

glBindTexture(GL_TEXTURE_2D,m_Texture[
0]);

//FrontFace

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

//BackFace

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

//LeftFace

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

//RightFace

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

//TopFace

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

//BottonFace

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

}

voidCCY457OpenGLView::DrawCubeNoTex()

{

glScalef(
0.3f,0.3f,0.3f);

//FrontFace

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

//BackFace

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

//LeftFace

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

//RightFace

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

//TopFace

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

//BottonFace

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

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值