OpenGL课程设计-三维球体的实现
- 格式:doc
- 大小:339.50 KB
- 文档页数:14
计算机图形学实验报告1、实验目的和要求利用第七章所学的知识,试在OpenGL中创建一个球体动画,使球体在窗口内做自由落体运动,并在撞击地面后能够反弹回来。
并用相应的代码表示出来。
2、实验内容利用glutSolidSphere函数等其它函数,在OpenGL中创建一个球体动画,使球体在窗口内做自由落体运动,并在撞击地面后能够反弹回来3、实验步骤1)相关算法及原理描述我们所使用的glut实用工具中,正好就有一个绘制球体的现成函数: glutSolidSphere,这个函数在“原点”绘制出一个球体。
由于坐标是可以通过glTranslate*和glRotate*两个函数进行随意变换的,所以我们就可以在任意位置绘制球体了。
2)运行结果如下图,程序调试成功,并且能正常显示4、实验总结通过本次试验,进一步认识,感觉OpenGL的功能很强大,各种各样的物理模拟实验他都不在话下!!不得不说,这软件很好很强大!!由于自己不太擅长编程, 所以有些功能还不能完全实现,但我会尽自己最大努力来克服自己的编程不足之处,多加练习。
5、附录带注释的源程序#include "glut.h"#include<stdlib.h>#include<stdio.h>#include<time.h>#include<math.h>#define PI 3.1415926double move=20.0;int i=0;int down=1;int count=1;double timeSpan=0; // 下降到底所需时间double movey=0.0;double duration=0.0; //持续时间double length=0.0;clock_t start,end;void init(void){GLfloat mat_specular[]={220.220,220.0,220.0,220.0};GLfloat mat_shininess[]={100.0};GLfloat light_position[]={0.0, 0.0, 0.0, -2.0}; //r-l u-d f-bGLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };GLfloat diffuseLight[] = { 0.6f, 0.6f, 0.6f, 1.0f };GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f};glClearColor(0.2,0.2,1.5,2.0); //bgc glColor3ub(100, 100, 215);glShadeModel(GL_SMOOTH);glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);glLightfv(GL_LIGHT0,GL_SPECULAR,specular);glLightfv(GL_LIGHT0,GL_POSITION,light_position);glEnable(GL_LIGHTING);glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST);void reshape(int w,int h){ glViewport(0,0,(GLsizei)w,(GLsizei)h); glMatrixMode(GL_PROJECTION);glLoadIdentity();if(w<=h)glOrtho(-12,12,-12*(GLfloat)(h)/(GLfloat)(w),12*(GLfloat)(h)/(GLfloat)(w), -1.0,1.0); }elseglOrtho(-12*(GLfloat)(w)/(GLfloat)(h),12*(GLfloat)(w)/(GLfloat)(h),-12,12,-1.0,1.0) JglMatrixMode(GL_MODELVIEW); glLoadIdentity();}void initDisplay(void){down=1; //向下运动glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);glLoadIdentity();glTranslatef(0.0,20.0,0.0);glutSolidSphere(0.4,40,50); glutSwapBuffers();}void display(void){ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity();glTranslatef(0,move,0.0); glutSolidSphere(0.4,40,50);glutSwapBuffers();}void MoveSphereUp(){end=clock();duration = (double)(end - start-16.0) /CLOCKS_PER_SEC;length=5*(timeSpan-duration)*(timeSpan-duration); move=20-length;if(move>19.932) {move=20;down=1;printf("%i",down);start=clock();}display();glLoadIdentity();}void MoveSphereDown(){if(count==1){start=clock();count=0;}end=clock();duration = (double)(end - start) /CLOCKS_PER_SEC;length=5*duration*duration;move=20-length;if(move<-20) {timeSpan=duration; //记下下降所经历的时间move=-20;start=clock();down=0; //向上运动}display();glLoadIdentity();}void TimerFunc2(int value){if(i==0){ //leftGLfloat light_position[]={2.0,0.0,0.0,0.0}; //r-l u-d f-bglLightfv(GL_LIGHT0,GL_POSITION,light_position);}if(i==1){ //left-upGLfloat light_position[]={2.0,2.0,0.0,0.0}; //r-l u-d f-bglLightfv(GL_LIGHT0,GL_POSITION,light_position);}if(i==2){ //upGLfloat light_position[]={0.0,2.0,0.0,0.0}; //r-l u-d f-bglLightfv(GL_LIGHT0,GL_POSITION,light_position);}if(i==3){ //up-rightGLfloat light_position[]={-2.0,2.0,0.0,0.0}; //r-l u-d f-bglLightfv(GL_LIGHT0,GL_POSITION,light_position);}if(i==4){ //rightGLfloat light_position[]={-2.0,0.0,0.0,0.0}; //r-l u-d f-bglLightfv(GL_LIGHT0,GL_POSITION,light_position);}if(i==5){ //right-downGLfloat light_position[]={-2.0,-2.0,0.0,0.0}; //r-l u-d f-bglLightfv(GL_LIGHT0,GL_POSITION,light_position);}if(i==6){ //downGLfloat light_position[]={0.0,-2.0,0.0,0.0}; //r-l u-d f-bglLightfv(GL_LIGHT0,GL_POSITION,light_position);}if(i==7){ //down-leftGLfloat light_position[]={2.0,-2.0,0.0,0.0}; //r-l u-d f-bglLightfv(GL_LIGHT0,GL_POSITION,light_position);}i=(++i)%8; //控制小球旋转的glutTimerFunc(60,TimerFunc2,1);}void TimerFunc1(int value){if(down==1){MoveSphereDown();}if(down==0){MoveSphereUp();}glutTimerFunc(10,TimerFunc1,0);}int main(int argc,char **argv){glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);glutInitWindowSize(400,740); glutInitWindowPosition(300,20);glutCreateWindow(argv[0]);init();glutDisplayFunc(initDisplay);glutReshapeFunc(reshape);glutTimerFunc(1400,TimerFunc1,0); //毫秒glutTimerFunc(400,TimerFunc2,1); // 毫秒glutMainLoop();return 0;}。
三维空间球体美术教案设计一、教学内容本次三维空间球体美术教案设计的主要内容为:教授学生如何在三维空间中绘制出球体。
包括球体的基本构造、轮廓线的绘制、阴影的表现以及颜色的运用等方面。
二、教学对象本次教学对象为初学者,适合从事美术创作的学生和从事相关专业的职业人员,对于进一步学习三维空间的其他知识和应用,具有较大的启示作用。
三、教学目标1.了解三维空间中球体的基本构造,能够准确判断球体的大小、位置和比例。
2.掌握球体轮廓线的绘制技巧,能够用准确的线条表现出球体的形态。
3.掌握阴影的表现方法,能够将球体立体感和光影感表现出来。
4.掌握颜色运用的规律,能够将色彩与球体的形态结合,营造出不同的效果。
四、教学重点1.球体的基本构造和比例2.球体轮廓线的绘制技巧3.阴影的表现方法4.颜色运用的规律五、教学难点1.如何在三维空间中准确地表现球体的比例和构造。
2.如何将色彩与球体的形态结合,达到最佳的艺术效果。
六、教学准备1.教学用品:铅笔、炭笔、橡皮、铅笔刀、红、黄、蓝、白、黑等颜料。
2.教学设备:黑板、项目投影仪、电脑。
3.教学环境:教室或绘画室。
七、教学步骤1.介绍三维空间球体的基本构造和比例,通过投影仪展示球体的图像,引导学生从不同角度观察三维空间球体。
2.通过实战演习,教授学生如何用铅笔和纸绘制球体的轮廓线。
重点讲解球体阴影的表现方法,让学生能够掌握球体的立体感和光影感的表现。
3.通过演习和配色练习,讲解颜色运用规律并实际操作,着重讲解球体在不同光照条件下的色彩变化以及如何调配颜料和色调来营造出不同的效果。
4.结合实际情境,让学生进行创意创作,通过教师的点拨和指导,鼓励学生将所掌握的知识应用到实践中去。
八、教学评估1.课堂互动评价:通过学生自由探讨和小组讨论等方式,评估学生对于本课程所掌握的知识的领会和理解。
2.演练表现评估:通过练习和演练的方式,检验学生的实际应用能力和创造力。
九、教学延伸1.讲解球体的相关知识和应用,如球体的切面分析等。
GIS专业实验报告(计算机图形学)实验8 使用opengl程序实现三维星球环绕效果一.实验目的及要求使用opengl程序实现三维星球环绕效果。
二.理论基础三维图形变换:三维图形变换包括三维几何变换和投影变换,通过它可由简单图形得到复杂图形,可以用二维图形表示三维对象。
三.算法设计与分析程序源码如下:#include <gl/gl.h>#include <gl/glu.h>#include <gl/glut.h>static GLfloat angle = 0.0, moon_angle = 0.0;void display(){glClearColor( 1.0, 1.0, 0.0, 0.0 );glShadeModel( GL_SMOOTH );glMatrixMode( GL_PROJECTION );glLoadIdentity();gluPerspective( 80.0, 1.0, 1.0, 50.0 );glMatrixMode( GL_MODELVIEW );glLoadIdentity();gluLookAt(8.0, 5.0, 8.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );//定义太阳的光照//发出白色的光{GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };GLfloat light_position[] = { 0.0, 0.0, 0.5, 1.0 };//最后一个参数为正数,表明是位置性光源glEnable( GL_LIGHT0 );glEnable( GL_LIGHTING );glEnable( GL_DEPTH_TEST );//定义太阳的材质//显红色GLfloat mat_ambient[] = { 0.3, 0.0, 0.0, 1.0 };GLfloat mat_emission[] = { 0.3, 0.0, 0.0, 1.0 };//绘制太阳glLightfv( GL_LIGHT0, GL_AMBIENT, light_ambient );glLightfv( GL_LIGHT0, GL_DIFFUSE, light_diffuse );glLightfv( GL_LIGHT0, GL_SPECULAR, light_specular );glLightfv( GL_LIGHT0 ,GL_POSITION, light_position );glMaterialfv( GL_FRONT ,GL_AMBIENT_AND_DIFFUSE, mat_ambient );glMaterialfv( GL_FRONT, GL_EMISSION, mat_emission );GLfloat ambient[] = { 0.2, 0.2, 0.2, 1.0 };glLightModelfv( GL_AMBIENT, ambient );glutSolidSphere( 2.0, 40, 40 );}//定制地球不发光,有材质{GLfloat mat_ambient[] = { 0.0, 0.0, 0.5, 1.0 };GLfloat mat_specular[] = { 0.0, 0.0, 1.0, 1.0 };GLfloat mat_shiness[] = { 30.0 };GLfloat mat_emission[] = { 0.0, 0.0, 0.1, 1.0 };glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_ambient );glMaterialfv( GL_FRONT, GL_SPECULAR, mat_specular );glMaterialfv( GL_FRONT, GL_EMISSION, mat_emission );glMaterialfv( GL_FRONT, GL_SHININESS, mat_shiness );glRotatef( angle, 0.0, 1.0, 0.0 );glTranslatef( 6.0, 0.0, 0.0 );glutSolidSphere( 0.5, 40, 40 );}//定制月球{GLfloat mat_ambient[] = { 0.2, 0.2, 0.2, 1.0 };GLfloat mat_specular[] = { 0.8, 0.8, 0.80, 1.0 };GLfloat mat_shiness[] = { 30.0 };GLfloat mat_emission[] = { 0.3, 0.3, 0.3, 1.0 };glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_ambient );glMaterialfv( GL_FRONT, GL_SPECULAR, mat_specular );glMaterialfv( GL_FRONT, GL_EMISSION, mat_emission );glMaterialfv( GL_FRONT, GL_SHININESS, mat_shiness );glRotatef( moon_angle, 0.0, angle, 1.0 );glTranslatef( 1.0, 0.0, 0.0 );glutSolidSphere( 0.3, 30, 30 );}glutSwapBuffers();}void idle(){angle += 0.5;moon_angle += 2.0;if ( angle > 360.0 ){angle = 0.0f;}if ( moon_angle > 360.0 ){moon_angle = 0.0;}glutPostRedisplay();}void menu( int id ){if ( id == 1 ){exit( 0 );}}int main( int argc, char ** argv ){glutInit( &argc, argv );glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE ); glutInitWindowPosition( 100, 100 );glutInitWindowSize(800, 450 );glutCreateWindow("模拟星球");glutDisplayFunc( display );glutIdleFunc( idle );glutCreateMenu( menu );glutAddMenuEntry( "Out", 1 );glutAttachMenu( GLUT_RIGHT_BUTTON );glutMainLoop();}四.程序调试及运行结果的自我分析与自我评价运行结果见下图1。
基于OpenGL的三维动画效果设计与实现OpenGL是一种跨平台的图形库,广泛应用于计算机图形学、游戏开发和虚拟现实等领域。
在OpenGL的基础上,可以实现各种精美的三维动画效果,如逼真的光影效果、自然的物理模拟和华丽的特效等。
本文将介绍如何基于OpenGL实现三维动画效果。
一、OpenGL简介OpenGL(Open Graphics Library)是一种跨平台的图形库,可以用于开发高性能的3D图形应用程序。
它提供了一套标准的API,程序员可以使用OpenGL库里的函数来绘制各种图形,包括点、线、三角形等。
OpenGL的主要优点是跨平台,程序可以在不同的操作系统和硬件上运行,并且不需要对程序做太多的修改。
二、OpenGL开发环境在开始OpenGL开发之前,需要配置正确的开发环境。
OpenGL的开发环境包括编程语言、OpenGL库、窗口系统和OpenGL的开发工具等。
编程语言:OpenGL支持多种编程语言,如C/C++、Java、Python等。
其中,C/C++是最常用的开发语言,因为它可以直接调用OpenGL的函数库。
OpenGL库:OpenGL库是开发OpenGL程序时必须的工具,它包含了OpenGL 的所有函数和常量。
窗口系统:OpenGL需要一个可视化的窗口系统,用来显示图形界面。
常用的窗口系统有Windows、Linux和MacOS等。
开发工具:开发OpenGL程序需要使用各种IDE和编辑器,如Visual Studio、CodeBlocks和Eclipse等。
三、实现三维动画效果的基础知识1.三维坐标系OpenGL使用右手坐标系表示三维坐标系,其中x轴向右,y轴向上,z轴向外。
2.矩阵变换OpenGL可以通过矩阵变换来实现图形的移动、旋转、缩放等操作。
常用的变换矩阵包括平移矩阵、旋转矩阵和缩放矩阵。
3.光照模型光照模型是OpenGL中重要的概念之一,它用来计算光源对物体的影响。
其中,主要包括光源的位置、光线的颜色和强度等因素。
在看OpenGL红皮书,看到生成球体这节,讲了很多,总感觉不如自己动手写一些代码来的实在,用OpenGL中三角形模拟球形生成.主要要点,模型视图变换,多边形表面环绕一致性,矩阵堆栈.先贴上代码.虽然是用F#写的,但是处理全是过程式的,很好理解.01 #r "F:\3D\1.0\Binaries\OpenTK\Debug\OpenTK.dll"02 #r "F:\3D\1.0\Binaries\OpenTK\Debug\OpenTK.GLControl.dll"0304open System05open System.Collections.Generic06open System.Windows.Forms07open System.Threading08open System.Drawing09open System.Drawing.Imaging010open OpenTK011open OpenTK.Graphics012open OpenTK.Graphics.OpenGL013014type loopForm() as form=015inherit Form()016let mutable x = 5.f017let mutable y = 5.f018let mutable z = 5.f019let offest = 1.f020let glControl = new OpenTK.GLControl()021let textX= new TextBox()022let textY= new TextBox()023let textZ= new TextBox()024let textLR = new TextBox()025let textUD= new TextBox()026let textInfo = new TextBox()027let labelX= new Label()028let labelY= new Label()029let labelZ= new Label()030let labelLR = new Label()031let labelUD= new Label()032let mutable first = 0033let mutable buffer = 0034let list = 0035let scale = 3.f036do037form.SuspendLayout()038glControl.Location <- new Point(10,40)039glControl.Size <- new Size(400,300)040glControl.BackColor <- Color.Red041glControl.Resize.Add(form.resize)042glControl.Paint.Add(form.paint)043form.MouseWheel.Add(form.MouseDown)044form.ClientSize <- new Size(600,400)045form.Text <- "opengl"046form.StartPosition <- FormStartPosition.Manual0 47form.Location <- new Point(1200,600)048form.Controls.Add(glControl)049form.ResumeLayout(false)050labelX.Location <- new Point(420,40)051labelY.Location <- new Point(420,70)052labelZ.Location <- new Point(420,100)053labelLR.Location <- new Point(420,130)054labelUD.Location <- new Point(420,160)055labelX.Text <- "X:" 056labelY.Text <- "Y:"057labelZ.Text <- "Z:"058labelLR.Text <- "水平:"059labelUD.Text <-"上下:"060textX.Location <- new Point(460,40)061textY.Location <- new Point(460,70)062textZ.Location <- new Point(460,100)063textLR.Location <- new Point(460,130)064textUD.Location <- new Point(460,160)065textInfo.Location <- new Point(420,190)066textInfo.Width <- 140067form.Controls.Add(textX)068form.Controls.Add(textY)069form.Controls.Add(textZ)070form.Controls.Add(textLR)071form.Controls.Add(textUD)072form.Controls.Add(labelX)073form.Controls.Add(labelY)074form.Controls.Add(labelZ)075form.Controls.Add(labelLR)076form.Controls.Add(labelUD)077form.Controls.Add(textInfo)078//#endregion 079override v.OnLoad e =080base.OnLoad e081GL.ClearColor Color.MidnightBlue082Application.Idle.Add(v.AIdle)083v.ShowUI 084textX.TextChanged.Add(form.TextChange)085textY.TextChanged.Add(form.TextChange)086textZ.TextChanged.Add(form.TextChange)087textLR.TextChanged.Add(form.TextChange)088textUD.TextChanged.Add(form.TextChange)089//踢除正反面090//GL.Enable EnableCap.CullFace091//GL.CullFace CullFaceMode.Back092//指定正反面093GL.FrontFace w094//设置材料面填充模式095GL.PolygonMode(MaterialFace.Front,PolygonMode.Fill)096GL.PolygonMode(MaterialFace.Back,PolygonMode.Line) 097//启用数组功能.098GL.EnableClientState(ArrayCap.VertexArray)099//GL.EnableClientState(ArrayCap.ColorArray)0100GL.EnableClientState(ArrayCap.IndexArray)0101//#region ""0102member v.resize (e:EventArgs) =0103GL.Viewport(0,0,glControl.ClientSize.Width,glControl.ClientSize.Height) 0104let aspect = float32 glControl.ClientSize.Width /float32glControl.ClientSize.Height0105let mutable projection =Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4,aspect,0.1f,64.f) 0106GL.MatrixMode MatrixMode.Projection0107GL.LoadMatrix(&projection)0108member v.paint (e:PaintEventArgs) =0109v.Render()0110member v.AIdle (e:EventArgs) =0111while (glControl.IsIdle) do0112v.Render()0113member v.TextChange (e:EventArgs) =0114x <- v.UIValue(textX)0115y <- v.UIValue(textY)0116z <- v.UIValue(textZ)0117member v.MouseDown(e:MouseEventArgs) =0118match v.ActiveControl with0119| :? TextBox as t1 -> 0120let mutable t = v.UIValue(t1)0121t <- t + float32 e.Delta * offest * 0.01f0122t1.Text <- t.ToString()0123| _ -> 0124v.Text <- v.ActiveControl.Text0125let state =float32 e.Delta * offest * 0.01f0126x<- x+state0127y<- y + state0128z <- z + state0129v.ShowUI0130member x.UIValue0131with get (text:TextBox) = 0132let mutable value = 0.f0133if System.Single.TryParse(text.Text,&value) then0 134value <- value0135value0136and set (text:TextBox) (value:float32) = text.Text<- value.ToString() 0137member v.ShowUI =0138textX.Text <- x.ToString()0139textY.Text <- y.ToString()0140textZ.Text <- z.ToString()0141textLR.Text <- v.UIValue(textLR).ToString()0142textUD.Text <- v.UIValue(textUD).ToString()0143member v.Normal (c:Vector3) =0144 c.Normalize() 0145 c * scale0146member v.Subdivide (v1:Vector3,v2:Vector3,v3:Vector3) =0 147let vs = Array.create 6 Vector3.Zero0148vs.[0] <- v10149vs.[1] <- v.Normal( Vector3.Lerp(v1,v2,0.5f))0150vs.[2] <- v.Normal( Vector3.Lerp(v3,v1,0.5f))0151vs.[3] <- v20152vs.[4] <- v.Normal( Vector3.Lerp(v2,v3,0.5f))0153vs.[5] <- v30154let is = Array.create 1200155is.[0] <- 00156is.[1] <- 10157is.[2] <- 20158is.[3] <- 20159is.[4] <- 10160is.[5] <- 40161is.[6] <- 40162is.[7] <- 10163is.[8] <- 30164is.[9] <- 20165is.[10] <-40166is.[11] <- 50167(vs,is)0168//#endregion 0169member v.CreatePane (angle:float32,x,y,z) =0170GL.PushMatrix()0171GL.Color3(Color.Green)0172GL.Rotate(angle,x,y,z)0173let mutable vv =[|Vector3.UnitY*scale;Vector3.UnitZ*scale;Vector3.UnitX*scale|]0174let mutable iv = [|0;1;2|]0175//let show array = printfn "%A" array0176let mutable t =int (v.UIValue(textInfo))0177if t > 6then0178t <- 60179elif t < 0then0180t <- 00181for j in0 .. t do0182let mutable av = Array.create 0 Vector3.Zero0183let mutable ev = Array.create 000184for i in0 .. 3 .. iv.Length - 1do0185let (vvv,iiv) =v.Subdivide(vv.[iv.[i]],vv.[iv.[i+1]],vv.[iv.[i+2]])0186let length = av.Length0187av <- Array.append av vvv0188let map = iiv |> Array.map (fun p -> p + length)0 189ev <- Array.append ev map0190vv <- av0191iv <- ev 0192//show vv0193//show iv0194GL.VertexPointer(3,VertexPointerType.Float,0,vv) 0195GL.DrawElements(BeginMode.Triangles,iv.Length,DrawElementsType.UnsignedInt, iv)0196GL.PopMatrix() 0197member v.Render =0198let mutable lookat = Matrix4.LookAt(newVector3(x,y,z),Vector3.Zero,Vector3.UnitY)0199GL.MatrixMode(MatrixMode.Modelview)0200GL.LoadMatrix(&lookat) 0201GL.Rotate(v.UIValue(textLR),0.f,1.f,0.f)0202GL.Rotate(v.UIValue(textUD),1.f,0.f,0.f)0203GL.Clear(ClearBufferMask.ColorBufferBit |||ClearBufferMask.DepthBufferBit)0204GL.Color3(Color.Green)0205v.CreatePane(0.f,0.f,1.f,0.f)0206v.CreatePane(90.f,0.f,1.f,0.f)0207//v.CreatePane(180.f,0.f,1.f,0.f)0208glControl.SwapBuffers()0209ignore0210let t = new loopForm()0211 t.Show() 0首先我们设定逆时针方向为正方向,分别设定正面为画布填充,反面为线填充,这样我们就能很容易知道我们生成的三角形倒底是不是正确生成的我们要的面向.0然后分别取用顶点数组和顶点数组索引功能.毕竟后面的点多,一个一个去组装没这个脑力,还没性能.0如何用三角开来模拟生成球面,方法肯定很多种,这里我们可以想象下,在坐标轴的原点就是球的原点,半径为1,被X,Y,Z轴分成八个部分,我们找到正右上的那边,与X,Y,Z轴的交点分别为x1(1,0,0),y1(0,1,0),z1(0,0,1).0然后我们把x1,y1,z1连起来画一个三角形.注意这里就有顺序了,想像一下,三个点的位置,要画正面是用逆时针方向,一算,x1,y1,z1这个方向就是,但是通常为了形象些,我们从y1上开始画,然后是前z1,然后是右x1.如代码是这样0let m utable vv = [|Vector3.UnitY*scale;Vector3.UnitZ*scale;Vector3.UnitX*scale|] let m utable iv = [|0;1;2|]0然后就是细分这三角形,过程就是这样,一个三角形分成四个.在for j in 0 .. t 这里,t越多,分的就越多,t是0,分一次成四个,t是1,四个再分别分成四个,就是16个.最后总的三角形就是4的t+1次方.0细分算法,大致如下,已知球面上二点,a1,a2,求在这球二点中间点ax.0已知球心在中间,得知,三个向量有如下关系,向量ax = (向量a2-向量a1)*0.5 + 向量a1.这样可以算到向量a1,那点ax就是向量a1*半径.0当一个三角形分成几个三角形,也就是三个顶点变成六个顶点,那么生成生成三角形的索引也要重新更新.具体过程用图来说明.0分的越细,球面越光滑,这样只生成了八分之一的球面,后面的如何画了,前面讲了矩阵堆栈的用法,刚好可以用在这样能在我方便生成另外几个面,v.CreatePane(90.f,0.f,1.f,0.f)这个是我们绕Y轴90度后,生成另外的一个面,为了不破坏全局坐标,我们可以在转之前调用PushMatrix记住当前矩阵,画完后再用PopMatrix回到当前矩阵.0看一下程序运行后的效果图.界面上的X,Y,Z指向人眼的位置,左右与上下指旋转方向.最下面指细分的程度,值越大,细分的越厉害.0大家可以把顶点索引变下顺序,然后再来看下效果,也可以把余下的六面全部补起.。
游戏软件设计课程报告(三维球体的实现)院系:专业:学号:姓名:指导教师:2010年10月10日目录目录一、应用程序的最终界面----------------------------------------------------------------1二、三维球体的绘制---------------------------------------------------------------------21、球体绘制方法研究 ----------------------------------------------------------------22、面分解法的实现----------------------------------------------------------------32.1面分解函数 ----------------------------------------------------------------32.2初值的选取 ----------------------------------------------------------------32.3 球体的实现----------------------------------------------------------------43、三角形绘制函数----------------------------------------------------------------44、三角面法向量函数 ----------------------------------------------------------------55、点的模长扩展函数 ----------------------------------------------------------------56、南北极法的实现----------------------------------------------------------------57、动画的实现-------------------------------------------------------------------10三、二种绘制方法的比较---------------------------------------------------------------12一、应用程序的最终界面一、应用程序的最终界面本OpenGL应用程序的最终界面主要由二部分构成,其一是参数控制栏,其二是视图显示窗。
1中文摘要本次课程设计采用OpenGL来完成。
OpenGL是个定义了一个跨编程语言、跨平台的编程接口的规格,它用于三维图象(二维的亦可)。
OpenGL是个专业的图形程序接口,是一个功能强大,调用方便的底层图形库。
本次课程设计是在win7系统下VC++6.0中的win32环境中,通过使用OpenGL所提供的标准库函数,综合图形学里的坐标转换,投影变换,光照以及纹理等知识,实现一个简单的太阳系的运行状况。
该系统仅做演示使用,将只包括太阳,地球与月亮,并且不保证相关数据的设定准确性。
目录一、课程设计任务及要求 (1)二、需求分析 (1)三、系统设计 (1)四、详细设计 (3)4.1 初始化的设定 (3)4.2 光源的位置与观察位置的设定 (4)4.3 纹理映射的设置 (5)4.4 各星球球体的绘制 (7)4.5 星球公转轨道 (9)4.6 人机交互式的实现 (10)五、运行调试与分析讨论 (12)5.1 程序运行截图 (12)5.2 结果分析 (13)六、设计体会与小结 (14)七、参考文献 (16)一、课程设计任务及要求1.利用OpenGL创建太阳,地球,月亮三个球体。
2. 实现“月亮绕着地球转,地球绕着太阳转”。
3. 为太阳,地球,月亮附上不同的纹理。
4. 具有较好的动画效果,消除闪烁现象。
5. 其他功能的添加。
二、需求分析本次课程设计使用的编译软件为Visual C++ 6.0。
设计中通过调用OpenGL函数库以来完成太阳,月亮,地球的球体绘制与纹理的加载,通过矩阵的变换以实现星球的运动效果。
从而模拟出太阳系的运行效果动画。
在之后,加入星球的轨道轨迹,使得模拟系统3D效果更加明显。
并加入人机交互操作。
通过“q,w,e,s,a,d”键来调整观察视角,可以实现全方位对此系统进行观察,使系统具有一定的可操作性。
三、系统设计本次课题为:实现太阳系运行动画。
系统设计步骤为:1.太阳,地球,月亮三个球体的创建。
Opengl绘制我们的⼩屋(⼀)球体,⽴⽅体绘制这个系列我想⽤来运⽤opengl红⽪书的前⼋章节的内容,来打造⼀个室内⼩屋.这⼀章主要是定义⼏个基本的结构.并给出球体与⽴⽅体的画法,先让我们来定义⼀些基本的结构.⼀个是包含点,法向量,纹理贴图向量,⼆是矩形与圆形的⽗类,包含⼀些基本公有的处理. 1type T2N3V3 =2struct3val mutable TexCoord : Vector24val mutable Normal : Vector35val mutable Position : Vector36new(v,n,p) = {TexCoord = v;Normal = n;Position = p}7end8 [<AbstractClass>]9type Shape() =10let mutable bCreate = false11let mutable vi = 012let mutable ei = 013let mutable count = 014member this.vboID with get() = vi and set value = vi <- value15member this.eboID with get() = ei and set value = ei <- value16member this.TriangelCount with get() = count and set value = count <- value17member this.IsCreate with get() = bCreate and set value = bCreate <- value18abstract Draw : unit -> unit19abstract Init : unit -> unit20member this.InitQ : unit -> unit =fun () -> ()View Code然后是球体的画法,相关具体过程如上篇,先贴上代码,我会对其中⼀些做些说明.1type Sphere(radius:float32,level:int) =2inherit Shape()3let mutable rad,lev = radius,level4let RightLevel =5if lev < 0then lev <- 06 elif lev > 6then lev <-67override this.Draw() =8if this.IsCreate<>true then this.Init()9 GL.BindBuffer(BufferTarget.ArrayBuffer,this.vboID)10 GL.BindBuffer(BufferTarget.ElementArrayBuffer,this.eboID)11 GL.InterleavedArrays(InterleavedArrayFormat.T2fN3fV3f,0,IntPtr.Zero)12 GL.DrawElements(BeginMode.Triangles,this.TriangelCount,DrawElementsType.UnsignedInt,IntPtr.Zero)13override this.Init() =14let alls = Array.create 6 (new T2N3V3())15 alls.[0] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), Vector3.UnitX, Vector3.UnitX * rad )16 alls.[1] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), Vector3.UnitY, Vector3.UnitY * rad )17 alls.[2] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), Vector3.UnitZ, Vector3.UnitZ * rad )18 alls.[3] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), -Vector3.UnitX, -Vector3.UnitX * rad )19 alls.[4] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), -Vector3.UnitY, -Vector3.UnitY * rad )20 alls.[5] <- new T2N3V3(new Vector2( 0.0f, 0.0f ), -Vector3.UnitZ, -Vector3.UnitZ * rad )21let is = [|221;2;0230;2;4240;4;5255;1;0261;3;2274;2;3284;3;5291;5;330 |]31let (vvv:T2N3V3 []),(iv: int[]) = this.Sub (alls,is)32let mutable vID,eID = 0,033//let mutable tv,vv,pv = vvv |> Array.map (fun v -> v.TexCoord,v.Normal,v.Position) |> Array.unzip334 GL.GenBuffers(1,&vID)35 GL.BindBuffer(BufferTarget.ArrayBuffer,vID)36 GL.BufferData(BufferTarget.ArrayBuffer,IntPtr (4 * 8 * vvv.Length),vvv,BufferUsageHint.StaticDraw)3738 GL.GenBuffers(1,&eID)39 GL.BindBuffer(BufferTarget.ElementArrayBuffer,eID)40 GL.BufferData(BufferTarget.ElementArrayBuffer,IntPtr (4 * iv.Length),iv,BufferUsageHint.StaticDraw)4142 this.vboID <- vID43 this.eboID <- eID44 this.TriangelCount <- iv.Length45 this.IsCreate <- true46 ()47member v.GetMidValue (first:T2N3V3,second:T2N3V3) =48let midN = Vector3.Lerp(first.Position,second.Position,0.5f) |> Vector3.Normalize49let midP = midN *(float32 rad)50let midT = Vector2.Lerp(first.TexCoord,second.TexCoord,0.5f) |> Vector2.Normalize51let result = new T2N3V3(midT,midN,midP)52 result53member v.Subdivide (v1:T2N3V3,v2:T2N3V3,v3:T2N3V3) =54let vs = Array.create 6 (new T2N3V3())55 vs.[0] <- v156 vs.[1] <- v.GetMidValue(v1,v2)57 vs.[2] <- v.GetMidValue(v3,v1)58 vs.[3] <- v259 vs.[4] <- v.GetMidValue(v2,v3)60 vs.[5] <- v361let is = Array.create 12062 is.[0] <- 063 is.[1] <- 164 is.[2] <- 265 is.[3] <- 266 is.[4] <- 167 is.[5] <- 468 is.[6] <- 469 is.[7] <- 170 is.[8] <- 371 is.[9] <- 272 is.[10] <-473 is.[11] <- 574 (vs,is)75member this.Sub(alls:T2N3V3 [],is:int []) =76//let mutable tv,vv,pv = alls |> Array.map (fun v -> v.TexCoord,v.Normal,v.Position) |> Array.unzip377let mutable allv = alls78let mutable iv = is79let show array = printfn "%A" array80for j in0 .. lev do81let mutable av = Array.create 0 (new T2N3V3())82let mutable ev = Array.create 0083 printfn "%i" allv.Length84 printfn "%i" iv.Length85for i in0 .. 3 .. iv.Length - 1do86let (vvv,iiv) = this.Subdivide(allv.[iv.[i]],allv.[iv.[i+1]],allv.[iv.[i+2]])87let length = av.Length88 av <- Array.append av vvv89let map = iiv |> Array.map (fun p -> p + length)90 ev <- Array.append ev map91 allv <- av92 iv <- ev93 allv |> Array.map (fun p -> p.Position) |> show94 show iv95 allv,ivView Code初始化需要的⼆个参数,分别代表球的⼤⼩(radius),与画的细分程度(level).其中相关如何绘制球体代码在上⽂有讲,相当于有是把⼀个分别位于x,y,z各(+radius,-radius)这六个点,组成的⼀个⼋个三⾓形,索引点的位置如Init⾥GL.InterleavedArrays(InterleavedArrayFormat.T2fN3fV3f,0,IntPtr.Zero)其中的T2fN3fV3f对应于我们的数据结构T2N3V3,这个函数分别相当于指定GL.TexCoordPointer,GL.NormalPointer,GL.VertexPointer(还会打开相应状态),会⾃动给我们处理好,我们也可以只指定顶点,如下GL.VertexPointer(3,VertexPointerType.Float,4*8,IntPtr (4*8-4*5)),这些数据之间的间隔对应与我们前⾯写⼊的GL.BufferData(BufferTarget.ArrayBuffer,IntPtr (4 * 8 * vvv.Length),vvv,BufferUsageHint.StaticDraw)其中vvv是T2N3V3的结构.基本的GL.BindBuffer的对应的三个处理就不细说了,在Draw⾥,BindBuffer是指定我们当前格式数据在存储位置,然后分别调⽤InterleavedArrays设定各顶点的状态,然后是调⽤DrawElements对应上⾯的GL.BindBuffer(BufferTarget.ElementArrayBuffer,this.eboID)处理.然后是⽴⽅体的绘制,其中⽴⽅体的绘制⽤的⽅法看起来会容易理解.如下1type Cube(width:float32,height:float32,length:float32,index:int) =2inherit Shape()3let mutable id = index4let xl,yl,zl =width/2.f,height/2.f,length/2.f5let mutable color = Color.White6let v8 = [|7new Vector3(xl,yl,zl)8new Vector3(-xl,yl,zl)9new Vector3(-xl,-yl,zl)10new Vector3(xl,-yl,zl)11new Vector3(xl,yl,-zl)12new Vector3(-xl,yl,-zl)13new Vector3(-xl,-yl,-zl)14new Vector3(xl,-yl,-zl)15 |]16new(x,y,z) =17let rnd = System.Random().Next()18 printfn "%i" rnd19 Cube(x,y,z,-1)20override this.Draw() =21if this.IsCreate<>true then this.Init()22 GL.EnableClientState(ArrayCap.VertexArray)23 GL.EnableClientState(ArrayCap.NormalArray)24 GL.BindBuffer(BufferTarget.ArrayBuffer,this.vboID)25 GL.VertexPointer(3,VertexPointerType.Float,0,IntPtr.Zero)26 GL.PushMatrix()27if id >= 0 && id < 8then28 GL.Translate(v8.[id])29 GL.Color3(this.Color:Color)30 GL.Normal3(Vector3.UnitZ)31 GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|0;1;2;0;2;3|])32//GL.Color3(Color.Black)33 GL.Normal3(Vector3.UnitY)34 GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|4;5;1;4;1;0|])35//GL.Color3(Color.Red)36 GL.Normal3(Vector3.UnitX)37 GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|4;0;3;4;3;7|])38//GL.Color3(Color.Green)39 GL.Normal3(-Vector3.UnitY)40 GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|3;2;6;3;6;7|])41//GL.Color3(Color.Blue)42 GL.Normal3(-Vector3.UnitX)43 GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|1;5;6;1;6;2|])44//GL.Color3(Color.DodgerBlue)45 GL.Normal3(-Vector3.UnitZ)46 GL.DrawElements(BeginMode.Triangles,6,DrawElementsType.UnsignedInt,[|5;4;7;5;7;6|])47 GL.PopMatrix()48override this.Init() =49let mutable vID = 050 GL.GenBuffers(1,&vID)51 GL.BindBuffer(BufferTarget.ArrayBuffer,vID)52 GL.BufferData(BufferTarget.ArrayBuffer,IntPtr (4 * 3 * v8.Length),v8,BufferUsageHint.StaticDraw)53 this.vboID <- vID54 this.IsCreate <- true55let rnd = System.Random(this.GetHashCode())56 this.Color <- Color.FromArgb(rnd.Next(0,255),rnd.Next(0,255),rnd.Next(0,255))57 ()58member this.Index with get() = id and set value = id <-value59member this.Color with get() = color and set value = color <- valueView Code上图中的V8分别对应其中的0-7个顶点,GL.DrawElements后⾯的0;1;2;0;2;3分别是以三⾓形的画法来画⼀个正⽅形.⽴⽅体的画法主要是确定宽,⾼,长,我们这样定义,我们站在原点上,⾯向Z+轴,我们的⼿展开来表⽰X轴(对应宽度),⽽我们的⾝⾼表⽰Y轴(对应⾼度),和我们⾯向距离的长远来表⽰Z轴,(对应长度).绘制也是8个⾯,和上⾯⼀样,也是在缓存中记录顶点,但是不⼀样的是,顶点索引是在绘制时没有⽤到顶点索引缓存,主要考虑后⾯有法向量的处理,还有现在没有加上的纹理贴图的处理.在这⾥,我们要特别注意,顶点顺序问题,在opengl,默认正⾯是逆时针,⽽我们可以看0;1;2;0;2;3对应图上的顺序.然后⼤家可能会发现,画⽴⽅体的后⾯5;4;7;5;7;6,这个顺序好像不对,是顺时针的.⼤家可以想象下,我们在门外看门的逆时针画法与我们在门内看门外顺时针的画法是⼀样的.所以如果我们要画后⾯4,5,6,7我们以为的是逆时针是不对的,我们要想象我们在那边来看,然后再画,应该是5,4,7,6这个⽅向.其中纹理贴图后⾯会说,和这处理也有类似.在上⾯,我们看到我们都没对顶点的颜⾊来定义,这⾥没必要,因为后⾯我们肯定要⽤到灯光,⽤到灯光的话,设置的颜⾊都没⽤,我们会⽤到灯光颜⾊与材质的颜⾊.纹理贴图也有没对应处理,这⾥在后⾯我会根据讲到再来改写相关处理.下⼀节,主要是讲第⼀⼈称漫游的相关处理.。
(计算机图形学)实验报告实验名称使用open GL在绘制球体的基础上增加光照和材质设置实验时间年月日专业班级学号:姓名:成绩教师评语:一、实验目的1、了解并学习open GL的编程;2、掌握在open GL生成图形的基本思想和基本步骤;3、使用open GL具体生成简单的三维立体图形;4、在生成的三维立体的图形上面增加光照和材质的设置。
二、实验原理在上一个实验的基础上,对绘制出来的球体进行光照和材质的设置使其看起来更有立体感,其中对我们有以下几条要求:1、理解环境光,漫反射光和镜面反射光的光照模型2、理解phong光照模型,熟练掌握opengl中设置光照的方法3、掌握材质的设置方式一.材质的指定材质和灯光一样有三种属性:环境属性,漫反射属性和镜面反射属性,这些属性确定了材质反射灯光的多少。
设置材质和设置光照很相似,设置材质的函数是glMaterial*()glMaterial{if}v(face, pname, value)face :指明对物体的哪些面进行材质设置GL_FRONTGL_BACKGL_FRONT_AND_BACKPname:要设置的材质属性GL_AMBIENT 设置材料的环境颜色GL_DIFFUSE 设置材料的漫反射颜色GL_SPECULAR 设置材料的镜面反射颜色GL_AMIBIENT_AND_DIFFUSE 设置材料的环境和漫反射颜色GL_SHININESS 设置镜面指数GL_EMISSION 设置材料的发散颜色GL_COLOR_INDEXES 设置环境,漫反射和镜面反射的颜色索引1.通常,GL_AMBIENT 和GL_DIFFUSE 都取相同的值,可以达到比较真实的效果。
使用GL_AMBIENT_AND_DIFFUSE 可以同时设置 GL_AMBIENT 和 GL_DIFFUSE属性。
2.GL_SHININESS属性。
该属性只有一个值,称为“镜面指数”,取值范围是 0到128。
游戏软件设计课程报告(三维球体的实现)院系:专业:学号:姓名:指导教师:2010年10月10日目录目录一、应用程序的最终界面----------------------------------------------------------------1二、三维球体的绘制---------------------------------------------------------------------21、球体绘制方法研究 ----------------------------------------------------------------22、面分解法的实现----------------------------------------------------------------32.1面分解函数 ----------------------------------------------------------------32.2初值的选取 ----------------------------------------------------------------32.3 球体的实现----------------------------------------------------------------43、三角形绘制函数----------------------------------------------------------------44、三角面法向量函数 ----------------------------------------------------------------55、点的模长扩展函数 ----------------------------------------------------------------56、南北极法的实现----------------------------------------------------------------57、动画的实现-------------------------------------------------------------------10三、二种绘制方法的比较---------------------------------------------------------------12一、应用程序的最终界面一、应用程序的最终界面本OpenGL应用程序的最终界面主要由二部分构成,其一是参数控制栏,其二是视图显示窗。
如下图如示。
当通过左边的控制面板来修改球体参数时,右边的视图窗口即会显示出用户操作所产生的效果。
球体参数控制面板动态球体效果显示二、三维球体的绘制1、球体绘制方法研究OpenGL 绘制几何图形,本人认为关键的一步在于建立物体的几何模型。
我们通过不同的规则来对同一个物体建模,将会得到很不相同的结果。
把物体的模型建设好,即能用数学表达式来表达或说构建出一个物体,那么用OpenGL 将其画出来或说表达出来,将不会是一件很困难的事情。
如何建立球体模型呢?由于我们实际的生活经验不难发现,地球可以抽象为一个理想的球体,而地球的定位一般是通过经度纬度值。
也就是说只要有二个参数就基本上可以确定一个球体上的点的几何位置。
基于此,首先可用经纬特征来构建一个球体模型。
假想好球体也分为南北二极,再选取一个点为经度的零点,这样便可以把球体想成是由很多的水平圆和竖直圆来包围着的。
而这些圆与圆的交点就构造出了很多的小平面,我们画球的目的就是要将这些小平面一个个画出来。
每个小平面再分为二个三角面,这样使每个经纬相交的点对应着二个小三角面。
4个顶点由经纬度是容易确定的,从而2个小三角面也就易于在OpenGL 中勾画出来。
如下图所示:当然,像球这样规则的几何体还有一个更普通的建模方法,在此简称为面分解法:即是先想像出构造出该物体的最小单元,由此画出逼近物体最粗糙或说最失真的图形。
再由该最失真图形一步步细化,从而慢慢逼近最真实的图形。
球体可以想像是由很多的小三角面构成,球体最粗糙的图形可以认为是一个正4面体,它的面分解法原理是将每个三角面分再分为更小的三角面,其过程表述如下:取初始三角形三边上的中点,将该三点模长扩展为球体半径长度,再将原始三点与现在三点结合,构成了4个小三角形。
其图形表示如下:纬线1纬线2经线1经线2图:每个交点对应二个小三角面V PP1 P2 P3 P4P1P2P3 P12 P312、面分解法的实现2.1面分解函数参数v1,v2,v3为初始三角面的三个顶点向量,count记录当前要分解的级数,也就是当前该面要进行等分的次数。
若count = 0,则不需要等分,而直接以初始三个顶点画三角面。
若count = 1,则要等分一次,若count = 2,则要进行二次等分,最终该原始三角面将被分为1*4*4 = 16个。
依次类推。
程序实现代码如下:void CVRworkView::SubDivide(float *v1, float *v2, float *v3, int count){//count为等分级数if(0 >= count) //count=0,则画由三点构成的三角形{DrawTriangle(v1,v2,v3);}else{GLfloat v12[3],v23[3],v31[3];GLint i;for(i = 0; i < 3; i++){v12[i] = (v1[i]+v2[i])/2; //求取等分的中点坐标v23[i] = (v2[i]+v3[i])/2;v31[i] = (v3[i]+v1[i])/2;}Normalize(v12,(float)m_nRadius); //将所得中点进行模长扩展Normalize(v23,(float)m_nRadius);Normalize(v31,(float)m_nRadius);SubDivide(v1,v12,v31,count-1); //对所产生的4个新的三角面再进行等分SubDivide(v2,v23,v12,count-1);SubDivide(v3,v31,v23,count-1);SubDivide(v12,v23,v31,count-1);}}2.2初值的选取2.1介绍的是针对一个普通面的分解办法,进行其操作的前提是要已知经初始的三个顶点。
实际中初始面(初始图形)的设计是有一定艺术水平的。
初始图形构造的好,不仅图形的空间位置易于确定,而且也容易构造出更逼真的图形。
在一般的参考书上,球体的初始图形是一个正20面体,当然,这是一个很好的办法。
但在本次设计中,球体的初始图形设置为由6个点构成的8面体,之所以这样做,是因为这样更有利于理解球体图形的生成,而且这样也方便确定各点的空间坐标。
所构成的图形如下图所示述:初始的六个点都取自于坐标轴,关于原点对称地在各坐标轴上取二点,从而易写出一个适合坐球体初始图形的各点的坐标如下:P1(r, 0, 0),P2(-r, 0, 0)P3(0, 0, r),P4(0, 0, -r)P5(0, r, 0),P6(0, -r, 0)2.3 球体的实现void CVRworkView::DrawGeometry(){GLfloat r = (GLfloat)m_nRadius;GLfloat vdata[6][3] = { //初始点坐标{r,0.0,0.0},{-r,0.0,0.0},{0.0,r,0.0},{0.0,-r,0.0},{0.0,0.0,r},{0.0,0.0,-r}};GLuint tindices[8][3] = { //初始面的构造{2,4,0},{2,0,5},{2,5,1},{2,1,4},{3,0,4},{3,5,0},{3,1,5},{3,4,1}};for(int i = 0; i < 8; i++){ //绘制球体SubDivide(&vdata[tindices[i][0]][0],&vdata[tindices[i][1]][0],&vdata[tindices[i][2]][0],m_nCount);}}3、三角形绘制函数void CVRworkView::DrawTriangle(float *v1, float *v2, float *v3) {//以三点为顶点画三角形GLfloat normal[3] = {0,0,0};NormalTriangle(v1,v2,v3,normal); //求取面法向量glBegin(m_nPattern);glNormal3fv(normal);glVertex3fv(v1);glVertex3fv(v2);glVertex3fv(v3);glEnd();} X4、三角面法向量函数经验认为,画图时面法向量的方向判定是很关键的。
有时,所画出的图形经常看到黑白相间,使不当显示的地方却能够被人眼所看到,那么这类问题一般都是因为法向量的方向计算有误。
void CVRworkView::NormalTriangle(float *v1, float *v2, float *v3, float *vout){//求三点构成的三角形面的法向量GLfloat v12[3],v23[3];for(int i = 0; i < 3; i++){v12[i] = v2[i] - v1[i];v23[i] = v3[i] - v2[i];}vout[0] = v12[1]*v23[2] - v12[2]*v23[1];vout[1] = -(v12[0]*v23[2] - v12[2]*v23[0]);vout[2] = v12[0]*v23[1] - v12[1]*v23[0];Normalize(vout,1);}5、点的模长扩展函数当细分三角面的时候,求取中点之后还需要将该中点的模长扩展为球半径的长度,这样才会使新增的点属于球体面上的点,从而画的图形才不会失真,不会有突高突低的形状。
扩展模长的方法很简单,即是使点的失量方向不改变,只增大其模长。
代码如下述:void CVRworkView::Normalize(float *v, float radius){//向量的标准化,以模长为radius进行标准化GLfloat d = (GLfloat)sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);if(d == 0.0){return ;}v[0] /= d; v[1] /= d; v[2] /= d;v[0] *= radius; v[1] *= radius; v[2] *= radius;}6、经纬度法的实现按一定的角度分解出单位纬度,然后再按一定的角度分解出单位经度,由此可得画小三角面的循环次数以及各点上的经纬值,从而可画出图形。