在Stage3D中实现一个天空盒

天空盒这货,其实核心技术就是CubeMap. 给一个Cube的6个面,贴上不同的纹理。

最笨的方法是创建6个平面,每个面贴一个单张纹理罢了。
实际上CubeMap 的采样方式也差不多, 只不过是用面法线来代替UV 曲纹理罢了。

最开始查资料的时候,资料说用面法线来取6个面,我以为是是用6个法线来代表6个面, 然后就纠结在如果对应上片段着色器。后来经过试验,才发现网上说的并不细致,作为一个规则形状(立方体,球形),直接归一化的它们的顶点,比如立方体8个顶点生成8个法线,传入片段着色器即可,完全不要被6个面对应的6个法线这些网络上的讲解误导了。 GPU会根据顶点间的法线差值正确的取出对应的 纹理。

在 Flare3D 的Demo中,有6个面在一张纹理上的贴图, 我不知道是否真有如此的API,讲6张图自动的拆开上传。
我的做法是自己创建6个裁剪矩形进行6张图分拆,然后上传

        private function initClipList() : void
        {
            m_clipList = new Vector.<Rectangle>();
            m_clipList.push(new Rectangle(2*m_size,m_size,m_size,m_size));
            m_clipList.push(new Rectangle(0,m_size,m_size,m_size));
           
            m_clipList.push(new Rectangle(m_size,0,m_size,m_size));
            m_clipList.push(new Rectangle(m_size,2*m_size,m_size,m_size));
           
            m_clipList.push(new Rectangle(m_size,m_size,m_size,m_size));
            m_clipList.push(new Rectangle(3*m_size,m_size,m_size,m_size));
        }

m_clipList 的分拆顺序,就是CubeMap上传纹理的顺序
如下

        public static const POSITIVE_X:uint = 0;
        public static const NEGATIVE_X:uint = 1;
        public static const POSITIVE_Y:uint = 2;
        public static const NEGATIVE_Y:uint = 3;
        public static const POSITIVE_Z:uint = 4;
        public static const NEGATIVE_Z:uint = 5;

对于CubeMap 我们需要人为的上传所有miplevel
层级数量依照纹理大小而定, 如果你的纹理是 515 * 512
那么依次上传的level 是 512*512 -> 256 * 256 -> 128 * 128 -> 64 * 64 – > 32* 32 -> 16 * 16 -> 4 * 4 -> 2 * 2 -> 1* 1
6个面中,每个面都要这么上传。

到此为止,CubeMap 实际上已经是完成了。
如果要做成天空盒,我们还要修改一下渲染的Shader

在游戏中的天空盒一般是不随着玩家移动而缩放的, 给人一种无法到达的感觉。 因此我们可以以 viewPorj 的矩阵来渲染它, 由于没有model矩阵,本质就是天空盒总是以相机的位置为中心,同时接收相机的旋转,但不缩放。

如果要做不接受旋转的天空盒,甚至直接用 proj 矩阵渲染就够了。

是用的Shader如下

顶点着色器

        public override function getVertexProgram():ByteArray
        {
            return new AGALMiniAssembler().assemble(Context3DProgramType.VERTEX,
                "m44 op va"+vaPos+" vc"+vcProjection+"n"+
                "nrm vt0.xyz va"+vaPos+".xyzn"+
                "mov vt0.w vc"+vertexConstIndex+".xn"+
                "mov v0 vt0n");
        }

第一行是 proj 矩阵 * Cube的顶点
第二行是 归一化个顶点,计算出法线
第三行是 将该法线的w 分量设置为1(不缩放就是靠它了)
第四行是 将法线传给像素着色器去取 CubeMap

像素着色器

        public override function getFragmentProgram():ByteArray
        {
            return new AGALMiniAssembler().assemble(Context3DProgramType.FRAGMENT,
                "tex oc v0 fs"+fcTexture+"<cube,clamp,linear,miplinear>n");
        }

AOI3D整合了OGRE引擎的Mesh解析了,可以加载火炬之光2的所有模型啦

这周迎来了 ALPHA 0.2 更新速度开始加快啦。。。
同样的,工作室的任务也开始繁重了。。。艹,怎么一起都来了。。。

AOI3D ALPHA 0.2
新增了
封装了Shader. AGAL Code 不再Object3D 内部创建了,也不再由 IMaterial接口提供了。
修复了 PlaneMesh 创建的平面偏移值错误,以及顶点顺序错误的bug
添加了SKyBox
添加了Ogre引擎的Mesh模型解析

本周有时间的话,尽量完成下一步的计划更新
优化骨骼动画,目前是CPU模拟,丢帧严重
修复NormalMap
新增Sprite3D
新增视锥体剔除
新增Ogre骨骼动画解析
整合ShadowMapping

话说~回到家 居然拉不到gitHub 所以不能复写了。。
结果写博客的时候,居然又同步成功了。。。
算了~明天去公司整合后再穿github 吧~~
主页直接贴个Demo, 支持精确选取的说

AOI3D ALPHA 0.1

差不多可以给AOI3D 来个版本号了吧~ 先来个 ALPHA 0.1

目前包含:
模型解析:MD5,OBJ
简易的模型骨骼动画播放器
灯光:点光,平行光
后期处理:HDR,BLUR,COLOR
投影:ShadowMapping, PlaneMapping
拾取:像素拾取

接下来的工作:
优化骨骼动画,目前是CPU模拟,丢帧严重
优化Shader,目前是零散的AGAL组合,之后要封装到Shader中
修复NormalMap
修复PlaneMesh, 目前虽然没问题,但总觉顶点没有对齐的样子
新增SkyBox
新增Sprite3D

最后:目前的Demo(精确拾取) Demo is Here
试试按键盘的 1,2,3,4 来切换动作. 丢帧注意…