![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命令都已经执行完成,并将最终的渲染结果显示到屏幕上。
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传