在上文中,讲述了PyOpenGL的基本配置,以及网格,球形的生成,以及基本的漫游。现在利用上一篇的内容,来利用高程图实现一个基本的地形,并且,利用上文中的第三人称漫游,以小球为视角,来在地形上前后左右漫游,能实时检测高度。下面先看下效果图:

二张图,球分别在不同的地方,不同的显示模型,一个是全填充的,一个是线连,可以从中看到一些基本的思路。大致过程分别如下,首先拿到一张高度图,检索其中的高度对应的通道的值,然后用来改变网格的高度。这个过程只需要在初始化时生成就行了,所以我们可以简单的用CPU来完成这个。然后是球体的漫游,这部分在上文中已经讲了第一与第三人称漫游,用的就是其中的第三人称作漫游,在这里,我们主要是要检索球下面的地形的高度,因为需要实时计算,这部分用GPU来完成。

我们先看下,根据高度图来改变网格高度的相关代码(请对照前文中的网格类Plane来看,下面的setHeight为其中的一个方法):

1 def setHeight(this,image):2 ix = image.size[0]3 iy = image.size[1]4 this.heightImage =image5 print ix,iy6 #print "xr,yr",this.xr,this.yr7 lerp = lambda a,b,d:a * d + b * (1.0 -d)8 fade = lambda t : t*t*(3.0-2.0*t) #t*t*t*(t*(t*6.0-15.0)+10.0)9 for y in range(this.yr):10 for x in range(this.xr):11 index = 5 * (this.xr * y + x) + 3

12 #print index13 fx = float(x) / float(this.xr - 1) * float(ix - 1)14 fy = float(y) / float(this.yr - 1) * float(iy - 1)15 #print float(x) / float(this.xr - 1),fx,float(y) / float(this.yr - 1),fy16 xl,xr,yu,yd = int(math.floor(fx)),int(math.ceil(fx)),int(math.floor(fy)),int(math.ceil(fy))17 dx,dy = fade(fx - xl),fade(fy -yu)18 #print "loc:",xl,xr,yu,yd,dx,dy19 #left up,right up,left down,right down20 lu,ru,ld,rd = image.im[ix * yu + xl],image.im[ix * yu + xr],image.im[ix * yd + xl],image.im[ix * yd +xr]21 #print ix * yu +xl,lu,ru,ld,rd22 hight =lerp(lerp(lu,ru,dx),lerp(ld,rd,dx),dy)23 this.data[index] = hight / 255.0

24 #print "setHeight:",hight / 255.0

检索高度图

当初完成这段代码后,我有时后悔在前面学习noise时,没有自己先完成一个根据高度图生成地形,不然理解柏林噪声函数会是一件非常简单的事,这段代码很简单,得到image的信息,然后把原来的地形网格他们二个做一个映射关系,就好像二个大小不同的矩阵,根据其中一个在本矩阵里的位置,找出在另一个矩阵中对应的位置。首先index得到的是当初位置网络数据里的高度索引,第前面文章中,这个值是0,然后根据线性关系,就如上面后说,找到当前位置对应在image的位置,fx,fy.为什么我说很后悔先看了noise,大家可以看下,这里的代码的逻辑和noise里的就是一样,但是这里我可以自己推出来,而看noise里的过程花费太多不必要的时间。在这里,我们可以想象的到,fx,fy是整数的机会不大,那么无论取floor(fx)或ceil(fx),都有较大的偏差,正确的方法应该是根据fx的小数位来做floor(fx)或ceil(fx)权重进行计算。简单来说,就是根据fx,fy来取在它周围的四个像素点,然后根据他们的小数位来对四个小数点进行混合计算。其中小数部分需要的fade可以用lerp,也可以用二阶平滑来至三阶平滑的映射关系,而像素值根据简单线性关系求就可以了。理解这里的以后,再去看柏林噪声实践(一) 海波等就容易理解多了。

这个是初始化地形的高度值,下面就是重点,如果根据球所在的位置,来得到当前位置里的高度,然后用来设定球的高度(简化问题,只求球心下的高度,二片卡住球的问题就没考虑)。有了前面的基础,在CPU中进行得到高度值也很容易,但是现在是漫游过程中,当前位置每时都在计算,CPU应该用来进行更复杂的逻辑运算,这部分交给GPU了,先给出相关着色器代码:

1 update_v = """

2 //#version 330 compatibility

3 #version 130

4 uniform sampler2D tex0;5 uniform floatxw;6 uniform floatyw;7 uniform floatheight;8 //the location of center of the sphere

9 uniform vec2 xz;10 uniform floatsphereRadius;11 uniform mat4 mMatrix;12 uniform mat4 vMatrix;13 uniform mat4 pMatrix;14 outvec4 o_color;15 voidmain() {16 vec4 pos =vec4(gl_Vertex);17 vec2 uv = vec2(xz/vec2(xw,yw) + vec2(0.5,0.5));18 uv.y = 1.0 -uv.y;19 vec3 rgb =texture2D(tex0, uv).rgb;20 pos.y = pos.y + sphereRadius + rgb.r;//height;//21 o_color = vec4(uv.x, uv.y, rgb.r, 1);22 gl_Position = pMatrix * vMatrix * mMatrix *pos;23

24 //vec4 v = vec4(gl_Vertex);25 //vec2 uv = vec2(xz/vec2(xw,yw) + vec2(0.5,0.5)).xy;26 //uv.y = 1.0 - uv.y;27 //v.x = v.x + xz.x;28 //v.z = v.z + xz.y;29 //v.y = v.y + texture2D(tex0, uv).r+ sphereRadius;30 //o_color = vec4(uv.x,uv.y, 0, 1 );31 //gl_Position = gl_ModelViewProjectionMatrix * v;

32 }"""33

34 update_f = """35 //#version 330 compatibility

36 #version 130

37 invec4 o_color;38 voidmain() {39 //vec4 color = texture2D(tex1, gl_TexCoord[0].st);

40 gl_FragColor = o_color;//vec4( 0, 1, 0, 1 );

41 }"""

着色器检索高度

这段代码大致思想和前面一样,不过纹理坐标需要映射到0-1之前,不过,也少了混合周围定点的计算,因为我们在设定纹理时(glTexParameterf),已经告诉着色器,自动线性混合了。在这里,需要说明的是,因为130后,已经废弃了固定管线的相关功能与API,虽然还能用,但是毕竟要向前看,所以主体的部分有二部分,一部分是用的是着色器版本120固定管线提供的gl_ModelViewProjectionMatrix,以及120后的,自己提供MVP,也顺便练习下如何在PyOpenGL里进行矩阵的基本操作。其中height是CPU计算的高度,这个就放附件里,不拿出来说了,至于为什么还拿出一个CPU版,前面不是说了不交给CPU吗,主要是我发现,有些旧的显卡对于这段逻辑处理还是有些问题(有一问题浪费大量时间才发现是旧显卡的问题),代码就不放了,大家有兴趣可以去附件里看。

嗯,还有必要说下绘制部分,地形网络用到一个颜色纹理,而球需要用到高度纹理,在glsl中,多纹理,多着色器如何设定以及完成。

1 classallshader:2 def __init__(this):3 this.planeProgram =shaders.compileProgram(shaders.compileShader(plane_v, GL_VERTEX_SHADER),4 shaders.compileShader(plane_f, GL_FRAGMENT_SHADER))5 #the parameter tex0 must be use in shaders,otherwise the

6 #glGetUniformLocation get -1

7 this.planeProgram.tex0 = glGetUniformLocation(this.planeProgram,"tex0")8 this.planeProgram.tex1 = glGetUniformLocation(this.planeProgram,"tex1")9 printthis.planeProgram.tex0,this.planeProgram.tex110

11 this.updateProgram =shaders.compileProgram(shaders.compileShader(update_v, GL_VERTEX_SHADER),12 shaders.compileShader(update_f, GL_FRAGMENT_SHADER))13 this.updateProgram.xl = glGetUniformLocation(this.updateProgram,"xw")14 this.updateProgram.yl = glGetUniformLocation(this.updateProgram,"yw")15 this.updateProgram.height = glGetUniformLocation(this.updateProgram,"height")16 this.updateProgram.sphereRadius = glGetUniformLocation(this.updateProgram,"sphereRadius")17 this.updateProgram.tex0 = glGetUniformLocation(this.updateProgram,"tex0")18 this.updateProgram.xz = glGetUniformLocation(this.updateProgram,"xz")19 this.updateProgram.hight = glGetUniformLocation(this.updateProgram,"hight")20 this.updateProgram.mMatrix = glGetUniformLocation(this.updateProgram,"mMatrix")21 this.updateProgram.vMatrix = glGetUniformLocation(this.updateProgram,"vMatrix")22 this.updateProgram.pMatrix = glGetUniformLocation(this.updateProgram,"pMatrix")23

24

25 defDrawGLScene():26 glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT)27 glMatrixMode(GL_MODELVIEW)28 camera.setLookat()29 #texture set

30 glActiveTexture(GL_TEXTURE0)31 glBindTexture(GL_TEXTURE_2D, colorMap)32 glActiveTexture(GL_TEXTURE1)33 glBindTexture(GL_TEXTURE_2D, hightMap)34 #plane

35 glUseProgram(shaderall.planeProgram)36 glUniform1i(shaderall.planeProgram.tex0, 0)37 plane.draw()38 glUseProgram(0)39 #sphare

40 eyeLoc =camera.origin41 uv = eyeLoc[0] / plane.xl + 0.5,eyeLoc[2] / plane.yl + 0.5

42 glUseProgram(shaderall.updateProgram)43 glUniform1f(shaderall.updateProgram.xl, plane.xl)44 glUniform1f(shaderall.updateProgram.yl, plane.yl)45 #CPU compute height

46 #glUniform1f(shaderall.updateProgram.height, plane.getHeight(eyeLoc[0],eyeLoc[2]))

47 glUniform1f(shaderall.updateProgram.sphereRadius, sph.radius)48 glUniform1i(shaderall.updateProgram.tex0, 1)49 #print uv

50 glUniform2f(shaderall.updateProgram.xz,eyeLoc[0],eyeLoc[2])51 #print "eye:",eyeLoc,eyeLoc[0],eyeLoc[2]

52 getMVP(eyeLoc)53 sph.draw()54 glUseProgram(0)55 glActiveTexture(GL_TEXTURE0)56 glBindTexture(GL_TEXTURE_2D, 0)57 glDisable(GL_TEXTURE_2D)58 glActiveTexture(GL_TEXTURE1)59 glBindTexture(GL_TEXTURE_2D, 0)60 glDisable(GL_TEXTURE_2D)61

62 glBegin(GL_LINES)63 glColor(1.0,0.0,0.0)64 glVertex3f(-plane.xl / 2.0, 1.0, -plane.yl / 2.0)65 glVertex3f(100.0, 1.0, -plane.yl / 2.0)66 glColor(0.0,1.0,0.0)67 glVertex3f(-plane.xl / 2.0, 1.0, -plane.yl / 2.0)68 glVertex3f(-plane.xl / 2.0, 1.0, 100.0)69

70 glColor(1.0,0.0,0.0)71 glVertex3f(0.0, 0.0,0.0)72 glVertex3f(100.0, 0.0, 0.0)73 glColor(0.0,1.0,0.0)74 glVertex3f(0.0, 0.0, 0.0)75 glVertex3f(0.0, 1.0, 100.0)76 glEnd()77

78 glutSwapBuffers()

glsl多纹理,多着色器

嗯,python好像对中文注解支持不友好,故采用我的鬼哭神嚎的英语,大家就不要笑了。说一下,后面给出二个坐标系,用来确定当家位置的,一个是左下角,一个是中心,分别向X,Z正轴发射出去。

下面这段是设定球MVP的代码:

1 defgetMVP(eye):2 v =ny.array(glGetFloatv(GL_MODELVIEW_MATRIX), ny.float32)3 p =ny.array(glGetFloatv(GL_PROJECTION_MATRIX), ny.float32)4 m = ny.array([[1, 0, 0, 0],[0, 1, 0, 0], [0, 0, 1, 0],[eye[0],0,eye[2],1]],ny.float32)5 #print m

6 glUniformMatrix4fv(shaderall.updateProgram.pMatrix,1,GL_FALSE,p)7 glUniformMatrix4fv(shaderall.updateProgram.vMatrix,1,GL_FALSE,v)8 glUniformMatrix4fv(shaderall.updateProgram.mMatrix,1,GL_FALSE,m)9 #glgeffloat

球MVP

附件:Python地形.zip 和上方的漫游模式一样,其中EDSF前后左右移动,WR分别向上与向下,鼠标右键加移动鼠标控制方向,V切换第一人称与第三人称。UP与DOWN切换前面操作的移动幅度。在第三人称下,因为球中着色器限定了Y轴,故那时模式看起来如2.5D的那种游戏视角,能左右转动视角,不能看到天,不知2.5D游戏里的那种是不是也是这样被限制住了。

python opengl 截图_初试PyOpenGL二 (Python+OpenGL)基本地形生成与高度检测相关推荐

  1. python opengl书籍_初试PyOpenGL一 (Python+OpenGL)

    很早就一直想学Python,看到一些书都有介绍,不管是做为游戏的脚本语言,还是做为开发项目的主要语言都有提及(最主要的CUDA都开始支持Python,CUDA后面一定要学),做为先熟悉一下Python ...

  2. python 粒子动画_初试PyOpenGL四 (Python+OpenGL)GPU粒子系统与基本碰撞

    我认为比较完善的GPU粒子系统应该如下,粒子初始化可以放在CPU里,但是相关数据运算首先要放在GPU里,并且运算后的数据也应该放在显存里,而不是内存里.故用第三篇实现GPU粒子系统不满足,因为他数据是 ...

  3. python编程基础_月隐学python第2课

    python编程基础_月隐学python第2课 学习目标 掌握变量的输入和输出 掌握数据类型的基本概念 掌握算数运算 1.变量的输入和输出 1.1 变量输入 使用input输入 input用于输入数据 ...

  4. 查看Python的版本_查看当前安装Python的版本

    一.查看Python的版本_查看当前安装Python的版本 具体方法: 首先按[win+r]组合键打开运行: 然后输入cmd,点击[确定]: 最后执行[python --version]命令即可. 特 ...

  5. python opencv手册_教你用Python实现5毛钱特效(给你的视频来点料)

    一.前言 请务必看到最后.Python牛已经不是一天两天的事了,但是我开始也没想到,Python能这么牛.前段时间接触了一个批量抠图的模型库,而后在一些视频中找到灵感,觉得应该可以通过抠图的方式,给视 ...

  6. python双线性插值函数_双线性插值法原理 python实现

    码字不易,如果此文对你有所帮助,请帮忙点赞,感谢! 一. 双线性插值法原理: ① 何为线性插值? 插值就是在两个数之间插入一个数,线性插值原理图如下: 在位置 x 进行线性插值,插入的值为f(x) ↑ ...

  7. python基本原理概论_怎样开始自学Python?

    本人才疏学浅,学识大多浅尝辄止,故文章若有错误,不论是文字笔误还是理解有错,烦请您留言以告知,本人必定感激不尽! **Python分类下的系列文章,不断更新中,如果你迫不及待地想要看看写得如何可以先试 ...

  8. 报考python工程师要求_国家认证的Python技术工程师有什么能力要求?

    的语言Python最近越来越受欢迎,它被越来越多的关注在国家层面.除了参加高考和小学和中学教育,这是之前所讨论的,现在连普通大学生不能逃避Python的邪恶的手.今年,Python已经加入了NCRE( ...

  9. sublime搭建python开发环境_使用sublime搭建python开发环境

    sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等.还可自定义键绑定,菜单和工具栏.Sublime Text的主要功能包括:拼写检查,书签,完整的 P ...

最新文章

  1. svn: E200009
  2. 【避坑】初次接项目的血与泪,扎坑了老
  3. 北斗部标808协议解析说明示例
  4. Excel告诉你身份证号码里藏着de秘密
  5. 轻松地与Java完全集成
  6. Netstars CTO 陈斌:技术管理的两种思路
  7. matlab杜哈梅尔积分,非平稳地震作用下桥梁系统碰撞间隙宽度的概率评价方法与流程...
  8. leetcode-125 Valid Palindrome
  9. python的合法名称_python 命名规范
  10. 势逼 React Native,跨平台开发框架 Flutter 很凶猛
  11. 为什么root下不能使用passwd命令_Linux:CentOS 7中常用的基础命令
  12. arcgis10之将多个shp文件合并成一个shp文件
  13. 解决拼音汉字混合搜索,由于同音字导致搜出不相干的内容
  14. 广电linux机顶盒装软件,电视盒子如何安装第三方软件(四种参考方法)
  15. com.alibaba.datax.common.exception.DataXException: Code:[ESWriter-03]
  16. 《密码安全新技术专题》 第十一周作业
  17. IBM WMB 使用方法
  18. 2017年中国大数据发展趋势和展望解读(上)
  19. IDEA 在hdfs中创建目录
  20. 泰拉瑞亚指令代码大全 无限钱无敌作弊码一览

热门文章

  1. CodeForces 258B Little Elephant and Elections 数位DP
  2. ASP.NET - MVC框架及搭建教程
  3. c++设置不适用预编译头
  4. 栈中函数调用原理_详解
  5. C#中的继承与多态还有接口
  6. 说明一项最有成就感的php项目,2020 Github 上 10 个最受欢迎的 PHP 项目
  7. 多线程内存泄漏_内存泄漏的场景和解决办法
  8. 关于div容器高度随着浏览器宽度按照宽高比自适应的问题(css解决方案)
  9. np合并 python_这15个tips,带你领略 Python 的简洁和优雅
  10. python 打包exe thread报错_pyinstaller 打包exe 遇到的坑