游戏裁剪
来源:互联网 发布:windows loader 和kms 编辑:程序博客网 时间:2024/05/22 06:49
裁剪能够极大提高渲染效率。
PVS
对于静态场景,我们可以先把场景立方体分割成网格(grid),即n*m*h个grid,先计算好在每个grid上所有角度可见的mesh(剔除物体完全被前面物体挡住的mesh),记录所有可见的mesh编号,如果相机在这个位置上,只要把这些可见的mesh进行下一步裁剪(比如视锥裁剪,去除不再视锥内的物体)
八叉树(Octree)
在进入视锥裁剪前,可以把空间进行分割。比如把空间分为8份。
OctreeNode结构很简单,如下:
public class OctreeNode extends NodeBase { private var _centerX:Number; private var _centerY:Number; private var _centerZ:Number; private var _minX:Number; private var _minY:Number; private var _minZ:Number; private var _maxX:Number; private var _maxY:Number; private var _maxZ:Number; private var _quadSize:Number; private var _depth:Number; private var _leaf:Boolean; private var _rightTopFar:OctreeNode; private var _leftTopFar:OctreeNode; private var _rightBottomFar:OctreeNode; private var _leftBottomFar:OctreeNode; private var _rightTopNear:OctreeNode; private var _leftTopNear:OctreeNode; private var _rightBottomNear:OctreeNode; private var _leftBottomNear:OctreeNode; //private var _entityWorldBounds : Vector.<Number> = new Vector.<Number>(); private var _halfExtent:Number;}
八叉树生成如下:
/** * @param maxDepth 八叉树的深度 * @param size 大小 * @param centerX 中心点 * @param depth 当前深度 */ public function OctreeNode(maxDepth:int = 5, size:Number = 10000, centerX:Number = 0, centerY:Number = 0, centerZ:Number = 0, depth:int = 0) { init(size, centerX, centerY, centerZ, depth, maxDepth); } private function init(size:Number, centerX:Number, centerY:Number, centerZ:Number, depth:int, maxDepth:int):void { _halfExtent = size*.5; _centerX = centerX; _centerY = centerY; _centerZ = centerZ; _quadSize = size; _depth = depth; _minX = centerX - _halfExtent; _minY = centerY - _halfExtent; _minZ = centerZ - _halfExtent; _maxX = centerX + _halfExtent; _maxY = centerY + _halfExtent; _maxZ = centerZ + _halfExtent; _leaf = depth == maxDepth; if (!_leaf) { var hhs:Number = _halfExtent*.5; addNode(_leftTopNear = new OctreeNode(maxDepth, _halfExtent, centerX - hhs, centerY + hhs, centerZ - hhs, depth + 1)); addNode(_rightTopNear = new OctreeNode(maxDepth, _halfExtent, centerX + hhs, centerY + hhs, centerZ - hhs, depth + 1)); addNode(_leftBottomNear = new OctreeNode(maxDepth, _halfExtent, centerX - hhs, centerY - hhs, centerZ - hhs, depth + 1)); addNode(_rightBottomNear = new OctreeNode(maxDepth, _halfExtent, centerX + hhs, centerY - hhs, centerZ - hhs, depth + 1)); addNode(_leftTopFar = new OctreeNode(maxDepth, _halfExtent, centerX - hhs, centerY + hhs, centerZ + hhs, depth + 1)); addNode(_rightTopFar = new OctreeNode(maxDepth, _halfExtent, centerX + hhs, centerY + hhs, centerZ + hhs, depth + 1)); addNode(_leftBottomFar = new OctreeNode(maxDepth, _halfExtent, centerX - hhs, centerY - hhs, centerZ + hhs, depth + 1)); addNode(_rightBottomFar = new OctreeNode(maxDepth, _halfExtent, centerX + hhs, centerY - hhs, centerZ + hhs, depth + 1)); } }
如何放置一个mesh,已知mesh的AABB盒,从Octree的根节点开始查找代码如下:
// TODO: this can be done quicker through inversion private function findPartitionForBounds(minX:Number, minY:Number, minZ:Number, maxX:Number, maxY:Number, maxZ:Number):OctreeNode { var left:Boolean, right:Boolean; var far:Boolean, near:Boolean; var top:Boolean, bottom:Boolean; if (_leaf) return this; right = maxX > _centerX; left = minX < _centerX; top = maxY > _centerY; bottom = minY < _centerY; far = maxZ > _centerZ; near = minZ < _centerZ; if ((left && right) || (far && near)) return this; if (top) { if (bottom) return this; if (near) { if (left) return _leftTopNear.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ); else return _rightTopNear.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ); } else { if (left) return _leftTopFar.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ); else return _rightTopFar.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ); } } else { if (near) { if (left) return _leftBottomNear.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ); else return _rightBottomNear.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ); } else { if (left) return _leftBottomFar.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ); else return _rightBottomFar.findPartitionForBounds(minX, minY, minZ, maxX, maxY, maxZ); } } }
把mesh放在这个Octree下即可。
渲染的时候从根节点开始遍历。
先判断Octree节点的包围盒是否在视锥内,如果是,遍历他的8个子Octree。
/** * Allows the traverser to visit the current node. If the traverser's enterNode method returns true, the * traverser will be sent down the child nodes of the tree. * This method should be overridden if the order of traversal is important (such as for BSP trees) - or if static * child nodes are not added using addNode, but are linked to separately. * * @param traverser The traverser visiting the node. * * @see away3d.core.traverse.PartitionTraverser */ public function acceptTraverser(traverser:PartitionTraverser):void { if (_numEntities == 0 && !_debugPrimitive) return; if (traverser.enterNode(this)) { var i:uint; while (i < _numChildNodes) _childNodes[i++].acceptTraverser(traverser); if (_debugPrimitive) traverser.applyRenderable(_debugPrimitive); } }
视锥裁剪
如何判断一个点在平面侧
给定一个平面
平面外的一个点
平面的法向量为
平面到点
如果不加入绝对值即
正号表示与法向量同一侧
负号表示与法向量方向一侧
假设
判断一个AABB包围盒是否在视锥(6个面组成)内,代码如下:
public function isInFrustum(planes:Vector.<Plane3D>, numPlanes:int):Boolean { //return true; for (var i:uint = 0; i < numPlanes; ++i) { var plane:Plane3D = planes[i]; var flippedExtentX:Number = plane.a < 0 ? -_halfExtentsX : _halfExtentsX; var flippedExtentY:Number = plane.b < 0 ? -_halfExtentsY : _halfExtentsY; var flippedExtentZ:Number = plane.c < 0 ? -_halfExtentsZ : _halfExtentsZ; var projDist:Number = plane.a * (_centerX + flippedExtentX) + plane.b * (_centerY + flippedExtentY) + plane.c * (_centerZ + flippedExtentZ) + plane.d; if (projDist < 0) { return false; } } return true; }
如何快速提取视锥平面
参考Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
待写。
阅读全文
0 0
- 游戏裁剪
- 三连游戏优化--α-β裁剪
- 裁剪
- 裁剪
- 裁剪
- 裁剪
- Unity优化笔记--裁剪游戏中的TTF字体.
- 游戏引擎理论与实现系列04-画线和裁剪
- Windows游戏编程大师技巧之Cohen-Sutherland裁剪直线算法
- opencv裁剪移并植到android实现游戏中的数字识别
- 视频裁剪,长度裁剪
- 多边形裁剪
- jre裁剪
- 裁剪系统
- 裁剪ffmpeg
- 图片裁剪
- qt裁剪
- 直线裁剪
- 【Java团队用OpenResty】2、Eclipse开发环境搭建
- loj #2051. 「HNOI2016」序列(莫队+ST+单调栈)
- LeetCode 513. Find Bottom Left Tree Value
- 在Keras 和 Tensorflow 框架下五种视频分类的实施方法
- 将类数组转换成数组封装成方法
- 游戏裁剪
- C#struct结构体
- redis 对key的设置操作
- Spring Aop实例之xml配置
- 将jenkins部署到tomcat上,使用tomcat启动和关闭
- 多段图的最短路径领接表法
- 电脑重启提示No bootable device问题怎么办
- 【java笔记】数组、数组的常见操作
- 【JS学习】ajax简单例子