测试Demo的目录结构:
->MyBatisCongfig.xml
->userMapper.xml
com.luohao.Test
->TestMyBatis.class
->User.class
测试数据库是MySQL,用的数据库连接是JDBC,上面的目录结构中MyBatisConfig.xml是MyBatis的核心配置文件,userMapper.xml是用来映射SQL语句的,这里的映射使用了mxl文件来配置而没有使用注释的方式的原因是在很多复杂的情况下使用xml文件来配置这里会使程序看起来整洁而且编程更加高效。
核心配置文件的xml文件是这样的:
文件:MyBatisConfig.xml
2 <!DOCTYPE configuration
3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
4 "http://mybatis.org/dtd/mybatis-3-config.dtd">
5 <configuration>
6 <environments default="development">
7 <environment id="development">
8 <transactionManager type="JDBC"/>
9 <dataSource type="POOLED">
10 <property name="driver" value="com.mysql.jdbc.Driver"/>
11 <property name="url" value="jdbc:mysql://localhost:3306/blogtest"/>
12 <property name="username" value="root"/>
13 <property name="password" value="*******"/>
14 </dataSource>
15 </environment>
16 </environments>
17
18 <mappers>
19 <mapper resource="com/luohao/config/userMapper.xml"/>
20 </mappers>
21
22 </configuration>
每一个environment对应了每一个数据库,这里的数据使用了我的一个博客的数据库作为测试。底下的mapper标签是用来映射SQL语句的文件路径的,这里从目录结构来看userMapper.xml来看路径应该是com/luohao/config/userMapper.xml。
之后只映射的SQL语句,文件为userMapper.xml
2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 <mapper namespace="com.luohao.config.userMapper">
4 <select id="Username" parameterType="String"
5 resultType="com.luohao.Test.User">
6 select * from user where username=#{username}
7 </select>
8 </mapper>
这里的命名空间是必须的,这是MyBatis是新特性也是让代码跟家严格的特性。
id用是一个标识,之后的java代码中会出现这个,paramterType是用来对应数据类型的,这里是username,对应的是String类,resultType对应的是实例类也可以叫做模型类,是数据库SQL语句执行所得到参数所对应的get或者set方法。
之后的数据库语句基本一致,只是#号之后的java代码会插入要查找的东西。下面就是java代码了。
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import org.apache.ibatis.io.Resources;
6 import org.apache.ibatis.session.SqlSession;
7 import org.apache.ibatis.session.SqlSessionFactory;
8 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
9
10 public class TestMyBaits {
11
12 public static void main(String[] args){
13 String resource="com/luohao/config/MyBatisConfig.xml";Ogre2.0 全新功能打造新3D引擎 - 天天不在 阅读原文»
不知当初是在那看到,说是Ogre2.0浪费了一个版本号,当时也没多想,以为没多大更新,一直到现在想做一个编辑器时,忽然想到要看下最新版本的更新,不看不知道,一看吓一跳,所以说,网络上的话少信,你不认识别人,别人张嘴就来,对别人也没损失,还可以装B下,靠.
从现在Ogre2.1的代码来看,大约总结下,更新包含去掉过多的设计模式,SoA的数据结构(用于SIMD,DOD),新的线程模式,新的渲染流程与场景更新,新的材质管理系统,新的模型格式,新的合成器方案,更新是全方面的,可以说,Ogre2.x与Ogre1.x完全不是同一个引擎,不管是效率,还是从渲染新思路的使用上.
大体上参照二份主要文档,一份是OGRE.2.0.Proposal.Slides.odp,现在Ogre的维护者之一dark_sylinc比对其他的引擎以及相关测试写的Ogre2.0要修改的方向,一是Ogre 2.0 Porting Manual DRAFT.odt,移植手册,简单来说,Ogr2.0具体的修改位置与说明.非常有价值的二份文档,可以说,这是全新Ogre改动的精华,我们从这二份文档里,能学到如何针对C++游戏引擎级别的包含效率,可用性的重构.这是一个幸运的学习经历.
从https://bitbucket.org/sinbad/ogre下载最新版本,里面的DOC文件夹,有多份文档,我整理了下,每部分包含改动原因,改动位置,相关代码来说,因为全是英文文档,所以如果理解有错误,欢迎大家指出,不希望误导了大家.本文只针对新模型新功能,也就是加了v1命名空间的(Ogre1.x中的功能,有对应Ogre2.x版本),本文不会特别说明.
Ogre1.x中问题与建议
Cache末命中
看看作者的幻灯片,哈哈,图片特别形象生动.
这个是函数是判断模型是否在当前摄像机可见,如果可见,加入渲染通道.不过你去看现在的Ogre2.1的代码,这个方法没有变,不是因为没有改,是因为渲染流程变了,这个函数的功能被MovableObject::cullFrustum包含了,其中判断摄像机与模型AABB相交的算法也换了.
这个函数因为每桢都对每个模型来计算,如果Cache misses,损失有点大.
同样这个一般用来得到模型的世界坐标位置,也是每桢每个模型要计算的,如果Cache miss,同上.
那么如何改进,像上面,你不要那些判断,要么多计算,要么结果不对,作者给出的答案就是改进渲染流程,减少判断条件的出现.后面会细说.
低效的场景遍历和操作.
可以看到场景每次更新都在重复,检查是否需要更新,然后更新.很多不必要的变量和是否更新状态的跟踪,以及太多的判断,分别造成cache misses缓存不友好.(我去,if判断有这么大的破坏力?还是只是引擎级别的代码才会造成这样的影响,后面渲染流程中,原来很多if都去掉了).
然后了Ogre的渲染流程中,其中SceneManager::_renderScene()调用太多次,如Shadow Map一次,合成器中的render_scene一次,然后他们还没有重复使用剔除的数据,每次renderScene,都重新剔除了一次.特别是合成器中多次调用render_scene,每次都会把渲染队列里的模型全部检查剔除一次,这是无效的操作.
综合这二点,渲染队队肯定要大改,如下是作者综合别的商业渲染引擎,给出的在Ogre2.0中新的实现建议,根据现在Ogre2.1我所看到的代码,已经实现如下图的功能.
这个图后面会简单说下其中的线程相关部分,这就是Ogre2.x的渲染流程了,从图中,我们可以看到新的合成器是Ogre核心中的一部分,已经不是可选组件了,当然新的合成器也有相当大的更新,功能更强大,更好用.其中更详细的部分,后面会专门写一篇介绍Ogre2.x新的渲染流程与合成器.
SIMD,DOD,SoA
在看如下内容时,先介绍一下什么是基于DOD的设计.DOD(面向数据数据),以及我们面向对象OOP常用的OOD(面向对象设计)
DOD与OOD之争: Data oriented design vs Object oriented design
Data-Oriented Design Data-Oriented Design 二 什么是DOD,为什么要使用DOD,什么情况下用DOD
[译]基于数据的设计(Data-oriented design) 这是CSDN上针对第一篇的翻译
有兴趣大家仔细读下,这里总结下DOD相对OOP的优势.简洁高效的并行化,缓存友好.
先看如下 http://stackoverflow.com/questions/12141626/data-oriented-design-in-oop 中提出的一个问题,二代码如下:
void updateAims(float* aimDir, const AimingData* aim, vec3 target, uint count)
{
for(uint i = 0; i < count; i++)
{
aimDir = dot3(aim->positions, target) * aim->mod;
}
}
//OOP
class Bot
{
vec3 position;
float mod;
float aimDir;
void UpdateAim(vec3 target)
{
aimDir = dot3(position, target) * mod;
}
};
void updateBots(Bots* pBots, uint count, vec3 target)
{
for(uint i = 0; i < count; i++)
pBots->UpdateAim(target);
}
};
下面有人解释为什么第一段代码要高效,在第二段代码中,每次得到一个结构域,浪费更多带宽,以及更新无用数据到缓存中,缓存Miss高.第一种一次取一个float块,提高缓存有效利用.
如在游戏中最常见的操作,取得每个模型的MVP矩阵,而OOP告诉我们,要取的位置,先要取得模型.模型还包含许多其它的内容,但是是无用的,占用缓存空间,缓存命中变低.而DOD是把所有的字段存放在一起,一下取的所有位置,请看下面SoA.
下面再次提出二个概念,一个是SoA(Structure of Arrays,非你百度搜出来的SOA),一个是AoS(Arrays of Structure),暂时先说下,SoA是一种DOD里常用的数据组织方式,对应OOP里常用的AoS组织方法.
简单说下,SoA的组织方式,是把一组元素的每个字段连续保存,如下是我针对Ogre2.x里的代码改写的.
没有评论:
发表评论