DirectX12(d3d12)初始化

一、前置要求
- Windows 10及以上(安装有DirectX12)
- VisualStudio 2022
二、DirectX12入门
1.引用头文件
#include<Windows.h>
#include<d3d12.h>
#include<dxgi1_4.h>
2.注册窗口类并初始化窗口
这里我们调用Windows API 通过应用程序的句柄来注册一个唯一的窗口类,并创建窗口实例。我们可以根据需求去创建多个窗口,或者唯一窗口。
注意这里并不是DX12的功能,而是WinAPI的功能。
int Window::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{//注册窗口类WNDCLASSEX wc = { 0 };//结构大小wc.cbSize = sizeof(WNDCLASSEX);//窗口样式: 水平大小改变重绘|竖直大小改变重绘|窗口拥有自己的绘制设备|检测鼠标双击事件wc.style = CS_HREDRAW | CS_VREDRAW|CS_OWNDC| CS_DBLCLKS;//这一句是窗口过程函数的初始化,如果有需要可以在Window里定义一个静态函数//函数签名如下,也可也不定义,自己处理MSG(下文会提到)//LRESULT CALLBACK Window::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)//wc.lpfnWndProc = Window::WndProc;//指向应用程序实例的句柄wc.hInstance = hInstance;//指定窗口的鼠标样式wc.hCursor = LoadCursor(NULL, IDC_ARROW);//设备窗口背景刷wc.hbrBackground = (HBRUSH)COLOR_WINDOW;//唯一的窗口类名称,确保窗口类在系统中是唯一的,不会与其他窗口类冲突。wc.lpszClassName = L"DXRenderer";//注册窗口类,在这里我们可以实现一个应用只能打开一次的效果if (!RegisterClassExW(&wc)){MessageBox(NULL, L"窗口类注册失败", L"错误", MB_ICONERROR);}//创建窗口句柄HWND hwnd = CreateWindow (L"DXRenderer", L"DXRenderer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);//展示窗口,nCmdShow有大量的宏标志可以使用,表示不同的打开方式ShowWindow(hwnd, nCmdShow);//一般在Show后立刻调用一次,立即更新窗口,保证良好的响应UpdateWindow(hwnd);
}
3.创建绘图设备接口(Device)
绘图设备接口是沟通GPU的重要接口,是对硬件层的隔离和隔离,并提供了更低级的GPU控制,以及对资源的管理,任务调度(可以创建多个命令队列以多线程方式进行绘图)。
在这一步,我们不需要将Device绑定到窗口,而是在后文通过交换链进行绑定。
//创建绘图设备
ID3D12Device* device = nullptr;
D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device));
4.创建Fence
Fence翻译为栅栏,是CPU与GPU同步的主要手段,Fence提供了跟踪GPU任务的能力。
//创建Fence
ID3D12Fence* fence = nullptr;
UINT64 fenceValue = 0;
d3d12Device->CreateFence(fenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
5.获取RTV,DSV,[CBV,SRV,UAV]描述符大小
- RTV (渲染目标视图) : 将渲染目标与图形渲染管线相关联。它允许图形程序将渲染的结果输出到一个或多个渲染目标上。
- DSV (深度/模板视图):通常与深度缓冲区和模板缓冲区相关联。深度缓冲区用于存储场景中各个像素的深度信息,而模板缓冲区用于存储与像素相关的模板信息。DSV允许GPU读取或写入深度和模板信息
- CBV (常量缓冲视图) :用于将常量缓冲区与着色器绑定。常量缓冲区包含了常量数据,如变换矩阵、材质属性等,这些数据可以在渲染过程中传递给着色器,以影响渲染结果。CBV允许GPU在着色器中访问这些常量数据。
- SRV (着色资源视图) :用于将纹理、缓冲区和其他资源与着色器绑定。它允许GPU在着色器中读取纹理数据、结构化缓冲区数据等。SRV是一种通用视图,可以与各种不同类型的资源相关联。
- UAV (无序访问视图) :允许GPU在着色器中对缓冲区进行无序访问,通常用于实现计算着色器中的并行计算任务。UAV允许着色器读取、写入和重新排序缓冲区中的数据,而不需要显式的同步。
// 获取RTV描述符大小
UINT rtvSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
// 获取DSV描述符大小
UINT dsvSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
//获取CBV,SRV,UAV描述符大小
//在DX12中,这三者的描述符都存储在相同的堆,使用相同的API获取
UINT cbvSrvUavSize = d3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
注意要保存这些大小,并不是一次性就丢弃。
6.检测多重采样抗锯齿(MSAA)的支持性
MSAA的原理是在渲染图像时,对每个像素位置进行多次采样。根据像素覆盖的多个采样点的值来计算最终像素的颜色。这些采样点通常位于像素中心和其周围的位置。
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaQualityLevels;
// 根据你的渲染目标格式设置,默认是32位RGBA
msaaQualityLevels.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
//采样数量
msaaQualityLevels.SampleCount = 4;
//无特殊标志
msaaQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
//质量级别设置
msaaQualityLevels.NumQualityLevels = 0;
//检测MSAA支持,会修改NumQualityLevels的值,如果不支持则为0
HRESULT hr = d3d12Device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,&msaaQualityLevels,sizeof(msaaQualityLevels)
);//根据MSAA支持来启用
if (SUCCEEDED(hr) && msaaQualityLevels.NumQualityLevels > 0)
{// MSAA支持,msaaQualityLevels.NumQualityLevels表示支持的质量级别
}
else
{// 不支持MSAA
}
7.创建命令队列(Command Queue)
命令队列是从属于Device的,一个Device可以有多个命令队列(你可以创建不同的队列以负责不同类型的职责),CPU的可以通过任意线程把渲染命令添加到命令队列。
在这一部分,我们不介绍如何把绘制命令添加到命令队列里。而是在后文交换链之后再进行介绍,以拥有一个合适的基础。
//创建命令队列
ID3D12CommandQueue* commandQueue = nullptr;
//创建命令队列描述信息
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
// 指定命令队列类型为图形命令队列
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
// 队列优先级设为正常
queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
// 无特殊标志
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
//为绘图设备创建命令队列
d3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue));
8.创建命令分配器(Command Allocator)
在介绍命令分配器之前,我们先介绍命令列表(Command List),在DX12等图形编程API中,通常不允许直接向命令队列提交绘制命令,一般只允许向命令队列提交命令列表,在提交命令列表时,会按照命令列表中相同命令顺序为命令队列添加命令。
而命令列表的创建和重用,一般情况下依赖于命令分配器,所以我们先创建一个命令分配器,并在下一个步骤中进行命令列表的创建,并对命令列表进行详细介绍。
//创建命令分配器
ID3D12CommandAllocator* commandAllocator;
HRESULT hr = d3d12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator));
9.创建命令列表(Command List)
通过命令列表,我们对低级的指令进行抽象和封装,使得功能变得更加易用。
每个命令分配器都与命令列表一一对应,命令分配器为命令列表分配内存,管理资源和状态。
命令列表可以重用,具体的方式在后文解释,同样的,命令列表的提交也将在后文进行。
这些都需要交换链作为基础才能成功被绘制。
//创建命令列表
ID3D12GraphicsCommandList* commandList;
HRESULT hr = d3d12Device->CreateCommandList(0, // NodeMask,默认为0D3D12_COMMAND_LIST_TYPE_DIRECT, // 使用Direct Command ListcommandAllocator, // 命令分配器nullptr, // Pipeline State Object(PSO),可以稍后设置IID_PPV_ARGS(&commandList)
);
10.创建交换链(Swap Chain)
交换链的作用是在这一帧图像未渲染完毕时,保留上一帧的图像,等待这一帧渲染完毕后直接替换上一帧的画面。这样使得我们看到连续的画面,而不是介于两帧之间的未渲染完成的画面。
一般来说,如果不使用这种技术,将导致画面闪烁,图像撕裂等问题
同时交换链内维护有缓冲区,存储渲染结果,待合适时机一起输出,同时这种缓冲区大小与Windows窗口紧密相关,自动维护合适的大小。
SwapChain有多个版本,这里以SwapChain1作为案例升级SwapChain3,Windows版本不同可能对支持的交换链API有影响。
//创建交换链3
ComPtr<IDXGISwapChain3> swapChain ;//交换链描述符
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
//窗口大小信息
swapChainDesc.Width = width; // 窗口宽度
swapChainDesc.Height = height; // 窗口高度
//像素格式
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 像素格式
//是否启用3D展示(通常用于3D眼镜,需要硬件支持,一般false)
swapChainDesc.Stereo = false;
//不与MSAA冲突的多重采样
swapChainDesc.SampleDesc.Count = 1; // 多重采样设置
swapChainDesc.SampleDesc.Quality = 0;
//设置后台缓冲区的用途是作为渲染目标(还可以用作着色器读取)
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
//缓冲区数量
swapChainDesc.BufferCount = bufferCount;
// 设置渲染目标与窗口大小不匹配时的缩放模式
//DXGI_SCALING_NONE:不进行缩放
//DXGI_SCALING_STRETCH:渲染目标将被拉伸以完全填充窗口
//DXGI_SCALING_ASPECT_RATIO_STRETCH:保持渲染目标的宽高比的情况下,将其拉伸以填充窗口
swapChainDesc.Scaling = DXGI_SCALING_ASPECT_RATIO_STRETCH;
// 交换效果,定义了在每次呈现后如何处理后台缓冲区,并如何切换前台和后台缓冲区
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
//设置交换链如何处置透明像素 (DXGI_ALPHA_MODE_PREMULTIPLIED 或 DXGI_ALPHA_MODE_STRAIGHT)
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
//无标志
swapChainDesc.Flags = 0;//创建交换链1(较为低级)
ComPtr<IDXGISwapChain1> swapChain1;
ThrowIfFailed(dxgiFactory->CreateSwapChainForHwnd(commandQueue.Get(), // 命令队列hwnd, // 窗口句柄&swapChainDesc, // 交换链描述符nullptr, // 全屏模式nullptr, // 允许输出&swapChain1 // 交换链对象
));// 尝试升级到IDXGISwapChain3接口
ThrowIfFailed(swapChain1.As(&swapChain));//升级成功
if(swapChain3)
{}
//升级失败
else
{}
11.创建RTV/DSV描述符堆
这里假设我们只是双重缓冲(1个显示,1个后缓冲),我们需要建立数量为2的RTV描述符。
并且我们需要一个深度缓冲描述符用于当前GPU计算使用
这里也假定交换链升级成功
//创建描述符堆的描述符,并指定属性
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
rtvHeapDesc.NumDescriptors = 2; // 描述符数量,通常等于后台缓冲区的数量
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; // 描述符堆类型,RTV
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; // 无特殊标志ComPtr<ID3D12Resource> backBuffer;
//获取缓冲区索引
UINT bufferIndex = swapChain->GetCurrentBackBufferIndex();
//获取后台缓冲区
HRESULT hr = swapChain->GetBuffer(bufferIndex, IID_PPV_ARGS(backBuffer.GetAddressOf()));//创建描述符堆
ComPtr<ID3D12DescriptorHeap> rtvHeap;
HRESULT hr = device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(rtvHeap.GetAddressOf()));//创建RTV句柄
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap->GetCPUDescriptorHandleForHeapStart();
// 假设 backBuffer 是后台缓冲区的资源对象
device->CreateRenderTargetView(backBuffer.Get(), nullptr, rtvHandle);
// 移动到下一个描述符
rtvHandle.ptr += rtvDescriptorSize; // rtvDescriptorSize 是描述符的大小//创建DSV描述符堆的描述符
D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
dsvHeapDesc.NumDescriptors = 1; // 单个深度/模板视图
dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; // 描述符堆类型,DSV
dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; // 无特殊标志
//创建dsv描述符堆
ComPtr<ID3D12DescriptorHeap> dsvHeap;
hr = device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(dsvHeap.GetAddressOf()));
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = dsvHeap->GetCPUDescriptorHandleForHeapStart();//创建深度缓冲区资源对象 depthBuffer
UINT width = 1920; // 深度缓冲区的宽度
UINT height = 1080; // 深度缓冲区的高度
DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT; // 深度/模板格式
UINT sampleCount = 1; // 采样数(通常为 1,不使用多重采样)
UINT sampleQuality = 0; // 采样质量级别
//----------------------------------------------------
D3D12_RESOURCE_DESC depthDesc = {};
depthDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; // 资源维度
depthDesc.Width = width; // 宽度
depthDesc.Height = height; // 高度
depthDesc.DepthOrArraySize = 1; // 深度或数组大小(通常为 1)
depthDesc.MipLevels = 1; // Mip 层级数量
depthDesc.Format = format; // 像素格式
depthDesc.SampleDesc.Count = sampleCount; // 采样数
depthDesc.SampleDesc.Quality = sampleQuality; // 采样质量级别
depthDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // 布局类型
depthDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; // 资源标志,允许深度/模板
//深度缓冲区清除值
D3D12_CLEAR_VALUE clearValue = {};
clearValue.Format = format; // 清除值的格式必须与深度缓冲区的格式匹配
clearValue.DepthStencil.Depth = 1.0f; // 初始深度值(通常为 1.0)
clearValue.DepthStencil.Stencil = 0; // 初始模板值(通常为 0)ComPtr<ID3D12Resource> depthBuffer; // 用于存储深度缓冲区资源
HRESULT hr = device->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), // 堆属性D3D12_HEAP_FLAG_NONE, // 堆标志&depthDesc, // 资源描述符D3D12_RESOURCE_STATE_COMMON, // 初始资源状态&clearValue, // 清除值IID_PPV_ARGS(depthBuffer.GetAddressOf()) // 输出深度缓冲区资源对象
);// 假设 depthBuffer 是深度缓冲区的资源对象
device->CreateDepthStencilView(depthBuffer.Get(), nullptr, dsvHandle);
12.设置视口
D3D12_VIEWPORT viewport = {}; // 创建视口对象
viewport.TopLeftX = 0.0f; // 视口左上角的X坐标
viewport.TopLeftY = 0.0f; // 视口左上角的Y坐标
viewport.Width = static_cast<float>(clientWidth); // 视口的宽度
viewport.Height = static_cast<float>(clientHeight); // 视口的高度
viewport.MinDepth = 0.0f; // 最小深度
viewport.MaxDepth = 1.0f; // 最大深度//在渲染过程中,在每次渲染前,将视口的属性设置到渲染管道中的命令列表(Command List)中,以便将其传递给GPU。
commandList->RSSetViewports(1, &viewport); // 设置视口
13.提交和重用命令列表
(1)重置
//命令列表的重置是可选的
commandList->Reset(commandAllocator.Get(), nullptr);
//重置分配器是必须的
commandAllocator->Reset();
(2)提交
// 记录需要的GPU命令
commandList->SetGraphicsRootSignature(rootSignature.Get());
commandList->SetPipelineState(pipelineState.Get());
commandList->SetGraphicsRootDescriptorTable(0, descriptorHeap.GetGPUDescriptorHandleForHeapStart());// 执行绘制操作
commandList->DrawIndexedInstanced(/*参数*/);//记录命令之后需要关闭
commandList->Close();
//commandQueue 是命令队列对象,ppCommandLists 是指向命令列表指针的数组。
commandQueue->ExecuteCommandLists(1, CommandListType, ppCommandLists);
14.可运行时调整的设定
-
用来渲染到屏幕上的RTV本身的格式(也就是说我们如果需要更改渲染贴图的大小,只需要在运行时直接更改RTV描述符并且替换掉原本的RTV)
-
Swap Chain 也可以在运行时更改设定,比如说运行时启用/停用MSAA
相关文章:
DirectX12(d3d12)初始化
一、前置要求 Windows 10及以上(安装有DirectX12)VisualStudio 2022 二、DirectX12入门 1.引用头文件 #include<Windows.h> #include<d3d12.h> #include<dxgi1_4.h>2.注册窗口类并初始化窗口 这里我们调用Windows API 通过应用程序的句柄来注册一个唯一…...
算法通关村-----回溯模板如何解决排列组合问题
组合总和 问题描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。candidates 中的 同一个 数字可以 无限…...
【1++的C++进阶】之智能指针
👍作者主页:进击的1 🤩 专栏链接:【1的C进阶】 文章目录 一,什么是智能指针二,为什么需要智能指针三,智能指针的发展 一,什么是智能指针 要了解智能指针,我们先要了解RA…...
一百七十九、Linux——Linux报错No package epel-release available
一、目的 在Linux中配置Xmanager服务时,执行脚本时Linux报错No package epel-release available 二、解决措施 (一)第一步,# wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm (二&…...
【AI视野·今日CV 计算机视觉论文速览 第248期】Mon, 18 Sep 2023
AI视野今日CS.CV 计算机视觉论文速览 Mon, 18 Sep 2023 Totally 83 papers 👉上期速览✈更多精彩请移步主页 Interesting: 📚Robust e-NeRF,处理高速且大噪声事件相机流的NERF模型。(from NUS新加坡国立) 稀疏噪声事件与稠密事件数据的区别:…...
解决Vue项目中的“Cannot find module ‘vue-template-compiler‘”错误
1. 问题描述 在Vue项目中,当我们使用Vue的单文件组件(.vue文件)时,有时会遇到以下错误信息: ERROR: Cannot find module vue-template-compiler这个错误通常发生在我们使用Vue的版本不匹配或者缺少必要的依赖模块时。…...
tensorflow基础
windows安装tensorflow anaconda或者pip安装tensorflow,tensorflow只支持win7 64系统,本人使用tensorflow1.5版本(pip install tensorflow1.5) tensorboard tensorboard只支持chrome浏览器,而且加载过程中可能有一段…...
spring_注解笔记
spring使用注解开发 文章目录 1.前提1 Bean2 属性注入3 衍生的注解4.自动装配5 作用域 1.前提 步骤1: 要使用注解开发,就必须要保证AOP包的导入 步骤2: xml文件添加context约束 步骤3: 配置注解的支持 <context:annotation-…...
c++运算符重载
目录 运算符重载的基本概念 重载加号运算符() 类内实现 类外实现 运算符重载碰上友元函数 可重载和不可重载的运算符 可重载的运算符 不可重载的运算符 重载自加自减运算符(a a) 智能指针 重载等号运算符() 重载等于和不等运算符(…...
vue子组件向父组件传参的方式
在Vue中,子组件向父组件传递参数可以通过自定义事件和props属性来实现。下面是一些关键代码示例: 1. 使用自定义事件: 在子组件中,通过 $emit 方法触发一个自定义事件,并传递参数。 <template><button cli…...
代码随想录Day41| 343. 整数拆分 |
343. 整数拆分 class Solution { public:int integerBreak(int n) {vector<int> f(n1,0);f[2]1;for(int i3;i<n;i){for(int j1;j<i-1;j){f[i]max(f[i],max(f[i-j]*j,(i-j)*j));}}return f[n];} }; 96. 不同的二叉搜索树 class Solution { public:int numTrees(int…...
工厂模式-(简单工厂模式)
首先看一下设计模式的六大原则 设计模式的六大原则 1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概…...
V8引擎是如何提升对象属性访问速度的?
JavaScript 中的对象是由一组组属性和值的集合,从 JavaScript 语言的角度来看,JavaScript 对象像一个字典,字符串作为键名,任意对象可以作为键值,可以通过键名读写键值。 然而在 V8 实现对象存储时,并没有…...
彩色相机工作原理——bayer格式理解
早期,图像传感器只能记录光的强弱,无法记录光的颜色,所以只能拍摄黑白照片。 1974年,拜尔提出了bayer阵列,发明了bayer格式图片。不同于高成本的三个图像传感器方案,拜尔提出只用一个图像传感器,在其前面放…...
IDEA中DEBUG技巧
Debug 介绍 Debug 设置 如上图标注 1 所示,表示设置 Debug 连接方式,默认是 Socket。Shared memory 是 Windows 特有的一个属性,一般在 Windows 系统下建议使用此设置,相对于 Socket 会快点。 ## Debug 常用快捷键 Win 快捷键M…...
人工智能训练师
人工智能训练师是一个较新的职业,2020年2月才被正式纳入国家职业分类目录。他们主要负责在人工智能产品使用过程中进行数据库管理、算法参数设置、人机交互设计、性能测试跟踪及其他辅助作业。 这个职业的背景源于AI公司从客户(用户)那里获取…...
【业务功能118】微服务-springcloud-springboot-Kubernetes集群-k8s集群-KubeSphere-OpenELB部署及应用
OpenELB部署及应用 一、OpenELB介绍 网址: openelb.io OpenELB 是一个开源的云原生负载均衡器实现,可以在基于裸金属服务器、边缘以及虚拟化的 Kubernetes 环境中使用 LoadBalancer 类型的 Service 对外暴露服务。OpenELB 项目最初由 KubeSphere 社区发…...
Unity中Shader的模板测试
文章目录 前言什么是模板测试1、模板缓冲区2、模板缓冲区中存储的值3、模板测试是什么(看完以下流程就能知道模板测试是什么)模板测试就是在渲染,后渲染的物体前,与渲染前的模板缓冲区的值进行比较,选出符合条件的部分…...
Scala 高阶:Scala中的模式匹配
一、概述 Scala中的模式匹配(case)类似于Java中的switch...case,但是Scala的模式匹配功能更为强大。通过模式匹配,可以匹配更复杂的条件和数据结构,包括常量、类型、集合、元组等。而 Java 的 switch 语句只能用于匹配…...
分子生物学——分子机器
分子生物学——分子机器 文章目录 前言一、2016年度诺贝尔化学奖1.1. 介绍1.2. 什么是分子机器?1.3. 分子机器的意义 总结 前言 对于本次搜集分子生物学领域的一个诺贝尔奖的有关内容的作业 参考文献: https://www.cas.cn/zt/sszt/2016nobelprize/hxj/2…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
