【Overload游戏引擎分析】画场景网格的Shader

Overload引擎地址: GitHub - adriengivry/Overload: 3D Game engine with editor

一、栅格绘制基本原理

Overload Editor启动之后,场景视图中有栅格线,这个在很多软件中都有。刚开始我猜测它应该是通过绘制线实现的。阅读代码发现,这个栅格的几何网格只有两个三角形面片组成的正方形,使用特殊Shader绘制出来的。

绘制栅格的代码在EditorRenderer.cpp中,代码如下:

void OvEditor::Core::EditorRenderer::RenderGrid(const OvMaths::FVector3& p_viewPos, const OvMaths::FVector3& p_color)
{constexpr float gridSize = 5000.0f; // 栅格的总的大小FMatrix4 model = FMatrix4::Translation({ p_viewPos.x, 0.0f, p_viewPos.z }) * FMatrix4::Scaling({ gridSize * 2.0f, 1.f, gridSize * 2.0f }); // 栅格的模型矩阵m_gridMaterial.Set("u_Color", p_color); // 栅格的颜色m_context.renderer->DrawModelWithSingleMaterial(*m_context.editorResources->GetModel("Plane"), m_gridMaterial, &model); // 绘制栅格// 绘制坐标轴的三条线m_context.shapeDrawer->DrawLine(OvMaths::FVector3(-gridSize + p_viewPos.x, 0.0f, 0.0f), OvMaths::FVector3(gridSize + p_viewPos.x, 0.0f, 0.0f), OvMaths::FVector3(1.0f, 0.0f, 0.0f), 1.0f);m_context.shapeDrawer->DrawLine(OvMaths::FVector3(0.0f, -gridSize + p_viewPos.y, 0.0f), OvMaths::FVector3(0.0f, gridSize + p_viewPos.y, 0.0f), OvMaths::FVector3(0.0f, 1.0f, 0.0f), 1.0f);m_context.shapeDrawer->DrawLine(OvMaths::FVector3(0.0f, 0.0f, -gridSize + p_viewPos.z), OvMaths::FVector3(0.0f, 0.0f, gridSize + p_viewPos.z), OvMaths::FVector3(0.0f, 0.0f, 1.0f), 1.0f);
}

从中看出,先将面片平移到视点的前方,使得三角形始终在视锥体范围内,同时将三角形进行缩放,总的尺寸缩放到10000。然后使用m_gridMaterial材质进行绘制。所谓的材质就是Shader的封装。最后再绘制坐标轴的三条线。

可以使用RenderDoc抓帧,可以验证确实是这么实现的。

二、栅格绘制的Shader代码

绘制栅格的Vertex Shader代码如下:

#version 430 corelayout (location = 0) in vec3 geo_Pos;
layout (location = 1) in vec2 geo_TexCoords;
layout (location = 2) in vec3 geo_Normal;layout (std140) uniform EngineUBO
{mat4    ubo_Model;mat4    ubo_View;mat4    ubo_Projection;vec3    ubo_ViewPos;float   ubo_Time;
};out VS_OUT
{vec3 FragPos;vec2 TexCoords;
} vs_out;void main()
{vs_out.FragPos      = vec3(ubo_Model * vec4(geo_Pos, 1.0)); // 计算顶点世界坐标系坐标vs_out.TexCoords    = vs_out.FragPos.xz;  // 对应的纹理坐标,取对应的世界坐标gl_Position = ubo_Projection * ubo_View * vec4(vs_out.FragPos, 1.0); // 计算NDC坐标
}

 Vertex Shader的代码相对较简单,有效的输入只有geo_Pos。EngineUBO是OpenGL的UBO变量,传入了模型、视图、投影矩阵。main方法中,计算了三角形的世界坐标系坐标、纹理坐标、输出gl_Position变量。

Fragment Shader的代码如下:


#version 430 coreout vec4 FRAGMENT_COLOR;layout (std140) uniform EngineUBO
{mat4    ubo_Model;mat4    ubo_View;mat4    ubo_Projection;vec3    ubo_ViewPos;float   ubo_Time;
};in VS_OUT
{vec3 FragPos;vec2 TexCoords;
} fs_in;uniform vec3 u_Color;float MAG(float p_lp)
{const float lineWidth = 1.0f;const vec2 coord       = fs_in.TexCoords / p_lp;const vec2 grid        = abs(fract(coord - 0.5) - 0.5) / fwidth(coord);const float line       = min(grid.x, grid.y);const float lineResult = lineWidth - min(line, lineWidth);return lineResult;
}float Grid(float height, float a, float b, float c)
{const float cl   = MAG(a);const float ml   = MAG(b);const float fl   = MAG(c);const float cmit =  10.0f;const float cmet =  40.0f;const float mfit =  80.0f;const float mfet =  160.0f;const float df   = clamp((height - cmit) / (cmet - cmit), 0.0f, 1.0f);const float dff  = clamp((height - mfit) / (mfet - mfit), 0.0f, 1.0f);const float inl  = mix(cl, ml, df);const float fnl  = mix(inl, fl, dff);return fnl;
}void main()
{const float height = distance(ubo_ViewPos.y, fs_in.FragPos.y);const float gridA = Grid(height, 1.0f, 4.0f, 8.0f);const float gridB = Grid(height, 4.0f, 16.0f, 32.0f);const float grid  = gridA * 0.5f + gridB;// const vec2  viewdirW    = ubo_ViewPos.xz - fs_in.FragPos.xz;// const float viewdist    = length(viewdirW);FRAGMENT_COLOR = vec4(u_Color, grid);
}

Fragment shader的代码没有看太明白,需要的时候再分析吧。

三、绘制坐标轴线Shader

相比之下,绘制坐标轴线的Shader就简单太多了。线的顶点使用两个uniform变量传入线的两个顶点,根据gl_VertexID判断使用哪个顶点。FS直接给出颜色。

############ Vertex Shader ############version 430 coreuniform vec3 start;
uniform vec3 end;
uniform mat4 viewProjection;void main()
{vec3 position = gl_VertexID == 0 ? start : end;gl_Position = viewProjection * vec4(position, 1.0);
}########  Fragment Shader #############
#version 430 coreuniform vec3 color;out vec4 FRAGMENT_COLOR;void main()
{FRAGMENT_COLOR = vec4(color, 1.0);
}

对应CPU端的代码:

void OvRendering::Core::ShapeDrawer::DrawLine(const OvMaths::FVector3& p_start, const OvMaths::FVector3& p_end, const OvMaths::FVector3& p_color, float p_lineWidth)
{// 绑定line Shaderm_lineShader->Bind();m_lineShader->SetUniformVec3("start", p_start); // 线的起点m_lineShader->SetUniformVec3("end", p_end);     // 线的终点m_lineShader->SetUniformVec3("color", p_color); // 线的颜色// 绘制线m_renderer.SetRasterizationMode(OvRendering::Settings::ERasterizationMode::LINE);m_renderer.SetRasterizationLinesWidth(p_lineWidth);// 掉Draw callm_renderer.Draw(*m_lineMesh, Settings::EPrimitiveMode::LINES);m_renderer.SetRasterizationLinesWidth(1.0f);m_renderer.SetRasterizationMode(OvRendering::Settings::ERasterizationMode::FILL);m_lineShader->Unbind();
}

这里有个m_lineMesh对象,其包含两个随意的顶点即可,只是为了启动两次顶点着色器,真实的顶点坐标是靠uniform传入的。Overload将其全部初始化为0:

std::vector<Geometry::Vertex> vertices;vertices.push_back({0, 0, 0,// 坐标0, 0,   // 纹理0, 0, 0,// 法线0, 0, 0,0, 0, 0});vertices.push_back({0, 0, 0,0, 0,0, 0, 0,0, 0, 0,0, 0, 0});m_lineMesh = new Resources::Mesh(vertices, { 0, 1 }, 0);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/96044.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32复习笔记(二):GPIO

目录 &#xff08;一&#xff09;Demo流程 &#xff08;二&#xff09;工程配置 &#xff08;三&#xff09;代码部分 &#xff08;四&#xff09;外部中断&#xff08;EXTI&#xff09; &#xff08;一&#xff09;Demo流程 首先&#xff0c;板子上有4个按键&#xff0c;…

外包做了3个月,技术退步明显。。。。。

先说一下自己的情况&#xff0c;大专生&#xff0c;17年通过校招进入广州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

网络初识必知会

局域网&#xff1a;把一些设备通过交换机/路由器连接起来 广域网&#xff1a;把更多的局域网也相互连接&#xff0c;当网络规模足够大的 交换机&#xff1a;组网过程中的重要设备&#xff01; 路由器&#xff1a;组网过程中的重要设备&#xff01; IP地址&#xff1a;描述一…

什么,这年头还有人不知道404

写在前面 哥&#xff0c;来帮我看看&#xff0c;这个请求怎么404了&#xff0c;明明接口路径是对的啊&#xff01;一个下午&#xff0c;组里的小哥突然让我帮忙看这个问题&#xff0c;我不禁一惊&#xff0c;啥&#xff0c;这年头了还有人搞不定404&#xff0c;如有还有&#…

FFmpeg:打印音/视频信息(Meta信息)

多媒体文件基本概念 多媒体文件其实是个容器在容器里面有很多流(Stream/Track)每种流是由不同的编码器编码的从流中读出的数据称为包在一个包中包含着一个或多个帧 几个重要的结构体 AVFormatContextAVStreamAVPacket FFmpeg操作流数据的基本步骤 打印音/视频信息(Meta信息…

LVGL_基础控件滚轮roller

LVGL_基础控件滚轮roller 1、创建滚轮roller控件 /* 创建一个 lv_roller 部件(对象) */ lv_obj_t * roller lv_roller_create(lv_scr_act()); // 创建一个 lv_roller 部件(对象),他的父对象是活动屏幕对象// 将部件(对象)添加到组&#xff0c;如果设置了默认组&#xff0c…

不断优化的素数算法

前言&#xff1a;素数判断是算法中重要的一环&#xff0c;掌握优秀的素数判断方法是算法player的必修课。本文介绍的是由简到繁的素数算法&#xff0c;便于初学者从入门到精通。 素数&#xff08;质数&#xff09;&#xff1a;只能被 1 和它本身整除的数称作素数&#xff0c;如…

总结二:linux面经

文章目录 1、 Linux中查看进程运行状态的指令、查看内存使用情况的指令、tar解压文件的参数。2、文件权限怎么修改&#xff1f;3、说说常用的Linux命令&#xff1f;4、说说如何以root权限运行某个程序&#xff1f;5、 说说软链接和硬链接的区别&#xff1f;6、说说静态库和动态…

(四)正点原子STM32MP135移植——u-boot移植

一、概述 u-boot概述就不概述了&#xff0c;u-boot、kernel、dtb三件套&#xff0c;dddd 经过国庆艰苦奋战&#xff0c;已经成功把所有功能移植好了 二、编译官方代码 进入u-boot的目录 2.1 解压源码、打补丁 /* 解压源码 */ tar xf u-boot-stm32mp-v2022.10-stm32mp-r1-r0.…

充分理清限制与条件+构造二分图+最小割:ARC142E

https://www.luogu.com.cn/problem/AT_arc142_e 他的充要条件是是什么&#xff1a; a i , a j ≥ m i n ( b i , b j ) a_i,a_j\ge min(b_i,b_j) ai​,aj​≥min(bi​,bj​)存在 a i ≥ m a x ( b i , b j ) a_i\ge max(b_i,b_j) ai​≥max(bi​,bj​) 第一个条件直接预处理一…

Springcloud支付模块

客户端消费者80 order 微服务提供者8001 payment 订单模块可以调动支付模块 步骤&#xff1a; 1、建moudle 2、改写pom 3、写yml 4、主启类 5、业务类

【LinuxC】时间、时区,相关命令、函数

文章目录 一、序1.1 时间和时区1.11 时间1.12 时区 1.2 查看时间时区的命令1.21 Windows1.22 Linux 二、C语言函数2.1 通用2.11 函数简介2.12 数据类型简介 2.2 windows 和 Linux特有函数2.3 C语言示例 一、序 1.1 时间和时区 1.11 时间 时间是一种用来描述物体运动变化的量…

黑马点评-01基于Redis实现短信登陆的功能

环境准备 当前模型 nginx服务器的作用 手机或者app端向nginx服务器发起请求,nginx基于七层模型走的是HTTP协议,可以实现基于Lua直接绕开tomcat访问Redis nginx也可以作为静态资源服务器,轻松扛下上万并发并负载均衡到下游的tomcat服务器,利用集群支撑起整个项目 使用nginx部…

黑马JVM总结(二十七)

&#xff08;1&#xff09;synchronized代码块 synchronized代码块的底层原理&#xff0c;它是给一个对象进行一个加锁操作&#xff0c;它是如何保证如果你出现了synchronized代码块中出现了问题&#xff0c;它需要给这个对象有一个正确的解锁操作呢&#xff0c;加锁解锁是成对…

【c++_containers】10分钟带你学会list

前言 链表作为一个像是用“链子”链接起来的容器&#xff0c;在数据的存储等方面极为便捷。虽然单链表单独在实际的应用中没用什么作用&#xff0c;但是当他可以结合其他结构&#xff0c;比如哈希桶之类的。不过今天学习的list其实是一个带头双向链表。 言归正传&#xff0c;让…

overleaf在线编辑工具使用教程

文章目录 1 用 orcid注册overleaf获取模板2 使用模板 1 用 orcid注册overleaf获取模板 通常来说&#xff0c;在期刊投稿网站information for author中找template 。下载压缩包后上传到over leaf中。 加入找不到官方模板&#xff0c;用overleaf中的 2 使用模板 .bib文件&…

3D孪生场景SDK:Viwer 孪生世界

NSDT 编辑器 提供三维场景构建、场景效果设计、场景服务发布全流程工具等&#xff0c;其场景编辑器支持资产管理、灯光设置、骨骼动画等功能&#xff1b;致力于协助资源不足的中小企业及个人快速开发数字孪生场景&#xff0c;帮助企业提高生产力、实现降本增效。 NSDT编辑器简…

adb详细教程(四)-使用adb启动应用、关闭应用、清空应用数据、获取设备已安装应用列表

adb对于安卓移动端来说&#xff0c;是个非常重要的调试工具。本篇介绍常用的adb指令 文章目录 一、启动应用&#xff1a;adb shell am start二、使用浏览器打开指定网址&#xff1a;adb shell am start三、杀死应用进程adb shell am force-stop/adb shell am kill四、删除应用所…

【AI视野·今日CV 计算机视觉论文速览 第262期】Fri, 6 Oct 2023

AI视野今日CS.CV 计算机视觉论文速览 Fri, 6 Oct 2023 Totally 73 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Improved Baselines with Visual Instruction Tuning Authors Haotian Liu, Chunyuan Li, Yuheng Li, Yong Jae Lee大型多模…

python开发幸运水果抽奖大转盘

概述 当我女朋友跟我说要吃水果&#xff0c;又不知道吃啥水果时候&#xff0c;她以为难为到我了&#xff0c;有啥事难为到程序员的呢&#xff01; 今天用python利用第三方tkinterthreadingtime库开发一个幸运水果抽奖大转盘&#xff01;抽到啥吃啥 详细 老规矩&#xff01;咱…