一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

基于WebGL的半透明物体的渲染方法与流程

2023-02-04 11:12:06 来源:中国专利 TAG:

基于webgl的半透明物体的渲染方法
技术领域
1.本技术涉及3d图形渲染技术领域,尤其是一种基于webgl的半透明物体的渲染方法。


背景技术:

2.半透明物体渲染在3d渲染中是非常常见的,也是一个难以解决的难题。目前基于opengl等桌面级图形库已经有一些顺序无关的半透明渲染(order in-dependent transparency)算法,比如逐像素链表(per-pixel linked lists)、深度剥离(depth peeling)、加权平均(weighted averaging)等。此外,常用的算法还有顺序有关的油画家算法。
3.基于opengl es实现的webgl没有原子操作(atomic operation)、着色器存储缓存对象(shader storage buffer object)等高级特性,不能实现逐像素链表法等算法。而深度剥离算法的性能问题在web端会更加严重,加权平均算法无法还原正确的颜色结果。至于油画家算法,由于其需要预先排序,对于大型场景来说性能较差,并且很多情况下有错误的混合结果,所以基于webgl目前没有效果和性能都较好的半透明物体的渲染方法。


技术实现要素:

4.本技术的目的在于克服现有技术不足之处,提供一种基于webgl的半透明物体的渲染方法。
5.本技术提供了一种基于webgl的半透明物体的渲染方法,包括:
6.对所有物体进行第一次渲染,以获取每个像素位的最大深度值和区间片元数;
7.基于所述最大深度值和区间片元数计算深度区间的切分数;
8.基于所述切分数和最大深度值计算深度区间的单位距离;
9.创建区间片元缓存纹理和深度区间索引纹理;
10.将所述深度区间的单位距离、区间片元缓存纹理和深度区间索引纹理输入到片元着色器中,对所有物体进行第二次渲染;
11.输出最终像素。
12.进一步的,获取每个像素位的最大深度值和区间片元数,包括:
13.在第一次渲染之前,调用webgl提供的方法depthfunc()来设置深度比较方式,其中,深度比较所采用的函数为greater;
14.在第一次渲染中,设置混合模式的源混合因子和目标混合因子都为gl.one,且写入红色通道的值为1;
15.当一个片元通过了片元着色器阶段,并进行到深度测试阶段时,如果该片元通过了深度测试以及后续渲染管线中的测试,则将该片元的深度写入深度缓冲区;
16.当深度缓冲区已经存在某一片元的深度值时,则根据深度比较函数提供的策略来判断是否要覆盖当前已存在缓冲区中的深度值;
17.当第一次渲染完成之后,深度缓冲区中将保存着每个像素位下所有片元的最大深度值,帧缓存的纹理红色通道中将存储当前像素位的区间片元数。
18.进一步的,所述切分数的计算公式为:
19.c=cb (1 (n-n
min
)
÷
(n
max-n
min
)
×
t),t∈[0, ∞),cb∈[1, ∞)
[0020]
其中,c为切分数,n
max
为最大区间片元数,n
min
为最小区间片元数,cb为由用户输入的区间切分基数,t为由用户输入的区间切分系数的常量值,n为输入数值区间片元数。
[0021]
进一步的,所述深度区间的单位距离的计算公式为:
[0022]
d=d
max
÷
c,d
max
∈[0,1]
[0023]
其中,d为深度区间的单位距离,d
max
为像素位的最大深度值,c为切分数。
[0024]
进一步的,所述区间片元缓存纹理包括第一纹理和第二纹理,其中,第一纹理用于储存区间片元缓存纹理中的颜色值,第二纹理用于储存区间片元缓存纹理中的深度值。
[0025]
进一步的,所述第一纹理的创建包括:
[0026]
调用webgl提供的函数createtexture()创建第一纹理;
[0027]
将纹理格式设置为rgba8;
[0028]
将纹理类型设置为unsigned_byte;
[0029]
调用teximage2d()函数初始化像素,其中,pixels参数设置为javascript的arraybuffer实例,即完成第一纹理的创建。
[0030]
进一步的,所述第二纹理的创建包括:
[0031]
调用webgl提供的函数createtexture()创建第二纹理;
[0032]
将纹理格式设置为r16ui;
[0033]
将纹理类型设置为unsigned_int;
[0034]
调用teximage2d()函数初始化像素,其中,pixels参数设置为javascript的arraybuffer实例,即完成第二纹理的创建。
[0035]
进一步的,所述深度区间索引纹理的创建包括:
[0036]
调用webgl提供的函数createtexture()创建深度区间索引纹理;
[0037]
将纹理格式设置为rg16f;
[0038]
将纹理类型设置为float;
[0039]
调用teximage2d()函数初始化像素,其中,pixels参数设置为javascript的arraybuffer实例,即完成深度区间索引纹理。
[0040]
进一步的,所述第二次渲染包括:
[0041]
根据屏幕坐标以及深度区间索引纹理获取深度区间开始的索引;
[0042]
根据片元深度值,以及深度区间单位距离,映射到相应深度区间,向下取整计算出相对于深度区间的开始索引偏移值,以获取区间片元缓存纹理上的实际存储位置;
[0043]
将rgba以及深度值写入区间片元缓存纹理上的实际存储位置,以完成一个区间片元缓存的写入;
[0044]
基于相应的混合模式完成所有区间片元缓存的写入,以完成第二次渲染。
[0045]
进一步的,所述最终像素的输出包括:
[0046]
调用屏幕后处理过程,对区间片元缓存纹理逐像素进行所有区间片元的排序;
[0047]
根据混合模式依次混合所有片元;
[0048]
输出屏幕所有alpha混合过的像素。
[0049]
本技术具有如下有益效果:本技术通过使用两个渲染过程和两侧屏幕后处理,完了顺序无关的半透明物体渲染,与深度剥离、逐像素链表算法相比,由于划分了区间,预先合并了一部分片元,相对更节省显存,并且性能要比深度剥离高,相对于加权平均算法和油画家算法,在选用了合适区间划分数的情况下,或深度分布相对均匀的场景下,有更正确的混合结果。
附图说明
[0050]
构成本技术的一部分的附图用于来提供对本技术的进一步理解,本技术的示意性实施例及其说明用于解释本技术,并不构成对本技术的不当限定。
[0051]
为了更清楚地说明本技术实施例中的技术方案,下面将对实施例描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本技术的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他的附图。
[0052]
图1是本技术实施例一中的深度区间划分的概念图;
[0053]
图2是本技术实施例一中深度缓冲区中保存着每个像素位下所有片元的最大深度值的结果图;
[0054]
图3是本技术实施例一中深度区间索引纹理与区间片元缓存纹理索引位置的示意图;
[0055]
图4是本技术实施例一的基于webgl的半透明物体的渲染方法的流程图;
[0056]
图5是本技术实施例一的基于webgl的半透明物体的渲染方法的总体流程图;
[0057]
图6是使用常规的渲染方式渲染的多个立方体的效果图;
[0058]
图7是是使用本技术的渲染方式渲染的多个立方体的效果图。
具体实施方式
[0059]
下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有作出创造性劳动前提下所获得的所有其它实施例,都属于本发明保护的范围。
[0060]
实施例一
[0061]
本技术实施例一所涉及的一种基于webgl的半透明物体的渲染方法,包括:对所有物体进行第一次渲染,以获取每个像素位的最大深度值和区间片元数;基于所述最大深度值和区间片元数计算深度区间的切分数;基于所述切分数和最大深度值计算深度区间的单位距离;创建区间片元缓存纹理和深度区间索引纹理;将所述深度区间的单位距离、区间片元缓存纹理和深度区间索引纹理输入到片元着色器中,对所有物体进行第二次渲染;输出最终像素,本技术通过使用两个渲染过程和两侧屏幕后处理,完了顺序无关的半透明物体渲染,与深度剥离、逐像素链表算法相比,由于划分了区间,预先合并了一部分片元,相对更节省显存,并且性能要比深度剥离高,相对于加权平均算法和油画家算法,在选用了合适区间划分数的情况下,或深度分布相对均匀的场景下,有更正确的混合结果。
[0062]
需要说明的是,像素位是指屏幕坐标系下的每一个坐标位置,每个像素位在实际渲染时对应这多个不同深度片元,本方案的基本原理为:把每个像素位的深度空间分割成等间距的有限个数的小区间,这个小区间称为深度区间,分割出来的深度区间存储的数据块称之区间片元,渲染每个片元时,先根据x、y值索引到屏幕坐标,再用深度值索引到对应深度区间,在深度区间下写入颜色值、alpha值和深度值,这样就基本上存储了所有深度下所有片元的数据,再逐像素位遍历,对其所属的所有的区间片元进行排序,并用相应的混合模式进行alpha混合,最终输出成一个像素,示例性的,概念图如图1所示,图中表现了4个像素位下若干个深度区间的划分。
[0063]
具体的,图4-5示出了申请实施例一中的基于webgl的半透明物体的渲染方法的流程图,包括:
[0064]
s101、对所有物体进行第一次渲染,以获取每个像素位的最大深度值和区间片元数;
[0065]
其中,获取每个像素位的最大深度值和区间片元数,包括:
[0066]
在第一次渲染之前,调用webgl提供的方法depthfunc()来设置深度比较方式,其中,深度比较所采用的函数为greater;
[0067]
在第一次渲染中,设置混合模式的源混合因子和目标混合因子都为gl.one,且写入红色通道的值为1;
[0068]
当一个片元通过了片元着色器阶段,并进行到深度测试阶段时,如果该片元通过了深度测试以及后续渲染管线中的测试,则将该片元的深度写入深度缓冲区;
[0069]
当深度缓冲区已经存在某一片元的深度值时,则根据深度比较函数提供的策略来判断是否要覆盖当前已存在缓冲区中的深度值;
[0070]
当第一次渲染完成之后,深度缓冲区中将保存着每个像素位下所有片元的最大深度值,帧缓存的纹理红色通道中将存储当前像素位的区间片元数。
[0071]
具体的,根据webgl的渲染管线,当渲染过程进行到片元着色器(fragment shader)阶段时,可从内置变量gl_fragcoord中读取当前片元的深度值,在渲染之前,调用webgl提供的方法depthfunc()来设置深度比较方式为greater。这样当一个片元通过了片元着色器阶段,进行到深度测试(depth test)阶段时,如果通过了深度测试以及后续渲染管线中的测试,会把该片元的深度写入深度缓冲区;而当深度缓冲区已经存在某一片元的深度值时,则根据深度比较函数提供的策略来判断是否要覆盖当前已存在缓冲区中的深度值,设置深度比较函数为greater,就是当片元深度值大于缓冲区的深度值时写入缓冲区,这样渲染完之后,深度缓冲区(depth buffer)中保存着每个像素位下所有片元的最大深度值,结果如图2所示。
[0072]
s102、基于所述最大深度值和区间片元数计算深度区间的切分数;
[0073]
具体的,所述切分数的计算公式为:
[0074]
c=cb (1 (n-n
min
)
÷
(n
max-n
min
)
×
t),t∈[0, ∞),cb∈[1, ∞)
[0075]
其中,c为切分数,n
max
为最大区间片元数,n
min
为最小区间片元数,cb为由用户输入的区间切分基数,t为由用户输入的区间切分系数的常量值,n为输入数值区间片元数。
[0076]
需要说明的是,由于片元数较多的情况,两个片元同属于个一个深度区间的概率增大(称为深度重叠)的可能性增大,深度重叠可能造成错误alpha混合结果,于是可以对片
元数较多的像素位根据参数(可由用户设置),加大对该像素位的切分数,以获得更高的精度,根据步骤s101中获取的区间片元数,遍历所有像素位下区间片元数,计算极值,获取最大区间片元数(记为n
max
)和最小区间片元数(记为n
min
),再提供给用户设置两个输入数值,一个为区间切分基数(记为cb),另一个为区间切分系数的常量值(记为t),然后,输入数值区间片元数(记为n),即可通过切分数的计算公式计算出切分数c。
[0077]
另外,在效果上区间切分系数n是一个可以放大区间片元数的倍数值,用户可以根据场景实际的物体密集分布情况,设置合适的放大倍数,来消除深度重叠。
[0078]
s103、基于所述切分数和最大深度值计算深度区间的单位距离;
[0079]
具体的,所述深度区间的单位距离的计算公式为:
[0080]
d=d
max
÷
c,d
max
∈[0,1]
[0081]
其中,d为深度区间的单位距离,d
max
为像素位的最大深度值,c为切分数。
[0082]
需要说明的是,步骤s103将会把0到1的连续的深度值离散化,从而实现在后续步骤中的分段存储深度值以及颜色值,这个过程可放在一个屏幕后处理(post progressing)过程中计算,并把单位距离和切分数输出到纹理。
[0083]
s104、创建区间片元缓存纹理和深度区间索引纹理;
[0084]
具体的,根据屏幕尺寸计算像素位总数,根据该像素位的切分数,预先创建一张能容纳所有区间片元的纹理,该纹理格式(texture format)需要设置为能存储rgba四个通道的基础上再多一个通道存储深度值,根据最大切分数选用相应的纹理格式,由于把所有像素位的深度区间都存储在一张纹理上,需要标识每个像素位的深度区间的开始索引,就是开始的深度区间所在纹素(texture pixel)的纹理坐标;
[0085]
需要说明的是,区间片元缓存纹理包括第一纹理和第二纹理,其中,第一纹理用于储存区间片元缓存纹理中的颜色值,第二纹理用于储存区间片元缓存纹理中的深度值。
[0086]
具体的,所述第一纹理的创建包括:
[0087]
调用webgl提供的函数createtexture()创建第一纹理;
[0088]
将纹理格式(texture internal format)设置为rgba8;
[0089]
将纹理类型(texture type)设置为unsigned_byte,也就是使用无符号整存储每个通道;
[0090]
调用teximage2d()函数初始化像素,其中,pixels参数设置为javascript(简称js)的arraybuffer实例(类型是uint8array),即完成第一纹理的创建。
[0091]
所述第二纹理的创建包括:
[0092]
调用webgl提供的函数createtexture()创建第二纹理;
[0093]
将纹理格式设置为r16ui;
[0094]
将纹理类型设置为unsigned_int;
[0095]
调用teximage2d()函数初始化像素,其中,pixels参数设置为javascript的arraybuffer实例,即完成第二纹理的创建。
[0096]
需要说明的是,考虑到区间片元包含颜色值和深度值,所以需要再创建第二纹理来存储深度值,第一纹理和第二纹理并称为区间片元缓存纹理,创建存储深度的纹理和创建存储颜色的纹理过程基本相同,区别在于每个像素使用1个16位无符号整型的通道来存储深度值即可,为此,在创建第二纹理时,需要设置纹理格式为r16ui,纹理类型为
unsigned_int。
[0097]
所述深度区间索引纹理的创建包括:
[0098]
调用webgl提供的函数createtexture()创建深度区间索引纹理;
[0099]
将纹理格式设置为rg16f;
[0100]
将纹理类型设置为float;
[0101]
调用teximage2d()函数初始化像素,其中,pixels参数设置为javascript的arraybuffer实例,即完成深度区间索引纹理。
[0102]
需要说明的是,深度区间索引纹理的创建过程基本和第一纹理的创建过程类似,区别在于需要2个通道来存储2个索引值,因为uv坐标是两个浮点数值,于是在第一纹理创建过程的基础上,设置纹理格式为rg16f,纹理类型为float。
[0103]
s105、将所述深度区间的单位距离、区间片元缓存纹理和深度区间索引纹理输入到片元着色器中,对所有物体进行第二次渲染;
[0104]
具体的,所述第二次渲染包括:
[0105]
根据屏幕坐标以及深度区间索引纹理获取深度区间开始的索引;
[0106]
根据片元深度值,以及深度区间单位距离,映射到相应深度区间,向下取整计算出相对于深度区间的开始索引偏移值,以获取区间片元缓存纹理上的实际存储位置;
[0107]
需要说明的是,计算开始索引偏移值公式为:
[0108]
o=floor(d
÷
d)
[0109]
其中,o为开始索引偏移值,d为片元深度值,d为深度区间单位距离,floor表示向下取整函数;
[0110]
将rgba以及深度值写入区间片元缓存纹理上的实际存储位置,以完成一个区间片元缓存的写入;
[0111]
基于相应的混合模式完成所有区间片元缓存的写入,以完成第二次渲染。
[0112]
具体的,准备好了深度区间的单位距离、深度区间索引纹理和区间片元缓存纹理之后,把它们输入到片元着色器(fragment shader)中,使用一个pass(渲染过程)开始正式渲染所有物体;对于每一个片元,先根据屏幕坐标以及深度区间索引纹理获取深度区间开始的索引,然后需要根据其深度值(记为d),以及深度区间单位距离(d),映射到相应深度区间,向下取整计算出相对于深度区间开始索引偏移值,这样就能计算出在区间片元缓存纹理上的实际存储位置,把rgba以及深度值写入该位置,就记录下了一个区间片元;由于深度重叠是可能发生的,写入区间片元缓存应该使用相应的混合模式(可由用户设置)。
[0113]
s106、输出最终像素。
[0114]
具体的,所述最终像素的输出包括:
[0115]
调用屏幕后处理过程,对区间片元缓存纹理逐像素进行所有区间片元的排序;
[0116]
根据混合模式依次混合所有片元,其中,混合模式是由客户设置的;
[0117]
输出屏幕所有alpha混合过的像素。
[0118]
本技术的技术方案把所有片元存储在一张纹理中,解决了webgl上因为没有原子操作和着色器存储缓存对象导致无法实现缓存所有片元问题;另外,通过划分深度区间,离散地切分了连续的深度值,可在有限的显存下缓存所有片元,显存最大使用是确定的,不会出现深度剥离算法那样可能会导致显存溢出的情况;其次,在物体深度分布不会过于集中
或模型不是密集交叉的情况下,有正确的混合结果。
[0119]
图6为使用常规的渲染方式渲染的多个立方体,可以看到涂装右上角的立方体看起很遮挡关系很混乱了,基本分不清前后关系了,图7是使用本技术方案的渲染方式渲染的多个立方体,立方体之前的空间关系清晰且正确,由此可见,本技术的技术方案在选用了合适区间划分数的情况下,或深度分布相对均匀的场景下,有更正确的混合结果。
[0120]
可选的,由于统计了像素位的片元数,并且作为计算切分数的参数之一,虽然会仍有较少深度重叠的发生,也会导致各个像素位的区间数不一致,则不可避免地使用了深度区间索引纹理,增加了性能消耗,也可以不计入像素位的片元数,直接取用户设置的固定切分数,这样就能直接计算出深度区间的开始索引,减少一些步骤和性能消耗,由于缓存纹理大小是确定的,也让显存占更稳定,但是出现混合错误的可能性会增大。
[0121]
可选的,防止深度重叠的方法就是加大切分数,但加大切分数据会导致缓存空间增大,增加显存占用,为了保证正确的结果,而显存空间量又是一定的,这时,可以把正式的渲染过程分多个pass(渲染过程)渲染,每个pass渲染屏幕中一小块,每个pass传入上一个pass最后一个缓存位置索引值加1,pass渲染完直接进行输出最终像素,这样相当于用时间换空间,充分发挥gpu显存和性能极致,来达到最好的效果。
[0122]
实施例二
[0123]
本技术实施例二涉及一种基于webgl的半透明物体的渲染装置,包括:
[0124]
第一渲染模块,用于对所有物体进行第一次渲染,以获取每个像素位的最大深度值和区间片元数;
[0125]
切分数计算模块,用于基于所述最大深度值和区间片元数计算深度区间的切分数;
[0126]
单位距离计算模块,用于基于所述切分数和最大深度值计算深度区间的单位距离;
[0127]
纹理创建模块,用于创建区间片元缓存纹理和深度区间索引纹理;
[0128]
第二渲染模块,用于将所述深度区间的单位距离、区间片元缓存纹理和深度区间索引纹理输入到片元着色器中,对所有物体进行第二次渲染;
[0129]
输出模块,用于输出最终像素。
[0130]
实施例三
[0131]
本技术实施例三涉及一种计算机可读存储介质,所述计算机可读介质存储用于设备执行的程序代码,该程序代码包括用于执行如本技术实施例一中的任意一种实现方式中方法的步骤;
[0132]
其中,计算机可读存储介质可以是只读存储器(read only memory,rom),静态存储设备,动态存储设备或者随机存取存储器(random access memory,ram);计算机可读存储介质可以存储程序代码,当计算机可读存储介质中存储的程序被处理器执行时,处理器用于执行如本技术实施例一中的任意一种实现方式中方法的步骤。
[0133]
以上,仅为本技术较佳的具体实施方式;但本技术的保护范围并不局限于此。任何熟悉本技术领域的技术人员在本技术揭露的技术范围内,根据本技术的技术方案及其改进构思加以等同替换或改变,都应涵盖在本技术的保护范围内。
再多了解一些

本文用于创业者技术爱好者查询,仅供学习研究,如用于商业用途,请联系技术所有人。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

相关文献