您当前的位置: 首页 >  ar

Jave.Lin

暂无认证

  • 4浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

LearnGL - 15.3 - 渲染顺序

Jave.Lin 发布时间:2020-08-12 12:03:23 ,浏览量:4

文章目录
  • 渲染队列
  • 核心排序函数
  • 不透明几何体
  • 半透明几何体
  • 其它几何体
  • 查看半透明效果
    • 正常效果
    • 不正常的效果
  • 深度写入的问题

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 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 getOwner()->getTrans()->get_view_pos().z getOwner()->getTrans()->get_view_pos().z; // 升序,view z越大越早绘制,先绘制背后远离镜头的,再绘制比较近于镜头的,Draw Back To Front
        }
    }
    else {
        // 其他几何体 目前是直接使用渲染队列值来排序
        return a->queue queue;
    }
}

具体看注释的说明

不透明几何体

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

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

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

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

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

半透明几何体

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

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

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

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

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

其它几何体

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

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

else {
    // 其他几何体 目前是直接使用渲染队列值来排序
    return a->queue 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);				                                        // 清理颜色缓存 与 深度缓存 与 模板缓存
关注
打赏
1664331872
查看更多评论
立即登录/注册

微信扫码登录

0.1805s