2023-08-21 Unity Shader 开发入门1 —— 渲染管线

文章目录

  • 一、概述
  • 二、应用阶段
  • 三、几何阶段
  • 四、光栅化阶段

一、概述

​ Unity 中的渲染管线和图形学中的渲染管线基本上指的是相同的概念,但是具体实现和细节方面可能存在一些差异。

​ Unity 的渲染管线建立在图形学的基础上,但具有自己的实现和拓展。其提供了一个高度可配置和可拓展的框架,允许开发者根据需求自定义渲染流程。

  • 渲染管线

    • 是计算机图形学中用于将三维场景转换为最终屏幕所见图像的过程;
    • 由一系列的阶段和操作组成,每个阶段都负责执行特定的任务;
    • 逐步处理输入的集合数据和纹理信息,最终生成可视化图像的过程。

    渲染管线(流水线)就是将数据分阶段的变为屏幕图像的过程!

  • 渲染管线中的数据

    1. 顶点数据:模型的顶点坐标、法线向量、纹理坐标等等;
    2. 纹理数据:纹理贴图等;
    3. 光照数据:光照参数、光源信息等;
    4. 其他 Unity场景上相关的数据
  • 渲染管线中的阶段

    渲染管线分为 3 个阶段:

    应用阶段 → 几何阶段 → 光栅化阶段

    在每一个阶段都会对数据进行处理,最终目的就是在屏幕上让我们看见最终的图像。

image-20230821194527218
图1 渲染管线中的阶段

二、应用阶段

  • CPU 和 GPU

    • CPU:中央处理器。

      负责算数运算、逻辑操作、数据传输等通用计算任务,同时还管理和调度计算机的资源(游戏开发中——游戏逻辑处理)。

    • GPU:图形处理器。

      是专门用于图形和并行计算的处理器。显卡即搭载 GPU 的硬件设备,显卡包含一个或多个 GPU 芯片,还包含显存(用于存储图像数据)、显示接口、视频解码器等等(游戏开发中——渲染相关处理)。

    CPU 主要处理操作系统管理、程序执行、通用计算等等;

    GPU 主要处理图形渲染、图像处理等等。

  • 应用阶段的任务

    渲染管线的应用阶段中大部分的内容都和渲染无关(比如:游戏逻辑处理、动画更新、物理模拟、场景管理等等)。

    当应用阶段完成后,后面的几何阶段以及光栅化阶段将开始处理和图形渲染相关的数据和操作。

    将应用阶段为什么会归纳到渲染管线中的原因是:应用阶段为渲染管线的后续提供了最重要的内容——数据。

    应用阶段主导者是 CPU。这一阶段将渲染需要用到的数据传递给 GPU 用于后续的两个阶段的处理。

    应用阶段的任务包括:

    1. 把不可见的物体数据剔除;
    2. 准备好模型相关数据(顶点、法线、切线、贴图、着色器等等);
    3. 将数据加载到显存中
    4. 设置渲染状态(设置网格需要使用那个着色器、材质、光源属性等等);
    5. 调用 DrawCall(CPU 通知 GPU 使用相关的数据和渲染状态进行渲染)。
    image-20230821185520287
    图2 应用阶段的主要任务

​ 在应用阶段中,主要按照 Unity 的规则进行游戏开发即可,需要注意的是关于 DrawCall 的优化。

  • DrawCall

    一次 DrawCall 是 CPU 命令 GPU 进行渲染的命令。DrawCall 多了会影响性能的主要瓶颈是 CPU。

    每次调用 DrawCall 之前,CPU 需要向 GPU 发送很多内容,包括数据、状态、命令等等。

    如果 DrawCall 过多,CPU 就会把大量的时间花费在提交 DrawCall 上,造成 CPU 过载,让玩家感受到卡顿。

    减少 DrawCall 的方式:批处理技术。

    1. 合并网格(可以将静态物体合并网格);

    2. 共用材质(在不同网格之间共用一种材质);

    3. 合并图集(2D 游戏和 UI 中,可以将多张图片合并为一张大图)等等。

三、几何阶段

  • 图元

    在渲染管线中,图元是指几何数据的基本单元,它是构成几何体的最小可绘制的单元。

    图元可以是点、线、三角形,在渲染管线的几何阶段,顶点数据会被组合为图元。

    这些图元将在后续的光栅化阶段转换为像素,最终呈现在屏幕上。

  • 几何阶段的任务

    几何阶段主要由 GPU 主导,因此我们无法拥有绝对的控制权,但是 GPU 为我们开放了部分控制权。

    几何阶段主要做的事情是:根据应用阶段输入的数据信息进行顶点坐标转换以及裁剪不可见图元等工作

    image-20230821191251227
    图3 几何阶段的主要任务
    1. 顶点着色器(完全可编程)

      它处理来自应用阶段由 CPU 传递过来的顶点相关数据,输入进来的每一个顶点都会调用一次顶点着色器中的逻辑

      顶点着色器需要完成的工作主要有:

      • 坐标变换 —— 顶点变换、法线变换、纹理坐标变换等;
      • 顶点属性处理—— 对顶点的其他属性进行处理,比如顶点颜色、透明度、切线向量等,可以用于实现顶点动画、着色、光照等效果;
      • 顶点插值 —— 计算顶点属性的插值值;
      • 等等。
    2. 曲面细分着色器、几何着色器

      可选的着色器,并且需要硬件和驱动程序的支持才能使用,因此不展开介绍。

    3. 裁剪

      裁剪阶段会自动将不在视野内和部分在视野内的图元(点、线、三角形)进行裁剪。

      在该过程中可以进行一些配置,但是一般不需要进行任何处理,渲染管线会自动进行处理。

    4. 屏幕映射

      将输入的三维坐标系下的图元坐标转换到屏幕坐标系中。

  • 几何阶段为渲染准备的内容

    在渲染管线(流水线)的几何阶段:

    最主要做的工作就是:对顶点进行处理,并进行坐标转换,裁剪画面外的图元

    最主要完成的就是:将模型的顶点从其本地坐标 转换到最终的屏幕坐标中

    在顶点着色器中进行一些操作就可以带来不同的表现效果的体现,比如:水波纹、布料等等。

四、光栅化阶段

  • 像素

    像素是计算机图形学中的基本概念,它是组成图像的最小可控单位,具有位置和属性,用于表示图像中的颜色和其他信息。

    它是二维图像中的一个点,每个像素都占据屏幕上的一个固定位置。

    比如我们常见的显示器分辨率为:1920 × 1080,就表示宽度为 1920 个像素、高度为 1080 个像素。

  • 片元

    在渲染管线中,片元是指在光栅化阶段生成的像素或像素片段,是渲染管线中进行像素级别操作和计算的基本单位。

    每个片元代表了屏幕上的一个像素,并且具有位置信息和与之相关的属性,比如:颜色、深度值、法线等等。

  • 光栅化阶段的任务

    光栅化阶段同样由 GPU 主导,同样我们无法拥有绝对的控制权,同样 GPU 为我们开放了部分控制权。

    光栅化阶段主要做的事情是根据几何阶段输入的信息计算每个图元覆盖哪些像素,以及为这些像素计算他们的颜色等等工作。

    image-20230821193546872
    图4 光栅化阶段的主要任务
    1. 三角形设置

      几何阶段输入到光栅化阶段的数据主要是三角形网格的顶点信息,得到的只是三角形网格每条边的两个端点信息。

      如果想要得到整个三角形网格对像素的覆盖情况,就必须计算每条边上的像素坐标,为了能计算三角形边界像素的坐标信息,我们必须得到三角形边界的表示方式。

      在此阶段,GPU 主要做的事情是计算三角形网格的表示数据。

    2. 三角形遍历

      该阶段主要根据三角形设置中计算出的三角形网格数据,检查每个像素是否被一个三角形网格所覆盖。

      如果覆盖的话,就会生成一个片元(包含屏幕坐标、深度、法线等等信息),此阶段也被成为扫描变换。

      在此阶段,GPU 主要做的事情是根据三角形网格信息得到被它们覆盖的片元序列。

      image-20230821193929912
      图5 三角形遍历示意
    3. 片元着色器(完全可编程)

      主要完成对三角形遍历输入的片元序列中的 每个片元(像素)的着色计算和属性处理。

      片元着色器需要完成的工作主要有:

      • 光照计算 —— 计算片元的光照效果;
      • 纹理映射 —— 根据片元在纹理中的位置,对纹理进行采样,将纹理颜色映射到片元上,实现表面贴图效果;
      • 材质属性处理 —— 根据材质的属性,比如颜色、透明度、反射率等,计算片元的最终颜色和透明度;
      • 阴影计算 —— 根据光源等信息,计算片元是否处于阴影中,影响其最终颜色;
      • 等等。
    4. 逐片元操作(可配置)——输出合并阶段

      主要完成对片元着色器输出数据(最终颜色、法线、纹理坐标、深度等)进行各种处理和计算。

      逐片元操作主要完成的工作主要有:

      • 决定每个片元的可见性,比如深度测试、模板测试;
      • 如果通过了所有测试,需要把片元的颜色值和已经存储在颜色缓冲区的颜色进行合并(混合);
      • 等等。
  • 光栅化阶段为渲染准备的内容

    在渲染管线(流水线)的光栅化阶段:

    最主要做的工作是:对片元(像素)进行最终处理

    最主要完成的是:确定片元(像素)最终是否渲染到屏幕上,并且确定其的最终渲染的颜色效果

    在片元着色器中进行一些处理就可以带来不同的表现效果的体现,比如:逼真的水面效果、火焰、黑白、模糊等等效果。

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

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

相关文章

css实现div内文字自动滚动

网上找了好久,终于找到了个能实现的,把它整理一下。 需求:表格内字体过长实现自动滚动 实现思路如下: html: <div class="item-column" style="background: rgb(12, 87, 154); width: 18%; height: 60px; line-height: 60px;"><p class=&qu…

ClickHouse安装及部署

文章目录 Docker快速安装Ubuntu预编译安装包安装检查是否支持SSE4.2使用预编译安装包 Tgz安装包配置文件修改修改密码配置远程访问 其他主机访问文章参考 Docker快速安装 本地pull镜像 docker run -d --name ch-server --ulimit nofile262144:262144 -p 9000:9000 -p 8123:81…

stm32的命令规则

stm32型号的说明&#xff1a;以STM32F103RBT6这个型号的芯片为例&#xff0c;该型号的组成为7个部分&#xff0c;其命名规则如下&#xff1a;

求助:vue从后端获取数据,如何对获得的数据进行拆分?

从后端获取数据格式如下&#xff1a; { "count": 3, "lists": [ { "id": 2, "name_id": 4, "name": "4: 2201030019: 张四", }, { …

Python网络爬虫入门到实战

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 网络爬虫&#xff08;We…

记录一个用C#实现的windows计时执行任务的服务

记录一个用C#实现的windows计时执行任务的服务 这个服务实现的功能是每天下午六点统计一次指定路径的文件夹大小 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.IO; using Syst…

基于互斥锁的生产者消费者模型

文章目录 生产者消费者 定义代码实现 / 思路完整代码执行逻辑 / 思路 局部具体分析model.ccfunc&#xff08;消费者线程&#xff09; 执行结果 生产者消费者 定义 生产者消费者模型 是一种常用的 并发编程模型 &#xff0c;用于解决多线程或多进程环境下的协作问题。该模型包含…

Flask-SocketIO和Flask-Login联合开发socketio权限系统

设置 Flask, Flask-SocketIO, Flask-Login: 首先&#xff0c;确保安装了必要的库: pip install Flask Flask-SocketIO Flask-Login基础设置: from flask import Flask, render_template, redirect, url_for, request from flask_socketio import SocketIO, emit from flask_…

unity将结构体/列表与json字符串相互转化

编写Unity程序时&#xff0c;面对大量需要传输或者保存的数据时&#xff0c;为了避免编写重复的代码&#xff0c;故采用NewtonJson插件来将定义好的结构体以及列表等转为json字符串来进行保存和传输。 具体代码如下&#xff1a; using System; using System.IO; using Newtons…

Go语言基础之切片

切片 切片&#xff08;Slice&#xff09;是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活&#xff0c;支持自动扩容。 切片是一个引用类型&#xff0c;它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合 切片的定义…

Redis 整合中 Redisson 的使用

大家好 , 我是苏麟 , 今天带来 Redisson 使用 . 官方文档 : GitHub - redisson/redisson: Redisson - Easy Redis Java client with features of In-Memory Data Grid. Sync/Async/RxJava/Reactive API. Over 50 Redis based Java objects and services: Set, Multimap, Sorte…

Alibaba-Easyexcel 使用总结

简介 简介 EasyExcel 是一个基于 Java 的简单、省内存的读写 Excel 的开源项目&#xff0c;在尽可能节约内存的情况下支持读写百 M 的 Excel。 但注意&#xff0c;其不支持&#xff1a; 单个文件的并发写入、读取读取图片宏 常见问题 Excel 术语 Sheet&#xff0c;工作薄…

每日一学——案例难点Windows配置

在Windows上配置DNS服务器有几个步骤&#xff1a; 步骤1&#xff1a;打开网络连接设置 在任务栏上右键单击网络图标&#xff0c;并选择“打开网络和Internet设置”。 在新窗口中&#xff0c;选择“更改适配器选项”。 在打开的窗口中&#xff0c;找到正在使用的网络适配器&a…

RNN+LSTM正弦sin信号预测 完整代码数据视频教程

视频讲解:RNN+LSTM正弦sin信号预测_哔哩哔哩_bilibili 效果演示: 数据展示: 完整代码: import torch import torch.nn as nn import torch.optim as optim import numpy as np import matplotlib.pyplot as plt import pandas as pd from sklearn.preprocessing import…

Nginx代理功能与负载均衡详解

序言 Nginx的代理功能与负载均衡功能是最常被用到的&#xff0c;关于nginx的基本语法常识与配置已在上篇文章中有说明&#xff0c;这篇就开门见山&#xff0c;先描述一些关于代理功能的配置&#xff0c;再说明负载均衡详细。 Nginx代理服务的配置说明 1、上一篇中我们在http…

angular实现全局组件

之前我们实现全局组件的第一种方式。我们是在定义了组件的时候通过在declares:[component],然后exports出该组件。最后在页面中每次导入该组件&#xff0c;而这次我们将采用另一种方式来实现 1 新建公用组件&#xff1a; navbreadcrumbnavbreadcrumb.component.htmlnavbreadc…

python的安装

1.进入python官网下载安装包&#xff1a;https://www.python.org/ 2.安装 注意&#xff1a;勾选Add Python 3.8 to PATH选项&#xff0c;并且建议选择Install Now选项&#xff0c;东西多。 解释&#xff1a;这里的path是指系统路径&#xff0c;即将python.exe文件添加到系 统…

非阻塞重试与 Spring Kafka 的集成测试

如何为启用重试和死信发布的消费者的 Spring Kafka 实现编写集成测试。 Kafka 非阻塞重试 Kafka 中的非阻塞重试是通过为主主题配置重试主题来完成的。如果需要&#xff0c;还可以配置其他死信主题。如果所有重试均已用尽&#xff0c;事件将转发至 DLT。公共领域提供了大量资…

go 指针

我们知道go中除了map 切片等类型都是进行值传递的&#xff0c;也就是copy一份&#xff0c;不会修改原有数据 普通指针 package mainimport "fmt"func main() {var a int 1var ip *intip &afmt.Printf("ip: %v\n", ip)fmt.Printf("ip: %v\n&qu…

数据库SQL语句使用

-- 查询所有数据库 show databases; -- 创建数据库&#xff0c;数据库名为mydatabase create database mydatabase; -- 如果没有名为 mydatabase的数据库则创建&#xff0c;有就不创建 create database if not exists mydatabase; -- 如果没有名为 mydatabase的数据库则创建…