最近有幸总结了一下kanzi中opengl的东西,实际比较重点的也就是shader部分,对于其他部分,这里也会简单的说,但是具体的功能作用就要自己下来慢慢研究了

一:引言

本文章主要介绍kanzi和opengl之间的一些问题,可能会比较杂,因为很多东西也无法预测他们具体是如何结合,故我们会以kanzi为主,在kanzi的基础上介绍opengl的一些东西。

通过kanzi help doc中的opengl接口,我们可以了解kanzi也是支持modern opengl,故老的opengl接口是不支持的。具体接口可见<system/wrappers/kzs_opengl.h>

这里的东西比较杂,我们不会具体的说,这里会分几个大块来针对性的说明。

二:具体介绍

一:着色器

一:shader(着色器)

着色器(Shader)是用来实现图像渲染的,用来替代固定渲染管线的可编辑程序。其中Vertex Shader主要负责顶点的几何关系等的运算,Pixel Shader(Fragment Shader)主要负责片源颜色等的计算。

着色器替代了传统的固定渲染管线,可以实现3D图形学计算中的相关计算,由于其可编辑性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制。

目前比较流行的Shader语言除了GLSL之外还有HLSL,RM等,当然,我们目前主要使用GLSL。

Opengl的绘图管线

当然,这部分opengl的部分这里只是简单介绍。我们只需知道整个工作流程即可。

  1. 准备顶点数据:

在CPU中进行。这里会定义一些VAO和VBO,他们包含了每个一些顶点数据的信息,在shader中的体现即attribute。

在kanzi中,我们定义的EmptyNode2D或者Image2D...在这部分的体现即会准备不重复的4个点即重复的6个点,构成2个三角形。然后会将这些点绑定到VAO或者VBO中,发送给GPU。

  1. Vertex Processing:

调用Vertex Shader处理顶点数据信息。这个阶段会接受传递过来的attribute数据作为输入,然后通过一些转换后输出。每个顶点都是1对1。

Kanzi中我们可以看到attribute属性的有kzPosition,kzTextureCoordinate0及其他。

  1. Primitive Assembly

图元装配:即把vertex shader输出的顶点数据集合到一起,并把它组合成一个图元的过程。这个输出的类型由用户决定,一般输出的是三角形,这个取决于你drawcall的类型。

  1. Geometry Shading: 这个目前不做介绍,它即对Primitive Assembly输出的图元处理后再输出图元。
  1. Rasterization

光栅化:一系列处理后的图元会被光栅化为一系列的‘候选像素点’。

  1. Fragment Processing

调用Fragment shader处理像素点。处理后我们只需要得到out的像素即gl_FragColor。

  1. Pre-Fragment :
  2. 生成frame buffer后GPU显示出来。

这部分东西很多,而我们应该了解的东西总结一下:

  1. Fragment Shader处理像素点,故一些运算如果可以放到Vertex shader中最好。
  2. 变量的属性:

Attribute:输入的定点属性,无法改变。

Uniform:用户定义的属性,可在外部改变。

Varying:在vertex shader和fragment shader传递变量

  1. Float精度

highp:

mediump:

lowp:

使用默认精度可加precision mediump float;

  1. 着色器尽量简单。

二:brush及Material

Kanzi中,如果需要对自带的2D节点添加材质,则需要一个中介brush。

如果我们需要在一个Node2D上画出某个东西(颜色,材质或者图片),我们需要借助一个brush来操作。

伪代码:

  1. 使用Material Brush:

Material::Create();

Shader::Create()

Shader->InitializeFromMemory()

Material->setShader()

MaterialBrush::Create(Material)

BrushResource = kzuBrushResourceCreateFromBrush(MaterialBrush)

Node->setBackGroundBrush(BrushResorce)

  1. Color Brush和TextureBrush同理。

故思考:如果我们需要提高开机速度,那么如果这个节点刚好有Material或者其他,那么我们可将这部分的内容拆开放到后面处理。测试,添加material和不加material加载速度确实是有差异的。

材质:通俗的将就是材质决定我们想要的物体呈现什么样子。可以理解为是编译shader后生成的一个实例,材质的属性就是shader uniform开放的变量。所以我们通过材质的属性可以达到我们想要的效果。

在kanzi中,shader这部分我们无法输入attribute,所以在我们操作范围内只能去改变out color。在其中,我们可以添加uniform去控制我们想要达到的效果。

在编写shader过程中,考虑到帧率因素,有以下优化方案:

  1. 较少甚至禁用 uniform varying的if或者for。
  2. 由于gpu中的运算时并行运算,所以在有if...else判断中,会根据最慢的执行计算,所以我们需减少if...else执行时间。
  3. GPU中计算实际为矩阵运算,而float在计算时相当于也会转换为四维矩阵的运算,所以我们应当减少运算的次数。
  4. 如果是透明或者纯色,我们可直接使用color,减少取纹理。
  5. 除法运算尽量转为乘法运算。
  6. 在运算过程中,注意一些复杂的运算符,比如pow,exp,sin,cos,log,tan等。
  7. Float的精度可根据实际情况使用精度低的类型
  8. 在计算一些顶点等信息时,能放到vertext中的尽量放到vertextshader中运算。
  9. 在运算过程中,避免有所依赖。这样并行运算可能会是同步的

扩展:

  1. Blend Mode:

    1. Opaque:不开启混融效果
    2. Automatic:根据Project属性的预设值选择Premultiplied或者Non-Premultiplied,默认是Premultiplied.
    3. Premultiplied:实际调用glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA)
    4. Non-Premultiplied:调用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    5. Mixed:调用glBlendSeparateFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA, ONE, ONE_MINUS_SRC_ALPHA)
    6. Additive:调用(GL_ONE, GL_ONE):实际就是两种颜色相加,比如(1,0,0)和(0,1,0)相glBlendFunc加得到(1,1,0)
  2. BlendIntensity:
    1. .rgba*BlendIntensity
    2. .a*BlendIntensity

二:模型

在项目中,很容易看到模型,表盘,车模等等。先说一下模型的构成:

而一起提供过来的还有一张图片,这张图片就是覆盖在模型表面的纹理。而我们看到的图片的形状和模型一般不同,这方面我们不需要关心,模型到底是取得图片的uv到底在哪也不关我们的事,我们只需要做的就是看后期可能会如何处理它的UV。

例:在项目表盘中,我们很容易看到模型,它到底是怎么工作的?

如何导入模型不做介绍,我们可以在kanzi中看到mesh管理器中有对应的mesh,每个mesh的信息也可以看到,三角形数量和顶点的数量、fbx名称、材质等等。

而对于模型的使用和kanzi中3d节点大同小异。

渲染模型流程:

首先,模型除了我们可以操作坐标之外,kanzi中我们是改变不了一个mesh内部的顶点结构的,一个mesh在kanzi中的体现就是model3D。所以在通过材质渲染node时,渲染流程即上面所述流程。顶点以attribute在Vertex shader作为输入,经过转换为世界坐标后输出进行图元装配、光栅化等。Vertex中还会包含uv,这个uv即纹理的坐标(-1, 1)。那在这部分我们是否可以修改这个mesh的内部结构了?

其次,在fragment中,模型已经是固定的,而类似于表盘中的扫光实现原理是什么呢?我们知道在fragment中的运算实际就是计算像素点,将输出的像素表现在模型对应的位置。所以对于表盘中的扫光,我们能看到进度的实际是通过控制纹理的uv坐标让颜色显示出来,而未显示的部分就是一个vec4(0.0)或其他颜色。

最后,对于模型,三角形越多越细致,而导致越占资源;对于纹理,分辨率越大越好,但是影响效率,所以在模型这块就需取一个适当的值。

三:光照

目前项目中用到光照的东西很少,一般像车模可能会加入光照。

首先光照类型:点光,平行光(太阳光),聚光(手电筒)

这些光在kanzi中都有定义,但是具体实际上也是在shader中去模拟光照的一系列计算。

虽说光是一系列的计算,但是opengl对这些光都有固定的说明。我们这里会针对kanzi中的东西做一个说明,其实也和opengl类似。

如何使用光不做介绍,我们说说材质中的光照。

Kanzi给我们提供了很多的光照类型的材质:

Phong:只包含光照

PhoneCube:包含光照和环境纹理

PhongTexture:包含光照和纹理

PhongTextureCube:包含光照、纹理和环境纹理。

对于这几种材质,都有共同属性就是针对光照的:

Ambient Color:环境光颜色

Diffuse Color:漫反射颜色

Emissive Color:反射颜色

Specular Color:镜面反射颜色

Specular Exponent:镜面反射系数

这几种属性可改变光的颜色以及一些光的效果。但是很多我们要实现的效果不仅仅是光可以做完的,我们也许在模型表面需要加入材质,于是我们使用PhongTexture,这个是在属性多了一个Texture属性,我们需要加入环境的颜色比如水面呈现天空的东西,于是我们再加入Cube。对于Cube,我们下节纹理介绍。

四:纹理

这部分其实也没什么东西可说,我们这里说一下压缩纹理和环境纹理。

压缩纹理:目前kanzi支持压缩的纹理类型:ATC、ETC、PVRTC。

很多时候我们用的都是PNG类型生成的纹理,而使用压缩纹理往往是资源可能很大或者影响到性能,但是使用压缩纹理的类型我们需要确定机器是否支持。

支持opengl es2.0(3.0)的是支持ETC1(2)的。我们机器支持的版本是 OpenGL ES 3.0(具体的可通过demo或者kanzi中的opengl接口查看),故我们在使用的时候可压缩成etc格式的压缩纹理,其他格式目前不清楚。

在kanzi中找到resource file->image,在对应图片属性页选中要压缩的目标格式,右键创建纹理即可。

环境纹理:游戏中有天空盒这个东西,但是kanzi中目前是无法使用的,我们可以使用环境纹理。原理:利用环境的颜色/纹理后映射到目的模型上。

环境纹理由六张图片生成,刚好是构成一个立方体。

在kanzi中创建一个环境纹理:Textures->create cube-map texture,然后再属性框添加这 六张图片(注意环境纹理的前后左右上下顺序)。

注:arm支持的最大纹理尺寸:8192

kanzi支持导入的最大纹理尺寸:4096

五:3D

项目中3D场景虽然不多,但是基本每个项目多多少少都包含一些,所以粗略的探讨一下opengl 3d部分在kanzi中的一些东西。

一:深度测试

深度:该像素点距3d中的摄像机的距离(绘制坐标),深度缓存存储着深度值。

在没有深度测试时一般都是按照顺序绘制,这样会把某些物体覆盖,所以深度测试会根据Z值(远近)来正常显示。

opengl默认不会启用深度测试,但是默认开启深度测试。

glEnable(GL_DEPTH_TEST)

绘制半透明物体不适用。

Kanzi中默认属性如上图所示。启用了深度测试,如果没有通过深度缓存,则会丢弃该片段,还需在每个渲染迭代之前清除深度缓存,否则仍然在使用上一次的深度值。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

禁用深度缓冲的写入在kanzi中没找到如何做,这种一般使用一个只读的深度缓冲。

二:Frustum Culling

将不可见的物体提前剔除。

三:Face Cull

面剔除。

剔除背向面,前向面,不启用剔除。

Opengl默认不启用面剔除,而kanzi默认启用背面剔除,意思显而易见就是背面的面会丢弃不渲染。

四:模板测试

片段着色器处理完一个片段之后,经过深度测试丢弃一些片段,被保留的片段进入模板测试,他可能会丢弃更多。深度测试根据深度缓冲进行,而模板测试也是根据模板缓冲进行。

模板缓冲会首先被清除为0,之后再模板缓冲中用1填充,然后在场景中的片段只会在模板值为1时被渲染,剩下的都会被丢弃。

Kanzi默认不启用模板测试,如果启用模板测试,一般有如下步骤:

  1. 启用模板缓冲的写入
  2. 渲染物体,更新模板缓冲的内容
  3. 禁用模板缓冲的写入
  4. 渲染其他物体,根据模板缓冲的内容丢弃特定的片段。

在每次迭代之前清除模板缓冲。

Stencil Fail Operation: 模板测试失败时的行为

Stencil Pass Depth Fail Operation: 模板测试通过,但深度测试失败时采取的行为

Stencil Pass Depth Pass Operation: 模板测试和深度测试都通过时采取的行为

行为具体有下面

Keep:保持当前存储的模板值

Zero:将模板值设置为0

Replace:将模板值设置为参考值(Stencil Function Reference Value)

Increase:如果模板值小于最大值则将模板值加1

IncreaseWrap:如果模板值超过了最大值则归零

Decrease:如果模板值大于最小值减1

DecreaseWrap:如果模板值小于0则将其设置为最大值

Invert:按位翻转当前的模板缓冲值

opengl和kanzi默认的行为都是keep。

Stencil Function:应用到已存储的模板值上的选项:

Always:永远通过测试

Never:永远不通过测试

Less:在片段模板值小于缓冲的模板值时通过测试

Lequal:在片段模板值小于等于缓冲区的模板值时通过测试

Greater:在片段模板值大于缓冲区的模板值时通过测试

Gequal:在片段模板值大于等于缓冲区的模板值时通过测试

Equal:在片段模板值等于于模板的模板值时通过测试

Notequal:在片段模板值不等于缓冲区的模板值时通过测试

Opengl默认GL_LESS,kanzi默认always。

五:裁剪测试

当启用scissor test时,会将渲染时的视口做限制,也就是我们处理的像素范围做了限制。

六:混合

七:抗锯齿

目前了解的在kanzi中做抗锯齿都是从shader入手还有多重采样。

转载请注明出处:https://blog.csdn.net/allen807733144

kanziopengl杂谈相关推荐

  1. 【杂谈】GAN最成功的3个商业化落地领域,你是否了解过?

    2015年的时候笔者开始关注GAN,公众号早期的文章中就有GAN的综述,这些年GAN的相关研究也是持续井喷.这一次咱们学术上的研究撇开不讲,这么多年过去了,GAN有哪些最成功的商业化落地领域? 图像生 ...

  2. 「杂谈」同学聚会最悲哀的事情

    「杂谈」同学聚会最悲哀的事情 大学毕业至今近乎20年了,期间参加过几次规模或大或小的同学聚会,有高中同学会聚会,初中同学聚会,也有大学同学聚会.这些同学聚会上,笔者发现其实体验都还很不错,基本没有发现 ...

  3. 「杂谈」计算机视觉人脸图像的十几个大的应用方向,你懂了几分?

    2020-02-16 13:45:50 文/编辑 | 言有三 人脸图像属于最早被研究的一类图像,也是计算机视觉领域中应用最广泛的一类图像,可以说掌握好人脸算法,基本就玩转了计算机视觉领域.在经历了几十 ...

  4. 杂篇-从整理文件发起的杂谈[-File-]

    有些东西很简单,简单到你不想去想,比如:为什么天是蓝的?--局限物语 零.前言 说一下本篇的初衷: coder盘作为工作盘有点乱,想整理一下 也想寻求一个方便管理工程的点子,既然File类玩的滚瓜烂熟 ...

  5. Android杂谈---获取手机屏幕大小

    Android杂谈---获取手机屏幕大小 SurfaceView简单例子 玩转Android---UI篇---ZoomControls放大缩小图片 更多相关推荐 这里总结下android中关于手机屏幕 ...

  6. 【杂谈】野生在左 科班在右——数据结构学习誓师贴

    [杂谈]野生在左 科班在右--数据结构学习誓师贴 一. 科班 Vs 野生 这个老生常谈的问题让很多野生码农觉得不公平,在一次次面试中因为学历和那些工作中根本就用不到的知识虐的一脸懵逼,然后除了抱怨什么 ...

  7. 数据库内核杂谈 - 一小时实现一个基本功能的数据库

    我们摒弃直接介绍数据库内核各个模块的思路,而是从应用开发者的角度出发,来看实现一个数据库需要哪些基本功能,然后把这些功能细分成最小的模块再手把手一起实现. 对与应用开发者而言,一个数据库需要哪些必要的 ...

  8. Effective C++ --8 定制new和delete 9杂谈讨论

    上一篇Effective C++ --7 模板与泛型编程 Effective C++ --8 定制new和delete 49.了解new-handler的行为 (1)set_new_handler允许 ...

  9. JIT编译器杂谈#1:JIT编译器的血缘(一)

    这年头啥都得讲个娱乐性.专栏第一篇杂谈,先来点八卦轻松一下. 对我来说,有没有人最近用DJI无人机求婚成功啥的如同耳边一阵风:上周CoreCLR在GitHub上以MIT许可证开源了才是激动人心的娱乐新 ...

最新文章

  1. 面试了一个 46 岁的程序员,我思绪万千!
  2. 使用CNN分类签名和文本图像
  3. 推荐一款免费的数据库管理工具,比 Navicat 还要好用,功能还很强大
  4. noip模拟赛 蒜头君的兔子
  5. python单例_Python单例模式
  6. SQL Server 优化---为什么索引视图(物化视图)需要with(noexpand)强制查询提示
  7. mysql数据库连接6_c# – 实体框架的动态MySQL数据库连接6
  8. php的session怎么用,php $_session怎么用
  9. 红帽linux5安装Oracle 9i enterprise
  10. Linux使用Jexus托管Asp.Net Core应用程序
  11. spring boot中 使用http请求
  12. 查看linux代码版本,如何查看 Linux Mint 版本号和代号 | Linux 中国
  13. bbs小项目整理(八)(总结、源码分享)
  14. 几个清华和北邮学霸公众号,值得学习
  15. ZZULIOJ1046-1050Python解法
  16. Appium环境搭建教程
  17. C++二进制数转换十进制数
  18. win11怎么装回win10系统
  19. Jo-SRC: A Contrastive Approach for Combating Noisy Labels
  20. 【如何学习CAN总线测试】——Python+Robot Framework框架实现UDS诊断自动化

热门文章

  1. 木纹标识lisp_Lisp
  2. 【DSP】离散系统的因果性判断
  3. 为什么说继承是把双刃剑
  4. linux 用户 组区别吗,Linux用户组之主组和附加组
  5. IDEA中 单元测试@Test的使用
  6. java性能调优指南,就是这么简单
  7. 为什么优秀的程序员bug很少?因为他们……
  8. ATA工厂测试AT_MODE下震动不振问题分析
  9. 简明扼要:numpy.random.seed()用法
  10. 前端常见面试题 - JS篇