[完结15章]系统玩转OpenGL+AI,实现各种酷炫视频特效

hbanhgbd · · 827 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
![1.png](http://static.itsharecircle.com/231220/145609053c92992aebaef8bf7040b300.png) 视频特效人才紧缺、需求量大、薪资高,学习正当时,所以今天给大家讲讲关于热门视频特效技术- OpenGL的相关知识,通过本文章,我将带着大家从0到1手把手实现特效美颜相机,让大家系统性掌握OpenGL 核心技术,从而轻松实现各种酷炫的视频特效、吃透视频特效原理,并积累大量图形学/数学知识,助力大家快速成为视频特效技术抢手人才! 那么,首先,我们先来了解一下,什么是OpenGL? OpenGL(Open Graphics Library)是一个跨平台、跨语言的图形编程接口(API)。它被广泛用于实现2D和3D图形渲染,并且是许多应用程序、游戏和网页浏览器的核心组件。 OpenGL主要功能是什么? OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL使用简便,效率高。 OpenGL的glclearcolor在Mesa中的实现是_mesa_ClearColor 函数。该函数用于指定颜色缓冲区的清除值,用于设置清除颜色。 void GLAPIENTRY _mesa_ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) { GET_CURRENT_CONTEXT(ctx); ctx->PopAttribState |= GL_COLOR_BUFFER_BIT; ctx->Color.ClearColor.f[0] = red; ctx->Color.ClearColor.f[1] = green; ctx->Color.ClearColor.f[2] = blue; ctx->Color.ClearColor.f[3] = alpha; } 在pom.xml文件中添加Swagger依赖库,这里我们使用的是Swagger2版本,在UI方面,比Swagger1版本要好看很多。 package com.example.emos.wx.config; import io.swagger.annotations.ApiOperation; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.ApiKey; import springfox.documentation.service.AuthorizationScope; import springfox.documentation.service.SecurityReference; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.ApiSelectorBuilder; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; import java.util.List; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket createRestApi() { Docket docket = new Docket(DocumentationType.SWAGGER_2); // ApiInfoBuilder 用于在Swagger界面上添加各种信息 ApiInfoBuilder builder = new ApiInfoBuilder(); builder.title("EMOS在线办公系统"); ApiInfo apiInfo = builder.build(); docket.apiInfo(apiInfo); // ApiSelectorBuilder 用来设置哪些类中的方法会生成到REST API中 ApiSelectorBuilder selectorBuilder = docket.select(); selectorBuilder.paths(PathSelectors.any()); //所有包下的类 //使用@ApiOperation的方法会被提取到REST API中 selectorBuilder.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)); docket = selectorBuilder.build(); /* * 下面的语句是开启对JWT的支持,当用户用Swagger调用受JWT认证保护的方法, * 必须要先提交参数(例如令牌) */ //存储用户必须提交的参数 List<ApiKey> apikey = new ArrayList(); //规定用户需要输入什么参数 apikey.add(new ApiKey("token", "token", "header")); docket.securitySchemes(apikey); //如果用户JWT认证通过,则在Swagger中全局有效 AuthorizationScope scope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] scopeArray = {scope}; //存储令牌和作用域 SecurityReference reference = new SecurityReference("token", scopeArray); List refList = new ArrayList(); refList.add(reference); SecurityContext context = SecurityContext.builder().securityReferences(refList).build(); List cxtList = new ArrayList(); cxtList.add(context); docket.securityContexts(cxtList); return docket; } } 向后端提交数据之前,我们先要做好前端的数据验证,比如说验证激活码必须是6位数字。 let data = { code: code, nickname: nickName, photo: avatarUrl, registerCode: that.registerCode }; that.ajax(that.url.register, 'POST', data, function(resp) { let permission = resp.data.permission; uni.setStorageSync('permission', permission); //跳转到index页面 }); 在CheckinController类中创建createFaceModel()方法 public class CheckinController { @PostMapping("/createFaceModel") @ApiOperation("创建人脸模型") public R createFaceModel(@RequestParam("photo") MultipartFile file, @RequestHeader("token") String token) { int userId = jwtUtil.getUserId(token); if (file==null) { return R.error("没有上传文件"); } String fileName = file.getOriginalFilename().toLowerCase(); String path = imageFolder + "/" + fileName; if (!fileName.endsWith(".jpg")) { return R.error("必须提交JPG格式图片"); } else { try { file.transferTo(Paths.get(path)); checkinService.createFaceModel(userId, path); return R.ok("人脸建模成功"); } catch (IOException e) { log.error(e.getMessage()); throw new EmosException("保存图片错误"); } finally { FileUtil.del(path); } } } } 编写CheckinController.java中的Web方法,查询用户签到的结果。 public class CheckinController { …… @Autowired private UserService userService; @Autowired private SystemConstants constants; @GetMapping("/searchTodayCheckin") @ApiOperation("查询用户当日签到数据") public R searchTodayCheckin(@RequestHeader("token") String token) { int userId = jwtUtil.getUserId(token); HashMap map = checkinService.searchTodayCheckin(userId); map.put("attendanceTime", constants.attendanceTime); map.put("closingTime", constants.closingTime); long days = checkinService.searchCheckinDays(userId); map.put("checkinDays", days); //判断日期是否在用户入职之前 DateTime hiredate = DateUtil.parse(userService.searchUserHiredate(userId)); DateTime startDate = DateUtil.beginOfWeek(DateUtil.date()); if (startDate.isBefore(hiredate)) { startDate = hiredate; } DateTime endDate = DateUtil.endOfWeek(DateUtil.date()); HashMap param = new HashMap(); param.put("startDate", startDate.toString()); param.put("endDate", endDate.toString()); param.put("userId", userId); ArrayList<HashMap> list = checkinService.searchWeekCheckin(param); map.put("weekCheckin", list); return R.ok().put("result", map); } } 编写TbUserDao.xml文件中的查询语句 <select id="searchUserInfo" parameterType="int" resultType="HashMap"> SELECT u.open_id AS openId, u.nickname, u.name, u.photo, u.sex, u.tel, u.email, d.dept_name AS dept, u.hiredate, CASE u.status WHEN 1 THEN "在职" WHEN 2 THEN "离职" END AS status, ( SELECT GROUP_CONCAT( role_name separator "," ) FROM tb_role WHERE JSON_CONTAINS ( u.role, CONVERT ( id, CHAR ) ) ) AS roles FROM tb_user u LEFT JOIN tb_dept d ON u.dept_id = d.id WHERE u.id = #{userId} AND u.status = 1 </select> <select id="searchDeptManagerId" parameterType="int" resultType="int"> SELECT u2.id FROM tb_user u1 JOIN tb_user u2 ON u1.dept_id=u2.dept_id JOIN tb_role r ON JSON_CONTAINS(u2.role, CAST(r.id AS CHAR)) WHERE u1.id=#{id} AND r.id=2 AND u1.status = 1 AND u2.status = 1 </select> <select id="searchGmId" resultType="int"> SELECT u.id FROM tb_user u JOIN tb_role r ON JSON_CONTAINS(u.role, CAST(r.id AS CHAR)) WHERE r.id=1 AND u.status = 1 </select> 如果你只有一小时的时间学习 OpenGL,并且希望使用 Python,那么你的学习目标应该是理解基本的 OpenGL 概念,同时能够编写一个简单的程序来创建并渲染基本的2D形状 <select id="searchMeetingMembersInSameDept" parameterType="String" resultType="boolean"> SELECT IF(COUNT(DISTINCT u.dept_id)=1,TRUE,FALSE ) AS bool FROM tb_meeting m JOIN tb_user u ON JSON_CONTAINS ( m.members, CAST( u.id AS CHAR ) ) WHERE m.uuid=#{uuid} AND u.status = 1 </select> <update id="updateMeetingInstanceId" parameterType="HashMap"> UPDATE tb_meeting SET instance_id=#{instanceId} WHERE uuid=#{uuid} </update> 编写MeetingServiceImpl中的私有业务方法 public class MeetingServiceImpl implements MeetingService { @Autowired private TbUserDao userDao; @Value("${emos.code}") private String code; @Value("${workflow.url}") private String workflow; @Value("${emos.recieveNotify}") private String recieveNotify; …… private void startMeetingWorkflow(String uuid, int creatorId, String date, String start) { HashMap info = userDao.searchUserInfo(creatorId); //查询创建者用户信息 JSONObject json = new JSONObject(); json.set("url", recieveNotify); json.set("uuid", uuid); json.set("openId", info.get("openId")); json.set("code",code); json.set("date",date); json.set("start",start); String[] roles = info.get("roles").toString().split(","); //如果不是总经理创建的会议 if (!ArrayUtil.contains(roles, "总经理")) { //查询总经理ID和同部门的经理的ID Integer managerId = userDao.searchDeptManagerId(creatorId); json.set("managerId", managerId); //部门经理ID Integer gmId = userDao.searchGmId();//总经理ID json.set("gmId", gmId); //查询会议员工是不是同一个部门 boolean bool = meetingDao.searchMeetingMembersInSameDept(uuid); json.set("sameDept", bool); } String url = workflow+"/workflow/startMeetingProcess"; //请求工作流接口,开启工作流 HttpResponse response = HttpRequest.post(url).header("Content-Type", "application/json").body(json.toString()).execute(); if (response.getStatus() == 200) { json = JSONUtil.parseObj(response.body()); //如果工作流创建成功,就更新会议状态 String instanceId = json.getStr("instanceId"); HashMap param = new HashMap(); param.put("uuid", uuid); param.put("instanceId", instanceId); int row = meetingDao.updateMeetingInstanceId(param); //在会议记录中保存工作流实例的ID if (row != 1) { throw new EmosException("保存会议工作流实例ID失败"); } } } } 综上所述,st_glFinish 函数在 Gallium3D 驱动层面上完成了等待命令完成和刷新前端缓冲区的操作。这是为了确保在继续执行代码之前,所有之前提交的OpenGL命令都已经执行完成,并将最终的渲染结果显示到屏幕上。
827 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传