LearnGL - 15.3 - 渲染顺序

49 篇文章 0 订阅
47 篇文章 0 订阅


LearnGL - 学习笔记目录

前某篇:LearnGL - 15 - Skybox - 天空盒 - 优化天空盒的渲染队列 - 有说一丢丢关于渲染顺序的优化,这个是直接使用 渲染队列值 来排序的

这一篇:我们将分别对 不透明几何体半透明几何体其他几何体 的渲染顺序进行排序

本人才疏学浅,如有什么错误,望不吝指出。


渲染队列

之前有提到过,现在再复制一篇:

	enum class RenderQueueType {
		Skybox		= 0500, // 天空盒子
		Background	= 1000,	// 背景
		Geometry 	= 2000, // 不透明几何体
		AlphaTest	= 2500, // FS 带有 discard 的
		Transprent	= 3000, // 透明的几何体
		Gizmos		= 3500, // 开发调式用的 Gizmos 绘制
		Overlay		= 4000, // UI 
	};

渲染队列值越小,绘制就越早


核心排序函数

目前比较简单,因为提供的功能有限,后续如果不断增加各种维度来排序的话,可能就来越复杂了

bool Camera::rendererCmp(MeshRenderer* a, MeshRenderer* b) {
    if (a->queue == b->queue) {
        // 注意我们的 view 是右手坐标
        // 意味着:从屏幕内指向我们观察(相机)的位置是 z 值的增量方向
        // 所以 view z 值越大,里我们相机近
        //      几何体不透明的话,先绘制近的,再绘制远的,这样可以类似 early-z 的效果,剔除后续不必要的 fragment shader
        //      如果是半透明的话,先绘制远的,再绘制近的,因为半透一般不写深度,需要与后面先绘制的背景内容融混处理
        // 几何体 或是 AlphaTest 的几何体
        if (a->queue >= (int)RenderQueueType::Geometry && a->queue <= (int)RenderQueueType::AlphaTest) {
            return
                a->getOwner()->getTrans()->get_view_pos().z >
                b->getOwner()->getTrans()->get_view_pos().z; // 降序,view z越大越早绘制,先绘制比较近于镜头的,再绘制背后原理镜头的,Draw Front To Back
        }
        // 半透明
        else if (a->queue >= (int)RenderQueueType::Transprent && a->queue < (int)RenderQueueType::Gizmos) {
            return
                a->getOwner()->getTrans()->get_view_pos().z <
                b->getOwner()->getTrans()->get_view_pos().z; // 升序,view z越大越早绘制,先绘制背后远离镜头的,再绘制比较近于镜头的,Draw Back To Front
        }
    }
    else {
        // 其他几何体 目前是直接使用渲染队列值来排序
        return a->queue < b->queue;
    }
}

具体看注释的说明


不透明几何体

虽然你可以直接看我的注释说明,但是我觉得很有必要强调说明

// 几何体 或是 AlphaTest 的几何体
if (a->queue >= (int)RenderQueueType::Geometry && a->queue <= (int)RenderQueueType::AlphaTest) {
    return
        a->getOwner()->getTrans()->get_view_pos().z >
        b->getOwner()->getTrans()->get_view_pos().z; // 降序,view z越大越早绘制,先绘制比较近于镜头的,再绘制背后原理镜头的,Draw Front To Back
}

可以看到,我是将 GeometryAlphaTest 渲染队列之间的都算是 不透明 的几何体

这类 不透明几何体 我们都可以先绘制离镜头 一些的,再绘制离镜头 一些的,这样就能尽可能的剔除了后续被 depth test 测试失败剔除了片段,从而避免 fragment shader 的执行,渲染效率也就提升了

总结为:不透明几何体,渲染顺序 先近后远


半透明几何体

虽然你可以直接看我的注释说明,但是我觉得很有必要强调说明

// 半透明
else if (a->queue >= (int)RenderQueueType::Transprent && a->queue < (int)RenderQueueType::Gizmos) {
    return
        a->getOwner()->getTrans()->get_view_pos().z <
        b->getOwner()->getTrans()->get_view_pos().z; // 升序,view z越大越早绘制,先绘制背后远离镜头的,再绘制比较近于镜头的,Draw Back To Front
}

可以看到,我是将 TransprentGizmos 渲染队列之间的都算是 半透明 的几何体

这类 半透明的几何体 我们都可以先绘制离镜头 一些的,再绘制离镜头 一些的,这样才能从渲染效果上看上去比较好一些

总结为:半透明几何体,渲染顺序 先远后近


其它几何体

其他几何体的渲染排序,目前我是直接使用 渲染队列值 来排序的

没啥可说,但要知道目前是有区别的

else {
    // 其他几何体 目前是直接使用渲染队列值来排序
    return a->queue < b->queue;
}

查看半透明效果

因为在渲染不透明几何体通常会开启深度剔除,所以渲染顺序的不同,在视觉上看不到区别的

因此我们只查看半透明在不同渲染顺序策略下的区别

先看正确的,都是在:Transparent 队列下的

正常效果

渲染队列为 Transparent 是正确的,因为半透明先渲染远的,再渲染近的
在这里插入图片描述

不正常的效果

下面将 Transparent 渲染队列修改为 Geometry,因为Geometry 是从近到远渲染的,效果应用在半透明上就不对了
在这里插入图片描述


深度写入的问题

因为我们半透明通常是不写入深度的,所以我们在这些几何体渲染是,会将渲染状态配置为不可写入深度

到如果该次 Draw Call 最后一个绘制关闭了深度写入,这时到了每一帧的 glClear 清理(重置)深度值时,就会有问题,因为上次还是保持着不写入深度的配置状态,因此 glClear 也是不会写入深度的,即:不能成功的清理深度

所以我们很有必要在 glClear 清理之前,先去开启一些深度写入即可 glDepthMask(GL_TRUE);,代码如下:

// 这里要强制开启一下 深度写入,因为有些绘制关闭深度写入
// 如果是最后一个渲染的话就会影响这里的下次清楚深度写入的问题
glDepthMask(GL_TRUE);
glClearColor(clearColor.x, clearColor.y, clearColor.z, clearColor.w);   // 设置清理颜色缓存时,填充的颜色值
glClearDepthf(clearDepth);		                                        // 设置清理深度缓存时,填充的深度值
glClear(clearFlag);				                                        // 清理颜色缓存 与 深度缓存 与 模板缓存
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值