整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

emsite框架是一个分布式的后台全自动快速开发框架

台简介: emsite框架是一个分布式的后台全自动快速开发框架,采用dubbo作为服务层框架,后台将集成单点登录、Auth2.0、storm+kafka消息处理系统、kafka+ flume+storm+hdfs+hadoop作为日志分析系统、配置中心、分布式任务调度系统、服务器实时监控系统、搜索引擎系统(elasticsearch)。以上各大功能将作为模块化集成到本项目。

框架简介

  • emsite框架是基于众多优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的开源Java EE分布式全自动快速开发框架平台。 系统自带全自动增量发版功能.
  • emsite目前包括以下五大模块,系统管理(SYS)模块、代码生成(GEN)模块、全自动增量发版(PATCH)模块、运营日志分析模块(规划中)、系统监控预警模块(规划中)
1、系统管理模块,包括组织架构(用户管理、机构管理、区域管理)、菜单管理、角色权限管理、字典管理等功能; 
2、代码生成模块,完成重复的工作;
3、全自动增量发版,轻松完成版本快速迭代;
  • emsite框架拥有 全自动增量发版子项目模块 [emsite-patch],该模块可以对git/svn管理的项目进行增量代码生成用于增量发版。总共包含四种生成方案:
1、git服务器分支提交分析;
2、git提交日志分析;
3、svn服务器分支提交分析;
4、svn提交日志分析;

框架规划

  • emsite采用dubbo作为服务层框架,后台将集成单点登录、oauth2.0、storm+kafka消息处理系统、kafka+flume+storm+hdfs+hadoop作为日志分析系统、配置中心、分布式任务调度系统、服务器实时监控系统、搜索引擎系统(elasticsearch),各大功能将作为模块化集成到本项目。
  • emipre团队后期两款产品:
1、在线客服开源系统;
2、统一微信公众号管理平台;

emsite生态圈

01、emsite框架(独立主分支master)
02、emsite微信公众号管理平台(独立分支wxdev)
03、emsite在线客服开源系统(独立项目:[emipre-ons-talk-parent](https://gitee.com/hackempire/empire-ons-talk-parent))
04、emstie框架springboot+springcloud版本(独立项目:[emsite-cloud](https://gitee.com/hackempire/emsite-cloud))
05、emsite框架soa框架(独立项目,远程RPC服务框架【服务熔断、降级、限流、异步、分布式、全链路监控】)
06、增量部署项目,支持git/gitee/svn(独立项目:[patch-generator](https://gitee.com/hackempire/patch-generator-parent))
07、增量部署桌面版项目,支持git/gitee/svn(独立项目:[patch-generator-desk](https://gitee.com/hackempire/patch-generator-desk))
08、全能监控项目地址(独立项目:[omnipotent-monitoring](https://gitee.com/hackempire/omnipotent-monitoring))

框架调整计划表【欢迎有志者加盟】

一阶段:

01、文档整理更新,数据库初始化excel和emsite-mysql.sql脚步同步更新[2018-02-07---2018-02-11]----已完成
02、JavaMelody和druid监控的分布式支持扩展[2018-02-07---2018-02-22]----执行中(ing)
03、代码优化之vo、dto层分离[2018-02-23---2018-03-10]----已结束
04、poi文件导出、导入优化解耦[2018-03-06---2018-03-15]----延期执行
05、分布式任务调度系统集成[2018-03-01---2018-03-05]----延期执行
06、kafka+flume+storm+hdfs+hadoop日志分析系统模块功能开发、当前日志系统架构优化[2018-03-13---2018-04-01]----延期执行
07、框架部署结构动静分离调整[ngnix+httpd],框架文件系统图片资源服务器架构调整[fastDFS][2018-04-01---2018-04-10]----延期执行
08、增量部署系统模块开发【SVN增量方案、GIT增量方案】----已完成
09、Apache ActiveMQ/Apache RocketMQ内部消息系统集成
10、emsite框架配置优化,集成配置中心
11、cas单点登录、jwt权限集成
12、微信公众号第三方平台基础功能开发(公众号管理、自定义菜单管理、粉丝管理、群发管理、素材管理)----计划执行
13、微信接口调用监控功能开发
14、在线客服开源系统
 a.openfire+smack+微信h5+swing/javafx(待定)+sip服务器集成(待定)+软硬电话集成+智能机器人
 备选技术:
 xmpp:Jabber、openfire
 sip:Asterisk、Cipango、FreeSwitch、SIPServer2008、opensips、Kamailio、OpenSER、sipXecx、miniSipServer、Brekeke、
 GNU SIP Witch、Mobicents、Mysipswitch、SailFin、SIP Express Router、sipX、Yate、YXA
 智能机器人:图灵机器人、百度AI机器人、青云客智能聊天机器人
15、微信公众平台插件开发(大转盘、在线门店、微信论坛、微信商城)
16、Solr/Elasticsearch搜索引擎系统集成
17、Swagger2系统开放Api接口文档测试系统集成
18、系统架构部署文档、部署视频教程、wiki文档、系统模块分析文档完善等
19、Jenkins持续集成方案整理
20、远程RPC服务框架开发【服务熔断、降级、限流、异步、分布式、全链路监控】
21、产品全线上线、开启框架培训社区、开启框架交流论坛
22、springboot+springcloud框架版本开发----计划执行
23、Mybatis分页插件PageHelper集成、分页功能解耦----已完成
24、内容管理模块功能删除----已完成

二阶段

25、emsite后台管理系统UI全新升级(备选方案:https://adminlte.io)
26、前后端分离架构调整,框架版本2.0(node.js、bigpipe、KnockoutJS/AngularJS/vueJS/ReactJS待定)
27、dao层优化,集成mybatis-plus----已搁置
28、Activiti工作流+在线OA系统模块开发----已搁置

emsite框架最新动态

1.经项目组研究讨论,由于JavaMelody/druid等分布式扩展后只支持内外IP访问各台服务器,且如需要支持外网分布式监控,需要增加监 
 控域名和Nginx搭配,故该条规划已搁置,转由zabbix server、Tomcat-manager、lambda probe进行全方位监控,后期将开放以上三
 个监控方案的文档至项目QQ群;另外本项目后期将考虑jmx自建部分组件的监控体系,敬请期待[2018-02-18]
2.重大喜讯:阿里巴巴已将dubbo项目已正式成功捐献给apache基金会孵化,由于apache目前还没比dubbo更处理更有力的分布式服务框架
 (soa),故预测dubbo将在不久成为apache顶级项目,且同spring cloud平分soa分布式服务的半壁江山[2018-02-18]
3.重要通知:由于本次dto和vo层改造忘记拉分支,所以将会直接在主分支上进行,提交的代码皆为可允许的代码!如果想拉改造之前的代码
 请进入项目标签中下载[2018-03-08]
4.最新通知:emsite-cloud项目正式立项(进入技术调研筹备阶段),将采用目前最火的技术springboot+springcloud来实现,项目地址
 https://gitee.com/hackempire/emsite-cloud[2018-03-08]
5.经架构分析,后台管理系统部分不适合做dto层拆分.emsite架构将采用前后端架构分离,前台(如微信h5功能)使用dto层作为数据传输对象,
 后台(如微信的数据管理)采用之前的entity作为数据传输对象.另外前后台API隔离,前台部分新开发dubbo接口、dto等.[2018-03-20]
6.框架完成升级到jdk1.8,spring4.2.2.RELEASE,maven打包插件升级到最新版本,全自动增量发版功能[2018-04-07]
7.增量打包桌面版已开发完毕,正式发布版本2.0,请关注patch-generator-desk
 项目地址:https://gitee.com/hackempire/patch-generator-desk[2018-05-01]

内置功能

1、用户管理:用户是系统操作者,该功能主要完成系统用户配置。
2、机构管理:配置系统组织机构(公司、部门、小组),树结构展现,可随意调整上下级。
3、区域管理:系统城市区域模型,如:国家、省市、地市、区县的维护。
4、菜单管理:配置系统菜单,操作权限,按钮权限标识等。
5、角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
6、字典管理:对系统中经常使用的一些较为固定的数据进行维护,如:是否、男女、类别、级别等。
7、操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
8、连接池监视:监视当期系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。

为何选择emsite

1、使用 Apache License 2.0 协议,源代码完全开源,无商业限制。
2、使用目前主流的Java EE开发框架,简单易学,学习成本低。
3、数据库无限制,目前支持MySql、Oracle,可扩充SQL Server、PostgreSQL、H2等。
4、模块化设计,层次结构清晰。内置一系列信息管理的基础功能。
5、操作权限控制精密细致,对所有管理链接都进行权限验证,可控制到按钮。
6、数据权限控制精密细致,对指定数据集权限进行过滤,七种数据权限可供选择。
7、提供在线功能代码生成工具,提高开发效率及质量。
8、提供常用工具类封装,日志、缓存、验证、字典、组织机构等,常用标签(taglib),获取当前组织机构、字典等数据。
9、兼容目前最流行浏览器(IE7+、Chrome、Firefox)。
10、最流行的分布式解决方案。
11、dubbo已正式进入apache基金会孵化,前程似锦,可以说已与spring cloud分别坐拥分布式服务框架的半壁江山.

技术选型

1、后端

a、核心框架:Spring Framework 4.2.2
b、分布式服务框架:dubbo2.5.8、dubbo-admin、dubbo-monitor
c、分布式协调组件:zookeeper3.4.6
d、服务跟踪:Hydra(京东)
e、分布式配置:apollo(携程)/disconf(百度)/diamond(阿里)
d、安全框架:Apache Shiro 1.2
e、视图框架:Spring MVC 4.2.2
f、服务端验证:Hibernate Validator 5.2
g、布局框架:SiteMesh 2.4
h、任务调度:Spring Task 4.2.2
i、持久层框架:MyBatis 3.2
j、数据库连接池:Alibaba Druid 1.0
k、缓存框架:Ehcache 2.6、Redis
l、日志管理:SLF4J 1.7、Log4j
m、数据库管理工具(备份、初始化):dbunit(当前使用)、Flyway
n、工具类:Apache Commons、Jackson 2.2、Xstream 1.4、Dozer 5.3、POI 3.9
o、监控架构:zabbix server、Tomcat-manager、lambda probe、cat
p、持续集成方案:Jenkins

2、前端

a、JS框架:jQuery 1.9。
b、CSS框架:Twitter Bootstrap 2.3.1(稳定后台,UI方面根据需求自己升级改造吧)。
c、客户端验证:JQuery Validation Plugin 1.11。
d、富文本在线编辑:CKEditor
e、在线文件管理:CKFinder
f、动态页签:Jerichotab
g、手机端框架:Jingle
h、数据表格:jqGrid
i、对话框:jQuery jBox
j、下拉选择框:jQuery Select2
k、树结构控件:jQuery zTree
l、日期控件: My97DatePicker

3、平台

a、服务器中间件:在Java EE 5规范(Servlet 3.0、JSP 2.1)下开发,支持应用服务器中间件 有Tomcat 7+、Jboss 7+、
 WebLogic 10+、WebSphere 8+。
b、数据库支持:目前仅提供MySql或Oracle数据库的支持,但不限于数据库,平台留有其它数据库支持接口, 你可以很方便
 的更改为其它数据库,如:SqlServer 2008、MySql 5.5、H2等
c、开发环境:Jdk1.7+(默认jdk1.8)、(Eclipse Java EE 4.3|sts-3.6.2.RELEASE|myeclipse10)、Maven 3.2+、Git

安全考虑

a、开发语言:系统采用Java 语言开发,具有卓越的通用性、高效性、平台移植性和安全性。
b、分层设计:(数据库层,数据访问层,业务逻辑层,展示层)层次清楚,低耦合,各层必须通过接口才能接入并进行参数校
 验(如:在展示层不可直接操作数据库),保证数据操作的安全。
c、双重验证:用户表单提交双验证:包括服务器端验证及客户端验证,防止用户通过浏览器恶意修改(如不可写文本域、隐藏
 变量篡改、上传非法文件等),跳过客户端验证操作数据库。
d、安全编码:用户表单提交所有数据,在服务器端都进行安全编码,防止用户提交非法脚本及SQL注入获取敏感数据等,确保数据安全。
e、密码加密:登录用户密码进行SHA1散列加密,此加密方法是不可逆的。保证密文泄露后的安全问题。
f、强制访问:系统对所有管理端链接都进行用户身份权限验证,防止用户
g、服务监控:系统采用dubbo的服务全链路监控技术、可以做到精准定位服务情况

快速体验

a、具备运行环境:JDK1.7+、Maven3.2+(建议3.5.3)、MySql5+或Oracle10g+。
b、下载emsite-parent项目,导入第三方ckfinder插件jar包到本地maven库
c、修改src\main\resources\emsite.properties文件中的数据库设置参数。
d、根据修改参数创建对应MySql或Oracle数据库用户和参数。
e、新建数据库emsite[字符集utf8 -- UTF-8 Unicode,排序规则utf8-bin],运行db\init-db.bat脚本,即可导入表结构及演示数
 据(linux操作系统:在控制台中切换至项目根目录,运行命令:mvn antrun:run -Pinit-db);或者直接在数据库工具中运行emsite 
 web项目db目录下的emsite_mysql.sql文件。
f、启动redis,zookeeper组件
g、启动emsite-service-dbs数据服务层项目,使用eclipse maven启动命令:clean tomcat7:run(校验:http://localhost:端口/emsite- 
 service-dbs出现HelloWorld页面)
h、启动emsite web服务器项目,运行目录下bin\run-tomcat7.bat或bin\run-jetty.bat 或使用eclipse maven启动命令:clean 
 tomcat7:run(第一次运行,需要下载依赖jar包,请耐心等待,校验:http://localhost:端口/emsite出现后台登录页面)。
i、最高管理员账号,用户名:emsite 密码:admin 

常见问题

a、用一段时间提示内存溢出,请修改JVM参数:-Xmx512m -XX:MaxPermSize=256m
b、有时出现文字乱码:修改Tomcat的server.xml文件的Connector项,增加URIEncoding="UTF-8"
c、为什么新建菜单后看不到新建的菜单?因为授权问题,菜单管理只允许最高管理员账号管理(最高管理员默认账号:emsite密码:admin)。 
d、第三方ckfinder导入方案[ckfinder包放在emsite项目下lib文件夹中]
 mvn install:install-file -DgroupId=com.ckfinder -DartifactId=ckfinder -Dversion=2.3 -Dpackaging=jar - 
 Dfile=D:/thirdxsd/ckfinder-2.3.jar
 mvn install:install-file -DgroupId=com.ckfinder -DartifactId=ckfinderplugin-fileeditor -Dversion=2.3 -Dpackaging=jar -
 Dfile=D:/thirdxsd/ckfinderplugin-fileeditor-2.3.jar
 mvn install:install-file -DgroupId=com.ckfinder -DartifactId=ckfinderplugin-imageresize -Dversion=2.3 -Dpackaging=jar - 
 Dfile=D:/thirdxsd/ckfinderplugin-imageresize-2.3.jar
 mvn install:install-file -DgroupId=com.empire -DartifactId=patch-generator -Dversion=0.0.1-SNAPSHOT -Dpackaging=jar - 
 Dfile=D:/thirdxsd/patch-generator-0.0.1-SNAPSHOT.jar
e、项目类文件报错或者jar包不存在
 解决方法:
 1.eclipse点击project->clean->选择emsite所有模块->ok 
 2.选择emsite-parent父项目->右键->debug as->maven -clean
 3.选择emsite-parent父项目->右键->debug as->maven -install
 4.选中报emsite其它jar模块引入失败的项目->右键->maven->update project->选中online、force Update of Snapshots/Releases、
 update project configuration from pom.xml、Refresh workspace resources from local filesystem、clean project等选项
 ->点击ok
 5.更新完成然后重复上面2、3步骤,问题解决
f、maven报错Project configuration is not up-to-date with pom.xml错误解决方法(导入项目之后发现有一个如下的错误:Project 
 configuration is not up-to-date with pom.xml. Run project configuration) 
 update
 其实这个问题解决非常简单:
 在项目上右键——【Maven】——【Update Project Configuration……】
 这时会打开一个(Update Maven Dependencies)的对话框,然后勾选住出错的项目,点击Ok,这样就搞定了。
g、dubbo服务链追踪与监控
 下载dubbo-monitor或dubbo-admin监控项目进行部署
h、项目spring配置文件spring-context-dubbo.xml报错dubbo标签不支持,请用开发工具关联在emsite项目lib文件夹下面的dubbo.xsd.
i、更换其它数据库需修改配置文件emsite.property中数据库连接配置,如果添加子项目模块并且修改为其它数据库,需要新建Global并且覆盖
 emsite-service-common-api中Global类的jdbcType方法用于支持数据库分页插件.
j、项目启动报dubbo配置的service无法启动,删除emsite->webapp->web-info->classes文件夹下面的所有文件
k、如果在jdk8中用maven-tomcat插件运行项目报无效的1.8目标,请在环境中M2_HOME为最新apache-maven-3.5.3,并且将eclipse中jdk配置
 Default VM agrments设置:-Dmaven.multiModuleProjectDirectory=M2_HOME

项目结构:

01、emsite-parent----------------maven-parent模块 
02、emsite-service-common-api----common-service-api
03、emsite-service-common-dbs----common-service-dbs
04、emsite-service-api-----------core-service-api
05、emsite-service-dbs-----------core-service-dbs
06、emsite-----------------------emsite-web后台管理
07、emsite-patch-----------------emsite增量发版模块

运行效果:

运行内存:

spring-tool-suite(sts开发工具)JVM配置如下:

 -vmargs
 -Dosgi.requiredJavaVersion=1.6
 -Xverify:none
 -Xms1536m
 -Xmx1536m
 -Xmn512m
 -XX:NewSize=512m
 -XX:MaxNewSize=512m
 -XX:PermSize=256m
 -XX:MaxPermSize=256m
 -XX:+DisableExplicitGC
 -Xnoclassgc
 -XX:+UseParNewGC
 -XX:+UseConcMarkSweepGC
 -XX:CMSInitiatingOccupancyFraction=85
 -XX:+PrintGCDetails
 -XX:+PrintGCDateStamps
 -Xloggc:d:/sts-3.6.2.RELEASE/gc.log
 -Dorg.eclipse.swt.browser.IEVersion=10001
 -Dcon.sun.management.jmxremote

1.emsite-service-dbs内存效果图:

2.emsite内存效果图

增量打包:

git地址:https://gitee.com/hackempire/emsite-parent

须先转发,转发,转发,加“大数据java架构师”关注,然后私信

jeesite”即可免费获取源码下载地址

1.平台简介

JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的开源Java EE快速开发平台。

JeeSite本身是以Spring Framework为核心容器,Spring MVC为模型视图控制器,MyBatis为数据访问层, Apache Shiro为权限授权层,Ehcahe对常用数据进行缓存,Activit为工作流引擎。

JeeSite主要定位于企业信息化领域,已内置企业信息化系统的基础功能和高效的代码生成工具,包括:系统权限组件、数据权限组件、数据字典组件、核心工具组件、视图操作组件、工作流组件、代码生成等。前端界面风格采用了结构简单、性能优良、页面美观大气的Twitter Bootstrap页面展示框架。采用分层设计、双重验证、提交数据安全编码、密码加密、访问验证、数据权限验证。使用Maven做项目管理,提高项目的易开发性、扩展性。

JeeSite目前包括以下三大模块,系统管理(SYS)模块、内容管理(CMS)模块、在线办公(OA)模块、代码生成(GEN)模块。 系统管理模块 ,包括企业组织架构(用户管理、机构管理、区域管理)、菜单管理、角色权限管理、字典管理等功能; 内容管理模块 ,包括内容管理(文章、链接),栏目管理、站点管理、公共留言、文件管理、前端网站展示等功能; 在线办公模块 ,提供简单的请假流程实例。

JeeSite 提供了常用工具进行封装,包括日志工具、缓存工具、服务器端验证、数据字典、当前组织机构数据(用户、机构、区域)以及其它常用小工具等。另外还提供一个强大的在线 代码生成 工具,此工具提供简单的单表、一对多、树结构功能的生成,如果对外观要求不是很高,生成的功能就可以用了。如果你使用了JeeSite基础框架,就可以很高效的快速开发出,优秀的信息管理系统。

2.内置功能

1.用户管理:用户是系统操作者,该功能主要完成系统用户配置。

2.机构管理:配置系统组织机构(公司、部门、小组),树结构展现,可随意调整上下级。

3.区域管理:系统城市区域模型,如:国家、省市、地市、区县的维护。

4.菜单管理:配置系统菜单,操作权限,按钮权限标识等。

5.角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。

6.字典管理:对系统中经常使用的一些较为固定的数据进行维护,如:是否、男女、类别、级别等。

7.操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。

8.连接池监视:监视当期系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。

9.工作流引擎:实现业务工单流转、在线流程设计器。

3.开发工具

1.Eclipse IDE:采用Maven项目管理,模块化。

2.在线演示:演示系统常用组件的使用代码,内嵌地图案例等。

3.代码生成:通过界面方式简单配置,自动生成相应代码,目前包括三种生成方式(增删改查):单表、一对多、树结构。生成后的代码如果不需要注意美观程度,生成后即可用。

4.设计思想

1、分层设计:(数据访问层,业务逻辑层,展示层)层次清楚,低耦合,各层必须通过接口才能接入并进行参数校验(如:在展示层不可直接操作数据库),保证数据操作的安全。

2、双重验证:用户表单提交双验证:包括服务器端验证及客户端验证,防止用户通过浏览器恶意修改(如不可写文本域、隐藏变量篡改、上传非法文件等)而跳过客户端验证操作数据库。

3、安全编码:用户表单提交所有数据,在服务器端都进行安全编码,防止用户提交非法脚本及SQL注入获取敏感数据等,确保数据安全。

4、密码加密:登录用户密码进行SHA1散列加密,此加密方法是不可逆的。保证密文泄露后的安全问题。

5、访问验证:系统对所有管理端链接都进行用户身份权限验证,防止用户直接通过URL进行未授权页面。

6、数据验证:对指定数据集权限进行过滤,七种数据权限可供选择(所有权限,公司及子公司,本公司,部门及子部门,本部门,本人数据,跨机构数据)

7、快速编码:提供基本功能模块的源代码生成器,提高开发效率及质量。

5.技术选型

1、后端

* 核心框架:Spring Framework 4.0

* 安全框架:Apache Shiro 1.2

* 视图框架:Spring MVC 4.0

* 服务端验证:Hibernate Validator 5.1

* 布局框架:SiteMesh 2.4

* 工作流引擎:Activiti 5.15

* 任务调度:Spring Task 4.0

* 持久层框架:MyBatis 3.2

* 数据库连接池:Alibaba Druid 1.0

* 缓存框架:Ehcache 2.6、Redis

* 日志管理:SLF4J 1.7、Log4j

* 工具类:Apache Commons、Jackson 2.2、Xstream 1.4、Dozer 5.3、POI 3.9

2、前端

* JS框架:JQuery 1.9。

* CSS框架:Twitter Bootstrap 2.3.1。

* 客户端验证:JQuery Validation Plugin 1.11。

* 富文本:CKEcitor

* 文件管理:CKFinder

* 动态页签:Jerichotab

* 手机端框架:Jingle

* 数据表格:jqGrid

* 对话框:jQuery jBox

* 下拉选择框:jQuery Select2

* 树结构控件:jQuery zTree

* 日期控件: My97DatePicker

4、平台

* 服务器中间件:在Java EE 5规范(Servlet 2.5、JSP 2.1)下开发,支持应用服务器中间件

有Tomcat 6、Jboss 7、WebLogic 10、WebSphere 8。

* 数据库支持:目前仅提供Oracle数据库的支持,但不限于数据库,平台留有其它数据库支持接口,

可方便更改为其它数据库,如:SqlServer 2008、MySql 5.5、H2等

* 开发环境:Java EE、Eclipse、Maven、Git

6.必会基础知识

1.软件工程基础、Java语言基础、JSP内置对象、EL表达式

2.Spring Framework:类的依赖、自动注入、事务处理

3.Spring MVC:URL映射、参数传递

4.Apache Shiro:安全拦截方式,应用方法,控制按钮

5.SiteMesh:布局框架的用法

6.JSP标准标签库(JSTL):if、choose、forEach、set

7.Spring MVC表单标签库:form、input、textarea、select、checkbox

8.文件存放规范,命名规范。

7.学习索引

1.Spring Framework :

•跟我学Spring3

2.Spring MVC

•跟开涛学Spring MVC

•JSP语法、Spring Form、JSTL、EL

•Bean Validation

3.Apache Shiro

•官方文档

•快速入门

4.SiteMesh 2.4

•官方文档

•入门实例、标签使用、装饰文件

5.Bootstrap 2.3

•Bootstrap官网

•Bootstrap中文网

6.jQuery

•jQuery API:官方文档 中文文档

•jQuery Validation:官方文档 使用范例

•jQuery zTree: 官方文档

•jQruey jBox:官方文档

7.Activiti

•官方网站

•中文文档

•咖啡兔Activiti

8.Ehcache

•官方文档

•EhCache分布式缓存

9.其它资料

•Alibaba Druid

•FreeMarker

8.安装部署

1.运行Maven目录下的settings.bat文件,用来设置maven仓库路径,并按提示操作(设置PATH系统变量、配置Eclipse)。

2.执行jeesite/bin/eclipse.bat 生成工程文件并下载jar依赖包(如果需要修改默认项目名,请打开pom.xml修改第7行artifactId,然后再执行eclipse.bat文件)。

3.将 jeesite 工程导入到eclipse,选中工程,按F5刷新。

4.设置数据源:src/main/resources/jeesite.properties

5.导入数据表并初始化数据:运行db/init-db.bat文件。(导入时如果出现“drop”失败提示信息,请忽略。)

6.新建Server(Tomcat),注意选择以下两个选项:

7.配置server.xml的Connector项,增加URIEncoding="UTF-8"

8.部署到Tomcat,设置Auto Reload为Disabled。

9.访问工程:http://127.0.0.1:8080/ jeesite 用户名:thinkgem 密码:admin

9.常见问题

1.'mvn' 不是内部或外部命令,原因如下

a)PATH未配置或配置了多个不一致的Maven地址,如用户/系统变量。

b)M2_HOME系统/用户变量地址不正确,可删除M2_HOME变量。

c)检查mvn运行是否正常,cmd执行:mvn -v

2.运行eclipse.bat 找不到文件路径或乱码:一般原因是路径中包含空格或中文。

3.导入到eclipse下找不到jar包:maven未配置,查看m2_repo仓库路径是否正确。

4.运行init-db.bat提示ORA-xxx:根据错误码排除错误,一般是数据库url不对,用户名或密码错误。

5.部署时出现某某被锁定,一般原因:Tomcat服务中的两个选项未选中。

6.字典列表,添加键值,出现乱码:server.xml未配置url编码为utf-8。

管理功能

内容管理

内容发布

概述

· 栏目列表:以树结构方式显示网站整体设置的栏目,点击在右侧可管理当前栏目的信息。

· 文章列表:当前栏目如果为文章模型的话,左侧则显示文章列表,如果为链接模型,左侧则显示链接列表。

· 内容模型,包括:新闻文章、友情链接:

1、 文章模型:对新闻、资料进行管理

1) 强大的可视化内容在线编辑器:提供常用的内容排版工具条;Word内容直接复制,格式不乱;提供通用模板排版格式;图片、Flash上传及添加附件功能。

2) 文件管理:提供上传的照片、文件增删功能。

3) 关键字:提供文章关键字功能。

4) 权重:提供文章排序功能,值越大越靠前。

5) 缩略图:文章缩略图片。

6) 相关文章:关联相关文章。

7) 推荐位:可推荐到首页焦点图、栏目文章推荐等。

8) 发布时间:可修改发布时间。

2、 链接模型:如友情链接内容。

文章列表

· 查询:可通过栏目选择,文章标题(模糊),文档状态查询。

· 栏目列:点击后可快速进行查询当前点击的栏目。

· 标题列:点击后可会计进入文章查看或修改页面。

· 操作列:提供文章的操作;

· 访问:快速预览发布后的页面;

· 修改:进行文章编辑修改

· 删除:删除当前文章,删除操作为逻辑删除,删除后在文章状态删除中可查询到,可恢复。

添加/修改文章

· 归属栏目:该栏目下有子栏目的不能选择。

· 标题:必填项,文章标题,最长255个汉字;颜色:标题颜色。

· 外部链接:如果当前文章不是本站文档,可选择"外部链接"设置外部链接地址,打开改文章时直接执行改地址。

· 关键字:发布文章关键字信息,设置后显示在页面的关键字标签里,录入可提高搜索引擎优化排名。

· 权重:设置文章的排列顺序,数值越大越靠前;可通过"置顶"复选框快速设置权重为999;也可通过设置"过期时间"设置置顶时间,超过指定时间后,置顶自动失效,并设置为0;过期时间为空,表示不过期。

· 摘要:文章的摘要信息,不超过255个汉字。

· 缩略图:提供文章图片功能,如图片新闻(438 × 268像素)等。

· 正文:文章的正文,可视化在线编辑器,提供常用的内容排版工具条;Word内容直接复制,格式不乱;提供通用模板排版格式;图片、Flash上传及添加附件功能。

· 添加图片:可进行从服务器上浏览一副以前上传的图片,也可链接其它网站图片,可以自己手动上传一副图片,操作界面如下:

· 添加附件:可进行修改链接标题,可服务器上选择或手动上传(小于5M),同图片,操作界面如下:

· 来源:填写文章的出处,来源等信息。

· 相关文章:可选择与该文章相关的文章,提供阅读者进行延伸阅读。

· 发布状态:文章的状态(发布、审核、删除),如果当前登录无发布权限,则直接进入审核状态,文章审核后才可进行正式发布。

· 查看评论:如果当前为意见征集模块,则可查看征集信息。

发布信息审核

审核需要审核的文章,如通知通告,有信息员发布后,管理员可通过此功能对信息进行审核发布。

统计分析

信息量统计

统计一段时间内的信息发布量及点击量。

评论管理

管理列表

允许评论的文章,评论后需管理员进行审核后才能展示到页面上。有该功能的人员可对待审核的评论进行审核操作。

栏目管理

概述

树形表格界面,可折叠;设置灵活,可随意调整栏目父子关系;支持无限级子栏目;支持栏目排序;支持多种内容模型(文章模型、链接模型等),支持上传栏目缩了图;支持设置栏目描述及关键字,提升搜索引擎排行。

1、 导航栏显示:设置是否在网站主导航栏中显示。

2、 分类页中显示列表:是否在二级页面中显示内容列表。

3、 展现方式:

1) 默认方式:有子栏目,显示子栏目内容列表;无子栏目,直接显示该栏目的内容列表。

2) 首栏目内容列表:显示第一个子栏目的内容列表。

3) 栏目第一条内容:显示该栏目中的第一篇内容。

列表

添加、修改

站点管理

概述

对站点进行维护,支持多站点发布,可设置站点标题、描述、关键字、版权信息、模板风格等。

列表

添加、修改

站点切换

当存在多站点发布的情况下,可通过该功能进行站点切换。

公共留言

概述

留言管理:姓名、邮箱、单位、电话、留言分类(咨询、建议、批评、其它)留言内容。

列表

审核

网站开发步骤

基础数据维护

1、 进入站点设置,并确定默认站点为当前站点。

2、 进入栏目设置,给当前站点设置和维护栏目,维护完成可访问:http://127.0.0.1:8080/jeesite/f 预览站点。

建立自己的主题

1、 完成数据维护下一步开始新建站点主题风格,进入字典管理,给"内容管理-站点主题 | cms_theme"字典,增加一个主题。

2、 进入站点设置,设置默认站点的:名称、描述、版权、主题(刚建立的主题)、首页视图等信息。

3、 复制 /src/main/webapp/WEB-INF/views/modules/cms/front/themes下的basic文件夹(为了对照方便,不要直接修改),重命名为自己设计的主题名称(刚建立的主题,字典键值)。

4、 到这里初始化工作基本完成,下一步开始编辑你的主题文件即可。

主题模板介绍

1、 首页模板:frontIndex.jsp, 命名格式:frontIndex*.jsp

2、 文章列表页:frontList.jsp, 命名格式:frontList*.jsp

3、 文章详情页:frontViewArticle.jsp,命名格式:frontViewArticle*.jsp

4、 文章评论:frontComment.jsp

5、 公众留言:frontGuestbook.jsp

6、 站点地图:frontMap.jsp

7、 站点搜索:frontSearch.jsp

模板中的标签可参看fnc.tld文件。具体用法可参看以上模板文件;使用它,你可以不用动后台一处代码,只需要修改你配置和模板文件,即可快速完成网站开发。

14

https://github.com/thinkgem/jeesite

内容管理模块

功能说明

ThinkGem

2014年6月17日

目录1.管理功能31.1.内容管理31.1.1.内容发布31.1.2.统计分析81.1.3.评论管理81.1.4.栏目管理91.1.5.站点管理101.1.6.公共留言12

管理功能

内容管理

内容发布

概述

· 栏目列表:以树结构方式显示网站整体设置的栏目,点击在右侧可管理当前栏目的信息。

· 文章列表:当前栏目如果为文章模型的话,左侧则显示文章列表,如果为链接模型,左侧则显示链接列表。

· 内容模型,包括:新闻文章、友情链接:

1、 文章模型:对新闻、资料进行管理

1) 强大的可视化内容在线编辑器:提供常用的内容排版工具条;Word内容直接复制,格式不乱;提供通用模板排版格式;图片、Flash上传及添加附件功能。

2) 文件管理:提供上传的照片、文件增删功能。

3) 关键字:提供文章关键字功能。

4) 权重:提供文章排序功能,值越大越靠前。

5) 缩略图:文章缩略图片。

6) 相关文章:关联相关文章。

7) 推荐位:可推荐到首页焦点图、栏目文章推荐等。

8) 发布时间:可修改发布时间。

2、 链接模型:如友情链接内容。

文章列表

· 查询:可通过栏目选择,文章标题(模糊),文档状态查询。

· 栏目列:点击后可快速进行查询当前点击的栏目。

· 标题列:点击后可会计进入文章查看或修改页面。

· 操作列:提供文章的操作;

· 访问:快速预览发布后的页面;

· 修改:进行文章编辑修改

· 删除:删除当前文章,删除操作为逻辑删除,删除后在文章状态删除中可查询到,可恢复。

添加/修改文章

· 归属栏目:该栏目下有子栏目的不能选择。

· 标题:必填项,文章标题,最长255个汉字;颜色:标题颜色。

· 外部链接:如果当前文章不是本站文档,可选择"外部链接"设置外部链接地址,打开改文章时直接执行改地址。

· 关键字:发布文章关键字信息,设置后显示在页面的关键字标签里,录入可提高搜索引擎优化排名。

· 权重:设置文章的排列顺序,数值越大越靠前;可通过"置顶"复选框快速设置权重为999;也可通过设置"过期时间"设置置顶时间,超过指定时间后,置顶自动失效,并设置为0;过期时间为空,表示不过期。

· 摘要:文章的摘要信息,不超过255个汉字。

· 缩略图:提供文章图片功能,如图片新闻(438 × 268像素)等。

· 正文:文章的正文,可视化在线编辑器,提供常用的内容排版工具条;Word内容直接复制,格式不乱;提供通用模板排版格式;图片、Flash上传及添加附件功能。

· 添加图片:可进行从服务器上浏览一副以前上传的图片,也可链接其它网站图片,可以自己手动上传一副图片,操作界面如下:

· 添加附件:可进行修改链接标题,可服务器上选择或手动上传(小于5M),同图片,操作界面如下:

· 来源:填写文章的出处,来源等信息。

· 相关文章:可选择与该文章相关的文章,提供阅读者进行延伸阅读。

· 发布状态:文章的状态(发布、审核、删除),如果当前登录无发布权限,则直接进入审核状态,文章审核后才可进行正式发布。

· 查看评论:如果当前为意见征集模块,则可查看征集信息。

发布信息审核

审核需要审核的文章,如通知通告,有信息员发布后,管理员可通过此功能对信息进行审核发布。

统计分析

信息量统计

统计一段时间内的信息发布量及点击量。

评论管理

管理列表

允许评论的文章,评论后需管理员进行审核后才能展示到页面上。有该功能的人员可对待审核的评论进行审核操作。

栏目管理

概述

树形表格界面,可折叠;设置灵活,可随意调整栏目父子关系;支持无限级子栏目;支持栏目排序;支持多种内容模型(文章模型、链接模型等),支持上传栏目缩了图;支持设置栏目描述及关键字,提升搜索引擎排行。

1、 导航栏显示:设置是否在网站主导航栏中显示。

2、 分类页中显示列表:是否在二级页面中显示内容列表。

3、 展现方式:

1) 默认方式:有子栏目,显示子栏目内容列表;无子栏目,直接显示该栏目的内容列表。

2) 首栏目内容列表:显示第一个子栏目的内容列表。

3) 栏目第一条内容:显示该栏目中的第一篇内容。

列表

添加、修改

站点管理

概述

对站点进行维护,支持多站点发布,可设置站点标题、描述、关键字、版权信息、模板风格等。

列表

添加、修改

站点切换

当存在多站点发布的情况下,可通过该功能进行站点切换。

公共留言

概述

留言管理:姓名、邮箱、单位、电话、留言分类(咨询、建议、批评、其它)留言内容。

列表

审核

网站开发步骤

基础数据维护

1、 进入站点设置,并确定默认站点为当前站点。

2、 进入栏目设置,给当前站点设置和维护栏目,维护完成可访问:http://127.0.0.1:8080/jeesite/f 预览站点。

建立自己的主题

1、 完成数据维护下一步开始新建站点主题风格,进入字典管理,给"内容管理-站点主题 | cms_theme"字典,增加一个主题。

2、 进入站点设置,设置默认站点的:名称、描述、版权、主题(刚建立的主题)、首页视图等信息。

3、 复制 /src/main/webapp/WEB-INF/views/modules/cms/front/themes下的basic文件夹(为了对照方便,不要直接修改),重命名为自己设计的主题名称(刚建立的主题,字典键值)。

4、 到这里初始化工作基本完成,下一步开始编辑你的主题文件即可。

主题模板介绍

1、 首页模板:frontIndex.jsp, 命名格式:frontIndex*.jsp

2、 文章列表页:frontList.jsp, 命名格式:frontList*.jsp

3、 文章详情页:frontViewArticle.jsp,命名格式:frontViewArticle*.jsp

4、 文章评论:frontComment.jsp

5、 公众留言:frontGuestbook.jsp

6、 站点地图:frontMap.jsp

7、 站点搜索:frontSearch.jsp

模板中的标签可参看fnc.tld文件。具体用法可参看以上模板文件;使用它,你可以不用动后台一处代码,只需要修改你配置和模板文件,即可快速完成网站开发。

必须先转发,转发,转发,加“大数据java架构师”关注,然后私信

“jeesite”即可免费获取源码下载地址

者 | 天元浪子

责编 | 伍杏玲

出品 | CSDN 博客

【CSDN 编者按】OpenGL(开放式图形库),用于渲染 2D、3D 矢量图形的跨语言、跨平台的应用程序编程接口,C、C++、Python、Java等语言都能支持 OpenGL。本文作者以 Python 语法为例,用两万字详解 OpenGL 的理论知识、用法与实际操作,干货满满,一起来看看吧。

预备知识

OpenGL 是 Open Graphics Library 的简写,意为“开放式图形库”,是用于渲染 2D、3D 矢量图形的跨语言、跨平台的应用程序编程接口(API)。OpenGL 不是一个独立的平台,因此,它需要借助于一种编程语言才能被使用。C / C++ / Python / Java 都可以很好支持 OpengGL,我当然习惯性选择 Python 语言。

如果读者是 Python 程序员,并且了解 NumPy,接下来的阅读应该不会有任何障碍;否则,我建议先花半小时学习一下 Python 语言。关于 Python ,可以参考我的另一篇博文《数学建模三剑客MSN》。事实上,我觉得 Python 语言近乎于自然语言,只要读者是程序员,即便不熟悉 Python ,读起来也不会有多大问题。

另外,读者也不必担心数学问题。使用 OpenGL 不需要具备多么高深的数学水平,只要能辅导初中学生的数学作业,就足够用了。

一、坐标系

在 OpenGL 的世界里,有各式各样的坐标系。随着对 OpenGL 概念的理解,我们至少会接触到六种坐标系,而初始只需要了解其中的三个就足够用了(第一次阅读这段话的时候,只需要了解世界坐标系就可以了)。

  • 世界坐标系(World Coordinates)

世界坐标系是右手坐标系,以屏幕中心为原点(0, 0, 0),且是始终不变的。

  • 视点坐标系(Eye or Camera Coordinates)

视点坐标是以视点为原点,以视线的方向为Z+轴正方向的坐标系。OpenGL 管道会将世界坐标先变换到视点坐标,然后进行裁剪,只有在视线范围(视景体)之内的场景才会进入下一阶段的计算。

  • 屏幕坐标系(Window or Screen Coordinates)

OpenGL 的重要功能之一就是将三维的世界坐标经过变换、投影等计算,最终算出它在显示设备上对应的位置,这个位置就称为设备坐标。在屏幕、打印机等设备上的坐标是二维坐标。值得一提的是,OpenGL 可以只使用设备的一部分进行绘制,这个部分称为视区或视口(viewport)。投影得到的是视区内的坐标(投影坐标),从投影坐标到设备坐标的计算过程就是设备变换了。

二、投影

三维场景中的物体最终都会显示在类似屏幕这样的二维观察平面上。将三维物体变为二维图形的变换成为投影变换。最常用的投影有两种:平行投影和透视投影。如下图所示,F 是投影面,p1p2 为三维空间中的一条直线,p’1 和 p’2 分别是 p1 和 p2 在 F 上的投影,虚线表示投影线,O 为投影中心。

  • 平行投影

这里所说的平行投影,特指正交平行投影——投影线垂直于投影面。将一个三维点 (x,y,z) 正交平行投影到 xoy 平面上,则投影点坐标为 (x,y,0)。由于平行投影丢弃了深度信息,所以无法产生真实感,但可以保持物体之间相对大小关系不变。

  • 透视投影

透视投影将投影面置于观察点和投影对象之间,距离观察者越远的物体,投影尺寸越小,投影效果具有真实感,常用于游戏和仿真领域。

三、视景体

无论是平行投影还是透视投影,投影成像都是在投影面上——我们可以把投影面理解成显示屏幕。世界坐标系描述的三维空间是无限的,投影平面是无限的,但(我们能够看到的)屏幕面积总是有限的,因此在投影变换时,通常只处理能够显示在屏幕上的那一部分三维空间。从无限三维空间中裁切出来的可以显示在屏幕上的部分三维空间,我们称之为视景体。视景体有六个面,分别是左右上下和前后面。

对于平行投影而言,视景体是一个矩形平行六面体;对于透视投影来说,视景体是一个棱台。理解这一点并不难:因为越远处的物体在投影窗口的透视投影越小,也就意味着填满投影窗口需要更大的体量,视景体自然就变成了棱台。

四、视口

对于平行投影而言,视口就是由视景体的左右上下四个面围成的矩形,对于透视投影来说,视口就是视景体的前截面在投影窗口上的透视投影。

视口是 OpenGL 中比较重要的概念,现阶段可以简单理解成屏幕(或其他输出设备)。事实上,视口和屏幕是相关但又不相同的,屏幕有固定的宽高比,而视口大小可以由用户自行定义。通常,为了适应不同宽高比的屏幕,在设置视口时,会根据屏幕宽高比调整视景体(增加宽度或高度)。

五、视点

现实生活中,人们看到的三维空间物体的样子取决于观察者站在什么角度去看。这里面包含着三个概念:

  • 观察者的位置:眼睛在哪儿?

  • 观察者的姿势:站立还是倒立?左侧卧还是右侧卧?

  • 观察对象:眼睛盯着哪里?

对应在 OpenGL 中,也有同样的概念,即视点的位置、瞄准方向的参考点,以及(向上的)方向。

六、OpenGL 变换

下图是三维图形的显示流程。世界坐标系中的三维物体经过视点变换和一系列几何变换(平移、旋转、缩放)之后,坐标系变换为视点坐标系;经过投影和裁剪之后,坐标系变换为归一化设备坐标系;最后经过视口变换显示在屏幕上,相应地,坐标系变成了窗口坐标系。

  • 视点变换:相当于设置视点的位置和方向

  • 模型变换:包括平移、旋转、缩放等三种类型

  • 裁剪变换:根据视景体定义的六个面(和附加裁剪面)对三维空间裁剪

  • 视口变换:将视景体内投影的物体显示在二维的视口平面上

安装 PyOpenGL

如果想当然地使用 pip 如下所示安装,可能会有一些麻烦。

pip install pyopengl

当我这样安装之后,运行 OpenGL 代码,得到了这样的错误信息:

FunctionError: Attempt to call an undefined function glutInit, check for bool(glutInit) before calling

原来,pip 默认安装的是32位版本的PyOpenGL,而我的操作系统是64位的。建议点击这里下载适合自己的版本,直接安装.whl文件。我是这样安装的:

pip install PyOpenGL-3.1.3b2-cp37-cp37m-win_amd64.whl

OpenGL 库及函数简介

我第一次接触 OpenGL 的 GL / GLU / GLUT 的时候,一下就被这些长得像孪生兄弟的库名字给整懵圈了,要不是内心强大,也许就跟 OpenGL 说再见了。时间久了才发现,OpenGL 的库及函数命名规则非常合理,便于查找、记忆:

OpenGL函数的命名格式如下:

<库前缀><根命令><可选的参数个数><可选的参数类型>

常见的库前缀有 gl、glu、glut、aux、wgl、glx、agl 等。库前缀表示该函数属于 OpenGL 哪一个开发库。从函数名后面中还可以看出需要多少个参数以及参数的类型。I 代表 int 型,f 代表 float 型,d 代表 double 型,u 代表无符号整型。例如 glColor3f 表示了该函数属于gl库,参数是三个浮点数。

OpenGL 函数库相关的 API 有核心库(gl)、实用库(glu)、实用工具库(glut)、辅助库(aux)、窗口库(glx、agl、wgl)和扩展函数库等。gl是核心,glu是对gl的部分封装。glut是为跨平台的OpenGL程序的工具包,比aux功能强大。glx、agl、wgl 是针对不同窗口系统的函数。扩展函数库是硬件厂商为实现硬件更新利用OpenGL的扩展机制开发的函数。本文仅对常用的四个库做简单介绍。

一、OpenGL 核心库 GL

核心库包含有115个函数,函数名的前缀为gl。这部分函数用于常规的、核心的图形处理。此函数由gl.dll来负责解释执行。由于许多函数可以接收不同数以下几类。据类型的参数,因此派生出来的函数原形多达300多个。核心库中的函数主要可以分为以下几类函数:

  • 绘制基本几何图元的函数:

    glBegain、glEnd、glNormal*、glVertex*

  • 矩阵操作、几何变换和投影变换的函数:

    如矩阵入栈函数glPushMatrix,矩阵出栈函数glPopMatrix,装载矩阵函数glLoadMatrix,矩阵相乘函数glMultMatrix,当前矩阵函数glMatrixMode和矩阵标准化函数glLoadIdentity,几何变换函数glTranslate*、glRotate*和glScale*,投影变换函数glOrtho、glFrustum和视口变换函数glViewport

  • 颜色、光照和材质的函数:

    如设置颜色模式函数glColor*、glIndex*,设置光照效果的函数glLight* 、glLightModel*和设置材质效果函数glMaterial

  • 显示列表函数:

    主要有创建、结束、生成、删除和调用显示列表的函数glNewList、glEndList、glGenLists、glCallList和glDeleteLists

  • 纹理映射函数:

    主要有一维纹理函数glTexImage1D、二维纹理函数glTexImage2D、设置纹理参数、纹理环境和纹理坐标的函数glTexParameter*、glTexEnv*和glTetCoord*

  • 特殊效果函数:

    融合函数glBlendFunc、反走样函数glHint和雾化效果glFog*

  • 光栅化、象素操作函数:

    如象素位置glRasterPos*、线型宽度glLineWidth、多边形绘制模式glPolygonMode,读取象素glReadPixel、复制象素glCopyPixel

  • 选择与反馈函数:

    主要有渲染模式glRenderMode、选择缓冲区glSelectBuffer和反馈缓冲区glFeedbackBuffer

  • 曲线与曲面的绘制函数:

    生成曲线或曲面的函数glMap*、glMapGrid*,求值器的函数glEvalCoord* glEvalMesh*

  • 状态设置与查询函数:

    glGet*、glEnable、glGetError

二、OpenGL 实用库 GLU

包含有43个函数,函数名的前缀为glu。OpenGL提供了强大的但是为数不多的绘图命令,所有较复杂的绘图都必须从点、线、面开始。Glu 为了减轻繁重的编程工作,封装了OpenGL函数,Glu函数通过调用核心库的函数,为开发者提供相对简单的用法,实现一些较为复杂的操作。此函数由glu.dll来负责解释执行。OpenGL中的核心库和实用库可以在所有的OpenGL平台上运行。主要包括了以下几种:

  • 辅助纹理贴图函数:

    gluScaleImage 、gluBuild1Dmipmaps、gluBuild2Dmipmaps

  • 坐标转换和投影变换函数:

    定义投影方式函数gluPerspective、gluOrtho2D 、gluLookAt,拾取投影视景体函数gluPickMatrix,投影矩阵计算gluProject和gluUnProject

  • 多边形镶嵌工具:

    gluNewTess、gluDeleteTess、gluTessCallback、gluBeginPolygon、gluTessVertex、gluNextContour、gluEndPolygon

  • 二次曲面绘制工具:

    主要有绘制球面、锥面、柱面、圆环面gluNewQuadric、gluSphere、gluCylinder、gluDisk、gluPartialDisk、gluDeleteQuadric

  • 非均匀有理B样条绘制工具:

    主要用来定义和绘制Nurbs曲线和曲面,包括gluNewNurbsRenderer、gluNurbsCurve、gluBeginSurface、gluEndSurface、gluBeginCurve、gluNurbsProperty

  • 错误反馈工具:

    获取出错信息的字符串gluErrorString

三、OpenGL 工具库 GLUT

包含大约30多个函数,函数名前缀为glut。glut是不依赖于窗口平台的OpenGL工具包,由Mark KLilgrad在SGI编写(现在在Nvidia),目的是隐藏不同窗口平台API的复杂度。函数以glut开头,它们作为aux库功能更强的替代品,提供更为复杂的绘制功能,此函数由glut.dll来负责解释执行。

由于glut中的窗口管理函数是不依赖于运行环境的,因此OpenGL中的工具库可以在X-Window、Windows NT、OS/2等系统下运行,特别适合于开发不需要复杂界面的OpenGL示例程序。对于有经验的程序员来说,一般先用glut理顺3D图形代码,然后再集成为完整的应用程序。这部分函数主要包括:

  • 窗口操作函数:

    窗口初始化、窗口大小、窗口位置函数等 glutInit、glutInitDisplayMode、glutInitWindowSize、glutInitWindowPosition

  • 回调函数:

    响应刷新消息、键盘消息、鼠标消息、定时器函数 GlutDisplayFunc、glutPostRedisplay、glutReshapeFunc、glutTimerFunc、glutKeyboardFunc、glutMouseFunc

  • 创建复杂的三维物体:

    这些和aux库的函数功能相同。

  • 菜单函数:

    创建添加菜单的函数 GlutCreateMenu、glutSetMenu、glutAddMenuEntry、glutAddSubMenu 和 glutAttachMenu

  • 程序运行函数:

    glutMainLoop

四、Windows 专用库 WGL

针对Windows平台的扩展,包含有16个函数,函数名前缀为wgl。这部分函数主要用于连接OpenGL和Windows ,以弥补OpenGL在文本方面的不足。Windows专用库只能用于Windows环境中。这类函数主要包括以下几类:

  • 绘图上下文相关函数:

    wglCreateContext、wglDeleteContext、wglGetCurrentContent、wglGetCurrentDC、wglDeleteContent

  • 文字和文本处理函数:

    wglUseFontBitmaps、wglUseFontOutlines

  • 覆盖层、地层和主平面层处理函数:

    wglCopyContext、wglCreateLayerPlane、wglDescribeLayerPlane、wglReakizeLayerPlatte

  • 其他函数:

    wglShareLists、wglGetProcAddress

开始 OpenGL 的奇幻之旅

一、OpenGL 基本图形的绘制

  • 设置颜色

设置颜色的函数有几十个,都是以 glColor 开头,后面跟着参数个数和参数类型。参数可以是 0 到 255 之间的无符号整数,也可以是 0 到 1 之间的浮点数。三个参数分别表示 RGB 分量,第四个参数表示透明度(其实叫不透明度更恰当)。以下最常用的两个设置颜色的方法:

glColor3f(1.0,0.0,0.0) # 设置当前颜色为红色

glColor4f(0.0,1.0,1.0,1.0) # 设置当前颜色为青色,不透明度

glColor3ub(0, 0, 255) # 设置当前颜色为蓝色

glColor 也支持将三个或四个参数以向量方式传递,例如:

glColor3fv([0.0,1.0,0.0]) # 设置当前颜色为绿色

特别提示:OpenGL 是使用状态机模式,颜色是一个状态变量,设置颜色就是改变这个状态变量并一直生效,直到再次调用设置颜色的函数。除了颜色,OpenGL 还有很多的状态变量或模式。在任何时间,都可以查询每个状态变量的当前值,还可以用 glPushAttrib 或 glPushClientAttrib 把状态变量的集合保存起来,必要的时候,再用 glPopAttrib 或 glPopClientAttrib 恢复状态变量。

  • 设置顶点

顶点(vertex)是 OpengGL 中非常重要的概念,描述线段、多边形都离不开顶点。和设置颜色类似,设置顶点的函数也有几十个,都是以 glVertex 开头,后面跟着参数个数和参数类型,同样也支持将多个以向量方式传递。两个参数的话,分别表示 xy 坐标,三个参数则分别表示 xyz 坐标。如有第四个参数,则表示该点的齐次坐标 w;否则,默认 w=1。至于什么是齐次坐标,显然超出了初中数学的范畴,在此不做探讨。

glVertex2f(1.0,0.5) # xoy平面上的点,z=0

glVertex3f(0.5,1.0,0.0) # 三维空间中的点

  • 绘制基本图形

仅仅设置颜色和顶点,并不能画出来什么。我们可以在任何时候改变颜色,但所有的顶点设置,都必须包含在 glBegin 和 glEnd 之间,而 glBegin 的参数则指定了将这些顶点画成什么。以下是 glBegin 可能的参数选项:

二、第一个 OpenGL 程序

通常,我们使用工具库(GLUT)创建 OpenGL 应用程序。为啥不用 GL 或者 GLU 库呢?画画之前总得先有一块画布吧,不能直接拿起画笔就开画。前文说过,工具库主要提供窗口相关的函数,有了窗口,就相当于有了画布,而核心库和实用库,就好比各式各样的画笔、颜料。使用工具库(GLUT)创建 OpenGL 应用程序只需要四步(当然,前提是你需要先准备好绘图函数,并给它取一个合适的名字):

  • 初始化glut库

  • 创建glut窗口

  • 注册绘图的回调函数

  • 进入glut主循环

OK,铺垫了这么多之后,我们终于开始第一个 OpenGL 应用程序了:绘制三维空间的世界坐标系,在坐标原点的后方(z轴的负半区)画一个三角形。代码如下:

# -*- coding: utf-8 -*-

# -------------------------------------------

# quidam_01.py 三维空间的世界坐标系和三角形

# -------------------------------------------

from OpenGL.GL import *

from OpenGL.GLUT import *

def draw:

# ---------------------------------------------------------------

glBegin(GL_LINES) # 开始绘制线段(世界坐标系)

# 以红色绘制x轴

glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明

glVertex3f(-0.8, 0.0, 0.0) # 设置x轴顶点(x轴负方向)

glVertex3f(0.8, 0.0, 0.0) # 设置x轴顶点(x轴正方向)

# 以绿色绘制y轴

glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明

glVertex3f(0.0, -0.8, 0.0) # 设置y轴顶点(y轴负方向)

glVertex3f(0.0, 0.8, 0.0) # 设置y轴顶点(y轴正方向)

# 以蓝色绘制z轴

glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明

glVertex3f(0.0, 0.0, -0.8) # 设置z轴顶点(z轴负方向)

glVertex3f(0.0, 0.0, 0.8) # 设置z轴顶点(z轴正方向)

glEnd # 结束绘制线段

# ---------------------------------------------------------------

glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴负半区)

glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明

glVertex3f(-0.5, -0.366, -0.5) # 设置三角形顶点

glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明

glVertex3f(0.5, -0.366, -0.5) # 设置三角形顶点

glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明

glVertex3f(0.0, 0.5, -0.5) # 设置三角形顶点

glEnd

# 结束绘制三角形

# ---------------------------------------------------------------

glFlush # 清空缓冲区,将指令送往硬件立即执行

if __name__ == "__main__":

glutInit # 1. 初始化glut库

glutCreateWindow('Quidam Of OpenGL') # 2. 创建glut窗口

glutDisplayFunc(draw) # 3. 注册回调函数draw

glutMainLoop # 4. 进入glut主循环

运行代码,我这里显示结果如下面左图所示。如果尝试运行这段代码出错的话,我猜应该是 PyOpenGL 安装出现了问题,建议返回到前面重读 PyOpenGL 的安装。

短暂的激动之后,你可能会尝试画一些其他的线段,变换颜色或者透明度,甚至绘制多边形。很快你会发现,我们的第一个程序有很多问题,比如:

  1. 窗口的标题不能使用中文,否则会显示乱码

  2. 窗口的初始大小和位置无法改变

  3. 改变窗口的宽高比,三角形宽高比也会改变(如上面右图所示)

  4. 三角形不应该遮挡坐标轴

  5. 改变颜色的透明度无效

  6. 不能缩放旋转

没关系,除了第1个问题我不知道怎么解决(貌似无解),其他问题都不是事儿。和我们的代码相比,一个真正实用的 OpenGL 程序,还有许多工作要做:

  • 设置初始显示模式

  • 初始化画布

  • 绘图函数里面需要增加:清除屏幕及深度缓存、投影设置、模型试图设置

  • 绑定鼠标键盘的事件函数

三、设置初始显示模式

初始化 glut 库的时候,我们一般都要用 glutInitDisplayMode 来设置初始的显示模式,它的参数可以是下表中参数的组合。

使用双缓存窗口,可以避免重绘时产生抖动的感觉。我一般选择 GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH 作为参数来设置初始的显示模式。

四、初始化画布

开始绘图之前,需要对画布做一些初始化工作,这些工作只需要做一次。比如:

glClearColor(0.0, 0.0, 0.0, 1.0) # 设置画布背景色。注意:这里必须是4个参数

glEnable(GL_DEPTH_TEST) # 开启深度测试,实现遮挡关系

glDepthFunc(GL_LEQUAL) # 设置深度测试函数(GL_LEQUAL只是选项之一)

如有必要,还可以开启失真校正(反走样)、开启表面剔除等。

五、清除屏幕及深度缓存

每次重绘之前,需要先清除屏幕及深度缓存。这项操作一般放在绘图函数的开头。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

六、设置投影

投影设置也是每次重绘都需要的步骤之一。glOrtho 用来设置平行投影,glFrustum 用来设置透视投影。这两个函数的参数相同,都是视景体的 left / right / bottom / top / near / far 六个面。

视景体的 left / right / bottom / top 四个面围成的矩形,就是视口。near 就是投影面,其值是投影面距离视点的距离,far 是视景体的后截面,其值是后截面距离视点的距离。far 和 near 的差值,就是视景体的深度。视点和视景体的相对位置关系是固定的,视点移动时,视景体也随之移动。

我个人认为,视景体是 OpengGL 最重要、最核心的概念,它和视口、视点、投影面、缩放、漫游等概念密切关联。只有正确理解了视景体,才能正确设置它的六个参数,才能呈现出我们期望的效果。

为了在窗口宽高比改变时,绘制的对象仍然保持固定的宽高比,一般在做投影变换时,需要根据窗口的宽高比适当调整视景体的 left / right 或者 bottom / top 参数。

假设 view 是视景体,width 和 height 是窗口的宽度和高度,在投影变换之前,需要先声明是对投影矩阵的操作,并将投影矩阵单位化:

glMatrixMode(GL_PROJECTION)

glLoadIdentity

if width > height:

k = width / height

glFrustum(view [0]*k, view [1]*k, view [2], view [3], view [4], view [5])

else:

k = height / width

glFrustum(view [0], view [1], view [2]*k, view [3]*k, view [4], view [5])

七、设置视点

视点是和视景体关联的概念。设置视点需要考虑眼睛在哪儿、看哪儿、头顶朝哪儿,分别对应着eye、lookat 和 eye_up 三个向量。

gluLookAt(

eye[0], eye[1], eye[2],

look_at[0], look_at[1], look_at[2],

eye_up[0], eye_up[1], eye_up[2]

)

八、设置视口

视口也是和视景体关联的概念,相对简单一点。

glViewport(0, 0, width, height)

九、设置模型视图

模型平移、旋转、缩放等几何变换,需要切换到模型矩阵:

glMatrixMode(GL_MODELVIEW)

glLoadIdentity

glScale(1.0, 1.0, 1.0)

十、捕捉鼠标事件、键盘事件和窗口事件

GLUT 库提供了几个函数帮我们捕捉鼠标事件、键盘事件和窗口事件:

  • glutMouseFunc

    该函数捕捉鼠标点击和滚轮操作,返回4个参数给被绑定的事件函数:键(左键/右键/中键/滚轮上/滚轮下)、状态(1/0)、x坐标、y坐标

  • glutMotionFunc

    该函数捕捉有一个鼠标键被按下时的鼠标移动给被绑定的事件函数,返回2个参数:x坐标、y坐标

  • glutPassiveMotionFunc

    该函数捕捉鼠标移动,返回2个参数给被绑定的事件函数:x坐标、y坐标

  • glutEntryFunc

    该函数捕捉鼠标离开或进入窗口区域,返回1个参数给被绑定的事件函数:GLUT_LEFT 或者 GLUT_ENTERED

    glutKeyboardFunc(keydown)

    该函数捕捉键盘按键被按下,返回3个参数给被绑定的事件函数:被按下的键,x坐标、y坐标

  • glutReshapeFunc

    该函数捕捉窗口被改变大小,返回2个参数给被绑定的事件函数:窗口宽度、窗口高度

如果我们需要捕捉这些事件,只需要定义事件函数,注册相应的函数就行:

def reshape(width, height):

pass

def mouseclick(button, state, x, y):

pass

def mousemotion(x, y):

pass

def keydown(key, x, y):

pass

glutReshapeFunc(reshape) # 注册响应窗口改变的函数reshape

glutMouseFunc(mouseclick) # 注册响应鼠标点击的函数mouseclick

glutMotionFunc(mousemotion) # 注册响应鼠标拖拽的函数mousemotion

glutKeyboardFunc(keydown) # 注册键盘输入的函数keydown

十一、综合应用

是时候把我们上面讲的这些东西完整的演示一下了。下面的代码还是画了世界坐标系,并在原点前后各画了一个三角形。鼠标可以拖拽视点绕参考点旋转(二者距离保持不变),滚轮可以缩放模型。

敲击退格键或回车键可以让视点远离或接近参考点。敲击 x/y/z 可以减小参考点对应的坐标值,敲击 X/Y/Z 可以增大参考点对应的坐标值。敲击空格键可以切换投影模式。

上图左是平行投影模式的显示效果,上图右是透视投影模式的显示效果。代码如下:

# -*- coding: utf-8 -*-

# -------------------------------------------

# quidam_02.py 旋转、缩放、改变视点和参考点

# -------------------------------------------

from OpenGL.GL import *

from OpenGL.GLU import *

from OpenGL.GLUT import *

import numpy as np

IS_PERSPECTIVE = True # 透视投影

VIEW = np.array([-0.8, 0.8, -0.8, 0.8, 1.0, 20.0]) # 视景体的left/right/bottom/top/near/far六个面

SCALE_K = np.array([1.0, 1.0, 1.0]) # 模型缩放比例

EYE = np.array([0.0, 0.0, 2.0]) # 眼睛的位置(默认z轴的正方向)

LOOK_AT = np.array([0.0, 0.0, 0.0]) # 瞄准方向的参考点(默认在坐标原点)

EYE_UP = np.array([0.0, 1.0, 0.0]) # 定义对观察者而言的上方(默认y轴的正方向)

WIN_W, WIN_H = 640, 480 # 保存窗口宽度和高度的变量

LEFT_IS_DOWNED = False # 鼠标左键被按下

MOUSE_X, MOUSE_Y = 0, 0 # 考察鼠标位移量时保存的起始位置

def getposture:

global EYE, LOOK_AT

dist = np.sqrt(np.power((EYE-LOOK_AT), 2).sum)

if dist > 0:

phi = np.arcsin((EYE[1]-LOOK_AT[1])/dist)

theta = np.arcsin((EYE[0]-LOOK_AT[0])/(dist*np.cos(phi)))

else:

phi = 0.0

theta = 0.0

return dist, phi, theta

DIST, PHI, THETA = getposture # 眼睛与观察目标之间的距离、仰角、方位角

def init:

glClearColor(0.0, 0.0, 0.0, 1.0) # 设置画布背景色。注意:这里必须是4个参数

glEnable(GL_DEPTH_TEST) # 开启深度测试,实现遮挡关系

glDepthFunc(GL_LEQUAL) # 设置深度测试函数(GL_LEQUAL只是选项之一)

def draw:

global IS_PERSPECTIVE, VIEW

global EYE, LOOK_AT, EYE_UP

global SCALE_K

global WIN_W, WIN_H

# 清除屏幕及深度缓存

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

# 设置投影(透视投影)

glMatrixMode(GL_PROJECTION)

glLoadIdentity

if WIN_W > WIN_H:

if IS_PERSPECTIVE:

glFrustum(VIEW[0]*WIN_W/WIN_H, VIEW[1]*WIN_W/WIN_H, VIEW[2], VIEW[3], VIEW[4], VIEW[5])

else:

glOrtho(VIEW[0]*WIN_W/WIN_H, VIEW[1]*WIN_W/WIN_H, VIEW[2], VIEW[3], VIEW[4], VIEW[5])

else:

if IS_PERSPECTIVE:

glFrustum(VIEW[0], VIEW[1], VIEW[2]*WIN_H/WIN_W, VIEW[3]*WIN_H/WIN_W, VIEW[4], VIEW[5])

else:

glOrtho(VIEW[0], VIEW[1], VIEW[2]*WIN_H/WIN_W, VIEW[3]*WIN_H/WIN_W, VIEW[4], VIEW[5])

# 设置模型视图

glMatrixMode(GL_MODELVIEW)

glLoadIdentity

# 几何变换

glScale(SCALE_K[0], SCALE_K[1], SCALE_K[2])

# 设置视点

gluLookAt(

EYE[0], EYE[1], EYE[2],

LOOK_AT[0], LOOK_AT[1], LOOK_AT[2],

EYE_UP[0], EYE_UP[1], EYE_UP[2]

)

# 设置视口

glViewport(0, 0, WIN_W, WIN_H)

# ---------------------------------------------------------------

glBegin(GL_LINES) # 开始绘制线段(世界坐标系)

# 以红色绘制x轴

glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明

glVertex3f(-0.8, 0.0, 0.0) # 设置x轴顶点(x轴负方向)

glVertex3f(0.8, 0.0, 0.0) # 设置x轴顶点(x轴正方向)

# 以绿色绘制y轴

glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明

glVertex3f(0.0, -0.8, 0.0) # 设置y轴顶点(y轴负方向)

glVertex3f(0.0, 0.8, 0.0) # 设置y轴顶点(y轴正方向)

# 以蓝色绘制z轴

glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明

glVertex3f(0.0, 0.0, -0.8) # 设置z轴顶点(z轴负方向)

glVertex3f(0.0, 0.0, 0.8) # 设置z轴顶点(z轴正方向)

glEnd # 结束绘制线段

# ---------------------------------------------------------------

glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴负半区)

glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明

glVertex3f(-0.5, -0.366, -0.5) # 设置三角形顶点

glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明

glVertex3f(0.5, -0.366, -0.5) # 设置三角形顶点

glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明

glVertex3f(0.0, 0.5, -0.5) # 设置三角形顶点

glEnd # 结束绘制三角形

# ---------------------------------------------------------------

glBegin(GL_TRIANGLES) # 开始绘制三角形(z轴正半区)

glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明

glVertex3f(-0.5, 0.5, 0.5) # 设置三角形顶点

glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明

glVertex3f(0.5, 0.5, 0.5) # 设置三角形顶点

glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明

glVertex3f(0.0, -0.366, 0.5) # 设置三角形顶点

glEnd # 结束绘制三角形

# ---------------------------------------------------------------

glutSwapBuffers # 切换缓冲区,以显示绘制内容

def reshape(width, height):

global WIN_W, WIN_H

WIN_W, WIN_H = width, height

glutPostRedisplay

def mouseclick(button, state, x, y):

global SCALE_K

global LEFT_IS_DOWNED

global MOUSE_X, MOUSE_Y

MOUSE_X, MOUSE_Y = x, y

if button == GLUT_LEFT_BUTTON:

LEFT_IS_DOWNED = state==GLUT_DOWN

elif button == 3:

SCALE_K *= 1.05

glutPostRedisplay

elif button == 4:

SCALE_K *= 0.95

glutPostRedisplay

def mousemotion(x, y):

global LEFT_IS_DOWNED

global EYE, EYE_UP

global MOUSE_X, MOUSE_Y

global DIST, PHI, THETA

global WIN_W, WIN_H

if LEFT_IS_DOWNED:

dx = MOUSE_X - x

dy = y - MOUSE_Y

MOUSE_X, MOUSE_Y = x, y

PHI += 2*np.pi*dy/WIN_H

PHI %= 2*np.pi

THETA += 2*np.pi*dx/WIN_W

THETA %= 2*np.pi

r = DIST*np.cos(PHI)

EYE[1] = DIST*np.sin(PHI)

EYE[0] = r*np.sin(THETA)

EYE[2] = r*np.cos(THETA)

if 0.5*np.pi < PHI < 1.5*np.pi:

EYE_UP[1] = -1.0

else:

EYE_UP[1] = 1.0

glutPostRedisplay

def keydown(key, x, y):

global DIST, PHI, THETA

global EYE, LOOK_AT, EYE_UP

global IS_PERSPECTIVE, VIEW

if key in [b'x', b'X', b'y', b'Y', b'z', b'Z']:

if key == b'x': # 瞄准参考点 x 减小

LOOK_AT[0] -= 0.01

elif key == b'X': # 瞄准参考 x 增大

LOOK_AT[0] += 0.01

elif key == b'y': # 瞄准参考点 y 减小

LOOK_AT[1] -= 0.01

elif key == b'Y': # 瞄准参考点 y 增大

LOOK_AT[1] += 0.01

elif key == b'z': # 瞄准参考点 z 减小

LOOK_AT[2] -= 0.01

elif key == b'Z': # 瞄准参考点 z 增大

LOOK_AT[2] += 0.01

DIST, PHI, THETA = getposture

glutPostRedisplay

elif key == b'\r': # 回车键,视点前进

EYE = LOOK_AT + (EYE - LOOK_AT) * 0.9

DIST, PHI, THETA = getposture

glutPostRedisplay

elif key == b'\x08': # 退格键,视点后退

EYE = LOOK_AT + (EYE - LOOK_AT) * 1.1

DIST, PHI, THETA = getposture

glutPostRedisplay

elif key == b' ': # 空格键,切换投影模式

IS_PERSPECTIVE = not IS_PERSPECTIVE

glutPostRedisplay

if __name__ == "__main__":

glutInit

displayMode = GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH

glutInitDisplayMode(displayMode)

glutInitWindowSize(WIN_W, WIN_H)

glutInitWindowPosition(300, 200)

glutCreateWindow('Quidam Of OpenGL')

init # 初始化画布

glutDisplayFunc(draw) # 注册回调函数draw

glutReshapeFunc(reshape) # 注册响应窗口改变的函数reshape

glutMouseFunc(mouseclick) # 注册响应鼠标点击的函数mouseclick

glutMotionFunc(mousemotion) # 注册响应鼠标拖拽的函数mousemotion

glutKeyboardFunc(keydown) # 注册键盘输入的函数keydown

glutMainLoop # 进入glut主循环

十二、小结

虽然还有很多领域需要我们继续探索,比如灯光、材质、雾化、拾取等,但那不是奇幻之旅的目标。奇幻之旅仅仅是帮助读者建立 OpenGL 的基本概念。至此,我们基本完成了任务。

加速渲染

实际应用 OpenGL 绘制三维图像时,往往需要处理数以万计的顶点,有时甚至是百万级、千万级。我们通常不会在绘制函数里面传送这些数据,而是在绘制之前,将这些数据提前传送到GPU。绘制函数每次绘制时,只需要从GPU的缓存中取出数据即可,极大地提高了效率。这个机制地实现,依赖于顶点缓冲区对象(Vertex Buffer Object),简称VBO。

尽管 VBO 是显卡的扩展,其实没有用到GPU运算,也就是说 VBO 不用写着色语言,直接用opengl函数就可以调用,主要目的是用于加快渲染的速。

VBO 将顶点信息放到 GPU 中,GPU 在渲染时去缓存中取数据,二者中间的桥梁是 GL-Context。GL-Context 整个程序一般只有一个,所以如果一个渲染流程里有两份不同的绘制代码,GL-context 就负责在他们之间进行切换。这也是为什么要在渲染过程中,在每份绘制代码之中会有 glBindbuffer、glEnableVertexAttribArray、glVertexAttribPointer。如果把这些都放到初始化时候完成,使用一种结构记录该次绘制所需要的所有 VBO 所需信息,把它保存到 VBO特定位置,绘制的时候直接在这个位置取信息绘制,会简化渲染流程、提升渲染速度。这就是 VAO 概念产生的初衷。

VAO 的全名是 Vertex Array Object,首先,它不是 Buffer-Object,所以不用作存储数据;其次,它针对“顶点”而言,也就是说它跟“顶点的绘制”息息相关。VAO 记录的是一次绘制中所需要的信息,这包括“数据在哪里 glBindBuffer”、“数据的格式是怎么样的 glVertexAttribPointer”、shader-attribute 的 location 的启用 glEnableVertexAttribArray。

根据我查到的资料,几乎所有的显卡都支持 VBO,但不是所有的显卡都支持 VAO,而 VAO 仅仅是优化了 VBO 的使用方法,对于加速并没有实质性的影响,因此本文只讨论 VBO 技术。

一、创建顶点缓冲区对象(VBO)

假定画一个六面体,顶点是这样的:

# -*- coding: utf-8 -*-

# 六面体数据

# ------------------------------------------------------

# v4----- v5

# /| /|

# v0------v1|

# | | | |

# | v7----|-v6

# |/ |/

# v3------v2

# 顶点集

vertices = np.array([

-0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, # v0-v1-v2-v3

-0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5 # v4-v5-v6-v7

], dtype=np.float32)

# 索引集

indices = np.array([

0, 1, 2, 3, # v0-v1-v2-v3 (front)

4, 5, 1, 0, # v4-v5-v1-v0 (top)

3, 2, 6, 7, # v3-v2-v6-v7 (bottom)

5, 4, 7, 6, # v5-v4-v7-v6 (back)

1, 5, 6, 2, # v1-v5-v6-v2 (right)

4, 0, 3, 7 # v4-v0-v3-v7 (left)

], dtype=np.int)

在GPU上创建VBO如下:

from OpenGL.arrays import vbo

vbo_vertices = vbo.VBO(vertices)

vbo_indices = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER)

创建 顶点 VBO 时,默认 target=GL_ARRAY_BUFFER, 而创建索引 VBO 时,target=GL_ELEMENT_ARRAY_BUFFER,因为顶点的数据类型是 np.float32,索引的数据类型是np.int。

在VBO保存的顶点数据集,除了顶点信息外,还可以包含颜色、法线、纹理等数据,这就是顶点混合数组的概念。假定我们在上面的顶点集中增加每个顶点的颜色,则可以写成这样:

vertices = np.array([

0.3, 0.6, 0.9, -0.35, 0.35, 0.35, # c0-v0

0.6, 0.9, 0.3, 0.35, 0.35, 0.35, # c1-v1

0.9, 0.3, 0.6, 0.35, -0.35, 0.35, # c2-v2

0.3, 0.9, 0.6, -0.35, -0.35, 0.35, # c3-v3

0.6, 0.3, 0.9, -0.35, 0.35, -0.35, # c4-v4

0.9, 0.6, 0.3, 0.35, 0.35, -0.35, # c5-v5

0.3, 0.9, 0.9, 0.35, -0.35, -0.35, # c6-v6

0.9, 0.9, 0.3, -0.35, -0.35, -0.35 # c7-v7

], dtype=np.float32)

二、分离顶点混合数组

使用 glInterleavedArrays 函数可以从顶点混合数组中分离顶点、颜色、法线和纹理。比如,对只包含顶点信息的顶点混合数组:

vbo_indices.bind

glInterleavedArrays(GL_V3F, 0, None)

如果顶点混合数组包含了颜色和顶点信息:

vbo_indices.bind

glInterleavedArrays(GL_C3F_V3F, 0, None)

glInterleavedArrays 函数第一个参数总共有14个选项,分别是:

  • GL_V2F

  • GL_V3F

  • GL_C4UB_V2F

  • GL_C4UB_V3F

  • GL_C3F_V3F

  • GL_N3F_V3F

  • GL_C4F_N3F_V3F

  • GL_T2F_V3F

  • GL_T4F_V4F

  • GL_T2F_C4UB_V3F

  • GL_T2F_C3F_V3F

  • GL_T2F_N3F_V3F

  • GL_T2F_C4F_N3F_V3F

  • GL_T4F_C4F_N3F_V4F

三、使用顶点缓冲区对象(VBO)

使用glDrawElements 等函数绘制前,需要先绑定顶点数据集和索引数据集,然后使用glInterleavedArrays 分理出顶点、颜色、法线等数据。

vbo_indices.bind

glInterleavedArrays(GL_V3F, 0, None)

vbo_indices.bind

glDrawElements(GL_QUADS, int(vbo_indices .size/4), GL_UNSIGNED_INT, None)

vbo_indices.unbind

vbo_indices.unbind

致谢:

写作过程中,我参考了很多资料,包括纸质书籍和网页,列写于此,一并致谢!

  • 《OpenGL编程精粹》杨柏林 陈根浪 徐静 编著

  • Opengl开发库介绍

  • OpenGL的API函数使用手册

  • glut处理鼠标事件

  • Learn OpenGL

原文:https://blog.csdn.net/xufive/article/details/86565130

声明:本文系CSDN博客原创文章,转载请联系原作者。

【End】

“只讲技术,拒绝空谈!”2019 AI开发者大会将于9月6日-7日在北京举行,这一届AI开发者大会有哪些亮点?一线公司的大牛们都在关注什么?AI行业的风向是什么?2019 AI开发者大会,倾听大牛分享,聚焦技术实践,和万千开发者共成长。

目前,大会盲订票限量发售中~扫码购票,领先一步!