level 2
一般来说,3d程序主要由2部分组成,它们依次是:
1.数据部分:2d和 3d 原始数据
2.绘制部分:处理原始数据,以及像素上屏
我们先从数据部分开始讲起
2013年10月18日 00点10分
3
level 2
数据方面,新版本的opengl做了很大的改动,
首先是固定管线被取消了,绘制数据必须递交给渲染器的attribute变量中
进行绘制前也需要预先准备好这些数据以及包括贴图数据
而在移植一些 桌面版本的 代码时, opengl es 可能会出现贴图变黑的现象,这一问题出在glTexImage2D()上面,以前的桌面版本opengl中对第三系数的调用可以是贴图
bp
p,而现在我们必须针对bpp来填 24bpp的贴图就填GL_RGB, 32bpp的贴图 就填 GL_RGBA,在安卓这样的小型设备上调试数据正确也有个小窍门,就是在 glsl 碎片渲染器中,把想要测试的数据处理成 (0,1)的范围,然后扔进gl_FragColor中,通过rgba 的分布来判断数据是否正确
2013年10月18日 00点10分
4
level 2
绘制部分,opengl es 2.0 主要的改动就是所有和矩阵运算相关函数都没有了,用户必须自行创建,同样也是要递交给 glsl, 而先前桌面版本的 glBegin glEnd也无法使用了,取而代之的是glDrawArrays,并且不能像 gles1那样直接上屏,所以总的来说,gles 2.0 表面要麻烦很多,但为了借助 glsl实现画质的突破,我们必须掌握 gles 2.0 的相关知识。现在,我以示例图片中的小程序 为例,向大家介绍如何用c4droid开发3d 程序
2013年10月18日 01点10分
5
level 2
首先我们已经创建了一个 opengl es 2.0 的窗口,我们第一步要做的是打开深度测试并将深度函数设置为 GL_LEQUAL,这样多边形就不会因为绘制顺序而产生错误:
glEnable(GL_DEPTH_TEST),glDepthFunc(GL_LEQUAL);
设置好之后我们准备数据,从文件来读取数据
个人推荐采用tga做为贴图格式,用obj做模型格式,因为这两种格式的内容最贴近原始数据,而且与这两 种文件格式信息相关的资料很健全,他们的分析器函数
也特别好写,例子中的 tga格式贴图我是用 photoshop保存的,而obj模型是通过maya导出的。
在第二张图中可以看到,我用 struct img 储存图像信息,成员如下:
1.解析tga后得到的原始图像数组,数组的排列顺序在图像中显示为由左往右,由下往上
2.图像数组的宽
3.图像数组的高
4.图像数组的 bpp
有了这些信息后,在指令 newimg_fil中,我使用如下opengl 函数创建 opengl贴图:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);/*避免极少数情况下产生内存错误 */
glGenTextures(1, texture);/* 创建贴图 */
glActiveTexture(GL_TEXTURE0);/* 开启0号贴图 */
glBindTexture(GL_TEXTURE_2D, rp1->pxl);/* 绑定贴图做为2d 贴图 */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);/* 设置min过滤 */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);/* 设置mag过滤 */
这样,我们就得获得了一个贴图 id
2013年10月18日 01点10分
6
更正一下 glGenTextures(1, texture)改为glGenTextures(1, &texture) glBindTexture(GL_TEXTURE_2D, rp1->pxl);/* 绑定贴图做为2d 贴图 */这 句 把rp1->pxl改为 texture
2013年10月18日 03点10分
level 2
我用struct msh储存以三角形为元素的模型信息, 成员如下:
1.空间顶点数据,描述顶点在空间中的3d座标
2.空间面数据,描述一个空间中的三角形
3.贴图顶点数据,描述空间顶点在贴图中对应的2d座标
4.贴图面数据,描述空间三角形对应的贴图三角形,以进行纹理映射
5.法线矢量数据,描述空间顶点的法线朝向
6.法线面数据,描述空间三角形对应的法线三角形,以进行法线插值运算
有了这6种数据,我们就可以以三角形为单位,完整的绘制出 claude的模型了
2013年10月18日 01点10分
7
level 9
楼主,把你输出的apk.发出来看看呗?那个3d方块很好玩,这个我也想试试。
2013年10月18日 01点10分
8
但是这个的话要数据包,因为贴图和模型都是外置的, 我写完文章再准备一下好了,
2013年10月18日 01点10分
回复 叜駣 :哦
2013年10月18日 01点10分
level 2
为了能进行绘制,我首先在settrm函数中,把 opengl es 2.0部分的环境准备好,过程如下:
1.建立一个glsl程序:
首先准备glsl程序的源代码字符串(见像图1),用glCreateShader建立 顶点渲染器与碎片渲染器,用glShaderSource读入源代码字符串并用glCompileShader进行编译。用 glCreateProgram创建一个glsl渲染程序,用glAttachShader将编译出的两个渲染器连上渲染程序,并用glLinkProgram进行编译,这样一个 glsl程序编译完成了,为了简洁起见,本例的glsl只实现顶点及贴图处理的基本功能
2.顶点渲染器:
如图1所示,在顶点渲染器中,创建2个attribute 变量,用以表示2种“属性”,分别是“空间位置”与“贴图位置”,我们可以把他们直接看成是7楼msh模型结构中的空间顶点数据与贴图顶点被转存为glsl变量, 而glsl需要4元素矢量表示空间位置,所以我们用gl_Position = vec4(v,1)得把3维空间数组转成glsl的格式,并作为顶点渲染器将处理的空间位置
3.碎片渲染器:
碎片渲染器的目的是读取贴图并按顶点渲染器中的贴图位置得到最终碎片颜色,由于没进行其它运算,所以并没有光影,漫反射,镜面反射等效果:
char fshd_str[] =
"precision mediump float;" /* 这一行描述运算精度,是gles 2的特色 */
"uniform sampler2D difimg;" /* 碎片渲染器将要读取的2维采样,也就是贴图 */
"varying vec2 diffrg;" /*碎片的贴图位置,由于在图1中,我们用顶点贴图位置对其进行了赋值,而它又是varying跨文件变量,所以在碎片渲染器中,diffrg不需要额外计算*/
""
"void main()" /* 主程序 */
"{"
"gl_FragColor = texture2D(difimg, diffrg);" /*最终上屏色,我们通过贴图碎片,从帖图中获取颜色,然后直接上屏*/
"}";
2013年10月18日 02点10分
9
level 2
4.主程序部分的数据准备:
为了能在主程序中改变glsl变量,我们首先要用 glGetAttribLocation 和 glGetUniformLocatio@分别获得获得glsl中 attribute类型变量以及 uniform 类型变量的编号,通过编号我们便可以使用
glVertexAttribPointer和 glUniform1f分别对attribute类型变量以及 uniform 类型变量进行改动了:
int glsl_v, glsl_vt,/* glsl 中的空间位置与贴图位置(也就是v和vt)的变量编号*/
glsl_difimg;/* glsl 中贴图的变量编号 */
glsl_v = glGetAttribLocation(shd, "v");/* 从渲染程序shd 中获得空间位置变量的编号 */
glsl_vt = glGetAttribLocation(shd, "vt");/* 从渲染程序shd 中获得贴图位置变量的编号*/
glsl_difimg = glGetUniformLocation(shd, "difimg");/* 从渲染程序shd 中获得贴图变量的编号 */
2013年10月18日 02点10分
10
level 2
准备好这些数据后,就可以开始绘制了
在绘制前,我们设好清屏色
glClearColor(1, 0, 1, 1);
因为纯紫色醒目且很少有人使用,所以一般用来做为透明背景色
现在开始绘制模型。
如图2所示,我采用的绘制函数是frmmsh_glsl(),设计思路是:
“创建一个for loop, 用来画出模型中的每一个三角形”
要达成这一目的,其本质就是要有一个能画出空间三角形的函数,完成了这一函数,也就可以
正确的
画出模型了。所以我们只讨论画三角形的函数应该如何设计
2013年10月18日 02点10分
11
level 2
首先我们为该函数提供9个(3顶点,每个顶点都有x,y,z值,共9个)空间位置数据 v[9],6个(3顶点,每个顶点都有x,y值,共6个)贴图位置数据vt[6]以及创建好的opengl贴图img(暂不讨论矩阵与法线部分),然后开始绘制:
glUseProgram(shd); /* 切换到9楼创建的glsl程序 */
glEnableVertexAttribArray(glsl_v);/* 通过变量编号,开启glsl程序中的空间位置变量 */
glEnableVertexAttribArray(glsl_vt);/* 通过变量编号,开启glsl程序中的贴图位置变量 */
glVertexAttribPointer(glsl_v, 3, GL_FLOAT, GL_FALSE, 0, v);/* 将空间位置数据发送至glsl */
glVertexAttribPointer(glsl_vt, 2, GL_FLOAT, GL_FALSE, 0, vt);/* 将贴图位置数据发送至glsl */
glActiveTexture(GL_TEXTURE0), glBindTexture(GL_TEXTURE_2D, img);/* 启用0号贴图并绑定要绘制的贴图img */
glUniform1f(glsl_difimg, 0);/*将贴图发送至glsl */
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);/* 绘制三角形,由glsl负责渲染 */
由于我们发送了glsl所需完整信息(在本例中也就是 空间位置数据 , 贴图位置数据, 和 贴图),所以 glsl 就能将三角形正确的渲染出来了
2013年10月18日 03点10分
12
更正一下,glUniform1f改为glUniform1i
2013年10月19日 13点10分
level 2
有了三角形绘制函数和要绘制的3d数据和2d数据,就可以在c4droid中借助opengl es 2.0开发3d程序了,前提是要掌握 opengl api的知识 和 glsl渲染语言的基本知识
另外,在开发时,除了4楼提到的贴图变黑的情况要注意以外,还要注意文件路径填写,要采用绝对路径,而分发apk到其它设备时,附带的数据包最好放进以/sdcard/为根目录的位置,或注明人工存放的位置。例如,在图2中,我完全可以直接用newmsh_fil("./claude.obj")来读取claude 的模型,但这样c4droid开启程序却崩溃了,因为程序是在别的位置运行的,在那个位置不一定找到claude.obj文件的,所以我填写了文件的绝对位置,于是程序正常运行
2013年10月18日 03点10分
13
level 8
楼主啊!Native Activity放弃了,手机杂牌,没有合适的刷机包,变砖就不好了,求其它扩展库实现这个,如SDL2,QT等方法。
2013年10月18日 11点10分
19
其它的可以纯sdl实现,不过你要具备图形编程能力,其实利用标准c库可以实现opengl 所有功能,只要因为用cpu渲染,速度较慢,但小规模的3维渲染还是很不错的
2013年10月18日 11点10分