Categories
OpenGL

OpenGL魔方一个

前一段边看OpenGL边练手,很早就在Mac下调通了(估计Linux也能跑吧),但Mac版发上来也没啥意义,于是今天移植到Windows下,姑且一发,有兴趣的同志试看看吧,自认为操作还是很友好的,鼠标左键拧它,右键控制视角,中键让它随机自拧。

这里下载。

Categories
OpenGL

OpenGL notes(5)

换到Glut上面,原先找到的cocoa那层都得重新写过。考虑到将来的移植问题,读取BMP的部分也就没用glaux(这玩意儿只有windows下能用……)和mac的库,自己弄了个读bmp的函数。写好之后测了半天,图片明明读进来了就是不显示纹理。折腾了一个下午,最后发现是个莫名其妙的问题导致bmp的头部读取不正常。

typedef struct tagBITMAPFILEHEADER
{
short int bfType; //specifies the file type
int bfSize; //specifies the size in bytes of the bitmap file
short int bfReserved1; //reserved; must be 0
short int bfReserved2; //reserved; must be 0
int bfOffBits; //species the offset in bytes from the bitmapfileheader to the bitmap bits

}BITMAPFILEHEADER;

很清楚的结构,short int长度2,int长度4,想当然的sizeof(BITMAPFILEHEADER)=14,试了一下,居然是16……搜了搜,发现这涉及结构体成员的对齐方式,把这段定义放进#pragma pack(1)和#pargma pack()之间即可。

原因是#pragma pack(n)指定了成员的对齐方式。对齐的时候,假设某个成员长度len,则取x=min(len, n),这个成员的起始地址就是x的整数倍。

据说intel和m$的面试题也考到这点,当然更深入。http://www.sf.org.cn/Article/base/200509/260.html

Categories
OpenGL

OpenGL notes(4)

这个有点CS的味道了,呵呵。从外部文件读取坐标作图,键盘控制视角的水平移动,也能抬头低头。

Categories
OpenGL

OpenGL notes(3)

做了几件事:

1. 贴图上去,生成texture。

2. 可以用键盘控制转动速度和视角远近。

3. 可以选择贴图的插值方式(Nearest, Linear & MipMapped)。在拉近视角的那一段演示了三者的区别,可能要用高清模式才能看清。后二者在这里没区别,因为箱子是很标准的256^3,第一个则可以看出来颗粒。

4. 灯光。设置了两个光源,一个是ambient的白光,亮度50%,另一个是diffuse的白光,亮度100%,位置固定。结果居然是看到箱子在两面显得暗,转到另外两面就变亮了。现在还不知道坐标是怎么设置的,也许是因为这里相对于空间转动的是视角而不是箱子吧。

update about 4:
检查了一个晚上,发现原来是在绘制立方体的时候没有用glNormal指定每个面的法向量,导致了光线诡异的变化。修改之后就正常了,下面这段视频是在修改后的基础上加入blending,实现透明效果。

Categories
OpenGL

OpenGL notes(2)

昨天夜里到今天夜里,解决了两个主要问题:如何读取BMP文件来构建CGImage对象,以及如何把24-bit的BMP做成纹理放到OpenGL里。

第一个问题就贴一段代码好了。

CFBundleRef bundle = CFBundleGetMainBundle();
CFURLRef url = CFBundleCopyResourceURL(bundle, CFSTR(“filename”), CFSTR(“bmp”), NULL);
//然后调用LoadImage(CFURLRef url),就可以得到一个CGImageRef了。
CGImageRef LoadImage(CFURLRef url)
{
if (!url)
return NULL;

CGImageSourceRef isr = CGImageSourceCreateWithURL (url, NULL);
CGImageRef ir = CGImageSourceCreateImageAtIndex (isr, 0, NULL);

return ir;

}

整个过程相当郁闷,折腾了半天url总是NULL,后来才找到这个比较通用的流程。如果在windows下应该只需要读进来一个File扔给auxDIBImageLoad()就可以了,无奈在Mac下最好的替代也许就是这个CGImage,只好硬着头皮上。

第二个问题就更是体现出CGImage的怪异。

事情是这样的。glTexImage2D需要的纹理数据存放在一个空间(就叫myData)里面。已经读入的要作为纹理的图片构成的CGImage对象由ir这个指针指向。于是,必须用CGBitmapContextCreate(…)来把CGImage的数据提取出来放到myData里。而这个函数只支持有限的几种图片模式(具体可见http://developer.apple.com/qa/qa2001/qa1037.html),也就是说OS/2下面24-bit的RGB三通道的BMP是不能直接用的。然后,我就迷糊了:我读入这个图片之后,在CGImage对象里面被存成什么样了呢?如果直接读取它的BitmapInfo传进去,报错说不支持这种模式。于是就得从支持的模式里面挑一中来强制转换。最后我才算明白,恶心之处就在于CGImage把RGB的存放方式改了,而且加上了Alpha通道,放在一个32-bit的结构里,但你用CGImageGetBitmapInfo()读取出来的只是转换之前的信息。经过半天摸石头过河的实验之后才搞清楚,RGB的24-bit被变成了顺序为RGBA的32-bit。所以应该用kCGImageAlphaPremultipliedLast或者kCGImageAlphaNoneSkipLast把Alpha扔掉才行。

并且,在glTexImage2D函数里面,internalformat要用GL_RGB,format要用GL_RGBA,才能把纹理正确渲染出来。因为前者是指定纹理的储存和绘制方式,后者是指定myData里的数据是以什么格式储存的。

最后,我用Photoshop做了个RGBA的32-bit BMP放进去,BitmapInfo参数用实际读取的结果做参数居然还是报告不支持该模式,nnd,也不应该是Big-endian和Little-endian的问题啊……再说了。

Categories
OpenGL

OpenGL notes(1)

有关Framework。

今天遇到一个问题。某个例程里面用了#include 调用了Mac OS X自带的OpenGL库,编译正常。在尝试用贴图渲染3D物体时,NeHe教程里用了AUX_RGBImageRec来储存读入的图片,而这个类型是包含在glaux库里的,这个库又是windows only的。Apple给的官方说明给了一些选项来完成mac中的相同任务,一是用Cocoa的NSView类,二是用Quartz的image source,三是直接从解压的文件里读入Raw数据。当然,我选了第二个。系统的ApplicationServices/CoreGraphics.framework/CGImage.h里面定义了Quartz的图像数据类型CGImageRef,所以,我得把这个头文件include进去。可是导入了ApplicationServices Framework到工程里,在头文件里用#include 却总是报错,no such file or directory。而在工程浏览器里CGImage.h明明在ApplicationServices下面……后来翻Xcode的文档才发现,涉及深层次的问题。

Mac下面的Framework都是用bundle的形式提供的,一个bundle里面可以共存多种版本,保证了对旧版本程序的支持。为了为特定的应用环境提供必需的编程接口,Apple在标准的Framework之外还提供了Umbrella Framework。照我的理解,UF顾名思义应该是期望用伞架的结构,讲分散在各个Standard Framework里的subframework虚拟的链接起来,形成针对某种特定应用的新的framework。与Standard Framework不同,UF并不把它的subframeworks里的头文件都包括进来,而仅仅包含那个framework的master header file,也就是与framework同名的那个。因此,在调用UF的时候,只需要include这个头文件即可。这样也带来一个好处,就是如果Apple对某个framework里的东西进行了修改,开发者并不需要对他们的代码做改动,因为那个master header file总是不会改变的。

好了,废话这么多,最终结论就是,只需要#include 就可以。