D3D11_Chili_Tutorial(2):画一个三角形
文章目录
- 11:D3D初始化篇—— COM(Component Object Model)
- 12:D3D架构 / 交换链
- 13:初始化设备
- 14:调试层
- 15:智能指针
- 16:画一个三角形(上集)
- 17:画一个三角形(下集)
- 18:做实验
- 19:常数缓存
- 流水线
11:D3D初始化篇—— COM(Component Object Model)
非常推荐的文章:
https://zhuanlan.zhihu.com/p/121800182
https://zhuanlan.zhihu.com/p/122482719
https://zhuanlan.zhihu.com/p/457348124
COM:Component Object Model
C++重用是通过源码而非编译好的二进制文件,它不太会关心二进制对象的格式。
那么首先来看,微软为啥要搞这么一个东西。
拿虚表举例,MSVC编译器会将指向虚表的指针放在类的开头(也就是先虚表指针,再类成员),然而对于GNU就是放在类的末尾。这就会导致一个不兼容问题:比如我在GNU环境下想用MSVC编译出来的dll咋办?即C++的不同编译器之间难以交互。
并且就算是同一个编译器,不同版本之间也很难交互。
比如这个问题下的大佬们所说:怎么通俗的解释COM组件? - 知乎 (zhihu.com)、
当自己写的一个dll升级的时候,内部可能增加了成员,导致分配的空间发生变化,从而使得次dll和以前的dll不能兼容。这个就是臭名昭著的dll hell,为此微软最开始想了个很挫的方法,那就是在dll后面加上自己的版本号,如:myDll_1.dll, myDll_2.dll……
作者:Froser
链接:https://www.zhihu.com/question/49433640/answer/116028598
并且像灵剑前辈说的那样,如果库升级了,一个类新增了成员,大小发生变化,那么之前编出来的dll中还是旧的定义下new出来的空间,在新的库中就不能使用。
所以COM的目标是想解决这样一些矛盾,为软件提供二进制层面的接口。我们可以直接让二进制文件被其他软件使用,而无需获取源码。这是一个很稳定的接口,就算重新编译了二进制文件,依赖此的客户端也不会崩溃。
COM的一些好处如下(但也正如灵剑前辈所言,其是一个遗留问题,但它仍然是Windows上的C++的二进制本机代码的动态链接的最佳的选择):
- 不用区分语言
可以在不同版本编译器、不同编译器甚至不同语言间提供接口,只要这种语言支持函数指针。如果这种语言支持操作内存,那么还可以创建COM物体 - 资源分配
不依赖于任何特定语言,有一套独立的资源分配系统。 - UUID
构造了一个操作系统级别的Factory,规定所有人的Interface都统一用UUID来标识 - 独立于语言的强大封装
- 线程安全
- 支持分布
- …
对于C++,我们可以这样制作interface:比如两个接口,一个openable,一个punchable,把它们弄成两个纯虚类,然后拥有这两种方法的就利用C++的多继承机制去继承他们俩。
还记得我们之前在龙书学习笔记中说的,I开头对象:COM 接口都以大写字母“I”作为开头。例如表示命令列表的COM接口为 ID3D12GraphicsCommandList
对于COM接口,首先告诉COM工厂让它创建COM对象,创建完后就给一些COM对象的接口,前缀为I。我们只需专注和接口交互。
当创建COM对象的时候,需要调用工厂相关的函数,让COM去做处理。因此可以想象对于COM对象就不是new和delete了:
在这样改造之后,出问题的还有析构过程~MyClass()或者说delete myClass,因为同一个对象可能返回了很多个接口,有些接口还在被使用,如果其中一个被人delete了,其他接口都会出错,所以又引入了引用计数,来让许多人可以共享同一个对象。
作者:灵剑
链接:https://www.zhihu.com/question/49433640/answer/115952604
COM对象会统计其引用次数,因此在使用完某接口时我们应调用它的 Release 方法而不是 delete ——当COM对象的引用计数为0它将自行释放自己所占用的内存。一开始则是creates初始化引用计数为1,别处使用就AddRef引用计数++,别处不使用了就Release然后引用计数–。
接着还要介绍几个重要的函数:
IUnknown::QueryInterface(REFIID,void) - Win32 apps | Microsoft Docs
Queries a COM object for a pointer to one of its interface; identifying the interface by a reference to its interface identifier (IID). If the COM object implements the interface, then it returns a pointer to that interface after calling IUnknown::AddRef on it.
那么对于UUID,一种是在头文件<Wininet.h>中通过类 IActiveDesktop ,这个类名中就包含有 __uuidof 的方法。
而像我们会用到的如:
__uuidof(ID3D12CommandAllocator)
其在d3d12.h中就封装好了uuid:
MIDL_INTERFACE("6102dee4-af59-4b09-b999-b44d73f09b24")
ID3D12CommandAllocator : public ID3D12Pageable
{
public:virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;};
示例代码(获取桌面壁纸的名称和路径):
#include <Windows.h>
#include <WinInet.h>
#include <ShlObj.h>
#include <iostream>int main()
{CoInitialize(nullptr); // 使用COM前先初始化子系统;不过在D3D中使用的是“轻量COM”,根本无需初始化子系统IActiveDesktop* pDesktop = nullptr;WCHAR wszWallpaper[MAX_PATH]; // 用于储存壁纸的名称的缓存// 创建真正的COM对象CoCreateInstance(CLSID_ActiveDesktop, // 活动的桌面nullptr,CLSCTX_INPROC_SERVER, // 创建对象的上下文。如进程、本地机器、远程上下文等__uuidof(IActiveDesktop), // 接口的UUID,希望函数查询的物体有这个接口reinterpret_cast<void**>(&pDesktop));pDesktop->GetWallpaper(wszWallpaper, MAX_PATH, 0);pDesktop->Release();std::wcout << wszWallpaper;CoUninitialize();std::cin.get();return 0;
}
输出结果:
再来看一下COM对象的一些细节:
如上图,比如一个COM对象有两个接口,那么它就会有两个虚表,一个虚表对应一组接口的函数。
12:D3D架构 / 交换链
D3D是面向对象的架构,建立在 COM 对象上。
如上图,这些父类都是 Device 。上图黄色的貌似打错了,应该是 IDXGIDEVICE
DXGI 承担的是底层的可以从 D3D 中剥离出去的任务,并且在版本迭代不会像 D3D 那样快。DXGI 现在的工作是遍历设备上所有可用的硬件。显示渲染帧,控制 Gamma 值。这些东西在各版本的 D3D 都不怎么需要变,所以干脆把这些东西独立出来放进 DXGI 里。
我们创建 D3D11 程序时并不意味着我们需要支持 D3D11 显卡。
当你编写 D3D11 应用程序时,如下图所示:
如上图字幕,其方法就是在创建设备时,特性级别选择 9 就行了。
这个不要和 SDKVersion 搞混了:
目标 SDK 版本11,这意味着用户只需要更新其应用程序的 D3D 版本,而与显卡无关。
设备用于创建物体,上下文(CONTEXT 用于绘制,即发出渲染命令并配置渲染管道):
DX11 里的上下文分为即时的和延迟的两种:
所以延迟上下文在多线程中表项良好。但唯一延迟上下文做不到的是查询图形驱动程序,因为它只会建立以下命令列表,在将来的某个时间执行。即时上下文可以查询到信息。(D3D12 似乎已经取消了立即上下文)
13:初始化设备
先来创建 Graphics.h:
#pragma once
#include "ChiliWin.h"
#include <d3d11.h>class Graphics
{
public:Graphics(HWND hWnd);
};
因为必须使用窗口的 handle ,所以我们构造函数传一个 HWND
随后在Windows类中添加这个类的成员(由于初始化依赖 HWND ,所以用智能指针管理):
并添加获取的函数:
Graphics& Gfx(); // 得不到图形的时候抛出异常,所以不用noexcept
补全后的头文件是这样的:
#pragma once
#include "ChiliWin.h"
#include <d3d11.h>class Graphics
{
public:Graphics(HWND hWnd);Graphics(const Graphics&) = delete;Graphics& operator=(const Graphics&) = delete;~Graphics();void EndFrame();void ClearBuffer(float red, float green, float blue) noexcept;
private:ID3D11Device* pDevice = nullptr;IDXGISwapChain* pSwap = nullptr;ID3D11DeviceContext* pContext = nullptr;ID3D11RenderTargetView* pTarget = nullptr;
};
对应的 EndFrame 函数:
void Graphics::EndFrame()
{pSwap->Present(1u, 0u);
}
这里写 1u 是我们觉得能到 60 帧。如果目标帧率只有 30 帧,就写 2u (60 / 2),以此类推。后一个参数 0u 是不要任何标签的意思。
然后就可以在我们的 App 框架中处理了:
void App::DoFrame()
{wnd.Gfx().EndFrame();
}
我们希望使用这个函数:
RenderTargetView 一般是从纹理对象(Texture Object)创建的,但我们也没有。但我们可以这样:
因为交换链可以看作是多个纹理的集合,多个帧缓存的集合。我们可以使用交换链上的函数访问后缓存,这其实就是一个纹理。然后在该纹理上调用函数创建渲染目标视图(RenderTargetView)并渲染。
所以这里我们用 pSwap->GetBuffer 得到 pBackBuffer ,第一个参数 0 是后缓存的索引。随后我们用 pTarget 来保存我们的渲染目标视图(RenderTargetView)。
// gain access to texture subresource in swap chain (back buffer)
ID3D11Resource* pBackBuffer = nullptr;
pSwap->GetBuffer(0, __uuidof(ID3D11Resource), reinterpret_cast<void**>(&pBackBuffer));
pDevice->CreateRenderTargetView(pBackBuffer,nullptr,&pTarget
);
pBackBuffer->Release();
然后的 ClearBuffer 就很简单了:
void Graphics::ClearBuffer(float red, float green, float blue) noexcept
{const float color[] = { red,green,blue,1.0f };pContext->ClearRenderTargetView(pTarget, color);
}
有了上面的结果,我们就可以用计时器让我们的颜色的红绿通道一直变化了:
void App::DoFrame()
{const float c = sin(timer.Peek()) / 2.0f + 0.5f;wnd.Gfx().ClearBuffer(c, c, 1.0f);wnd.Gfx().EndFrame();
}
14:调试层
这一节将为 D3D 子系统设置错误检查和丰富的诊断程序。
上一节我们写了类似的代码:
但是没有给返回值,direct3d函数通常会返回 HRESULT ,如果要发生错误它会抛出一些诊断信息会帮助解决异常。
自然的想法是和一起窗口类的处理一样,之前处理窗口类的时候我们写了这两个宏:
// error exception helper macro
#define CHWND_EXCEPT( hr ) Window::Exception( __LINE__,__FILE__,hr )
#define CHWND_LAST_EXCEPT() Window::Exception( __LINE__,__FILE__,GetLastError() )
然后处理的时候我们像这样直接抛出异常:
最后的 WinMain 再去处理异常:
try
{return App{}.Go();
}
catch (const ChiliException& e)
{MessageBox(nullptr, e.what(), e.GetType(), MB_OK | MB_ICONEXCLAMATION);
}
catch (const std::exception& e)
{MessageBox(nullptr, e.what(), "Standard Exception", MB_OK | MB_ICONEXCLAMATION);
}
catch (...)
{MessageBox(nullptr, "No details available", "Unknown Exception", MB_OK | MB_ICONEXCLAMATION);
}
但这里有一个问题,很久以前 DirectX SDK 和 Windows SDK 是分开的,而 DirectX SDK 与 Windows 的 HRESULT 不兼容。你需要通过一个名为 DXerror 的独立库来获取 HRESULT 并将其转换为人类可读的字符串。后来 DirectX API 已合并到 Windows SDK 中,当发生这种情况时他们更改了格式消息让他们也支持报告 DX 的错误,所以不再需要 DXerror(DXERR.LIB) 了。不过仅当您使用 Windows 8 或更高版本时才有效。用 WIN7 的不行,WIN7 也必须使用 DXERR.LIB 。但是问题是当 DirectX API 合并到 Windows SDK 的时候 DXERR.LIB 就被废弃了。而如果你的目标平台是 WIN7 那么仍然需要下载 DXERR.LIB 。并且还出现一个问题是 dxerr 仅支持 Unicode 和 nstring(narrow string)。
最后 Chili 解决了这一切,需要文件如下:
除此之外还在图形类中添加了一些类:
而在 DXERR 中我们感兴趣的是这两个方法:
const CHAR* WINAPI DXGetErrorStringA( _In_ HRESULT hr );void WINAPI DXGetErrorDescriptionA( _In_ HRESULT hr, _Out_cap_(count) CHAR* desc, _In_ size_t count );
两个函数前者提供代表该错误的宏的名称,后者则是错误的描述。
接着又添加了 设备删除异常 类:
然后在 Graphics.cpp 中同样我们定义几个宏来让异常抛出的代码更简洁:
// graphics exception checking/throwing macros (some with dxgi infos)
#define GFX_EXCEPT_NOINFO(hr) Graphics::HrException( __LINE__,__FILE__,(hr) )
#define GFX_THROW_NOINFO(hrcall) if( FAILED( hr = (hrcall) ) ) throw Graphics::HrException( __LINE__,__FILE__,hr )#ifndef NDEBUG
#define GFX_EXCEPT(hr) Graphics::HrException( __LINE__,__FILE__,(hr),infoManager.GetMessages() )
#define GFX_THROW_INFO(hrcall) infoManager.Set(); if( FAILED( hr = (hrcall) ) ) throw GFX_EXCEPT(hr)
#define GFX_DEVICE_REMOVED_EXCEPT(hr) Graphics::DeviceRemovedException( __LINE__,__FILE__,(hr),infoManager.GetMessages() )
#else
#define GFX_EXCEPT(hr) Graphics::HrException( __LINE__,__FILE__,(hr) )
#define GFX_THROW_INFO(hrcall) GFX_THROW_NOINFO(hrcall)
#define GFX_DEVICE_REMOVED_EXCEPT(hr) Graphics::DeviceRemovedException( __LINE__,__FILE__,(hr) )
#endif
于是我们就可以直接这样包住我们之前写的代码了(检查他们返回的 HRESULT ):
// create device and front/back buffers, and swap chain and rendering context
GFX_THROW_INFO(D3D11CreateDeviceAndSwapChain(nullptr,D3D_DRIVER_TYPE_HARDWARE,nullptr,swapCreateFlags,nullptr,0,D3D11_SDK_VERSION,&sd,&pSwap,&pDevice,nullptr,&pContext
));
// gain access to texture subresource in swap chain (back buffer)
ID3D11Resource* pBackBuffer = nullptr;
GFX_THROW_INFO(pSwap->GetBuffer(0, __uuidof(ID3D11Resource), reinterpret_cast<void**>(&pBackBuffer)));
GFX_THROW_INFO(pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &pTarget));
pBackBuffer->Release();
上面这样写宏,是为了在 Debug 和 Release 下有区别,调试模式下就让 InfoManager 添加信息。
但是在我们的 EndFrame 方法里头就有点特殊了:
void Graphics::EndFrame()
{HRESULT hr;
#ifndef NDEBUGinfoManager.Set();
#endifif (FAILED(hr = pSwap->Present(1u, 0u))){if (hr == DXGI_ERROR_DEVICE_REMOVED){throw GFX_DEVICE_REMOVED_EXCEPT(pDevice->GetDeviceRemovedReason());}else{throw GFX_EXCEPT(hr);}}
}
这里 pSwap->Present 返回的可能是已移除设备的错误代码,这是一个特殊的错误代码,因为它还包括其他信息,所以这里我们的处理方法是又加了一个 pDevice->GetDeviceRemovedReason()
用这个函数来获取。这里产生的原因通常是由于驱动程序崩溃,或者超频你的GPU并搞砸了。所以有错误就抛出异常并获取原因。
其他的处理异常和之前 Windows 下的处理方法类似。
在 Window.h 中我们还添加了额外的一个类(无图形异常):
当我们尝试获取图形类,但没有时将被抛出异常。
当我们刻意写错并在调试层工作时:
除了我们刚刚的异常处理,在底下的output中还会有额外的相关信息:
但是我们希望错误弹出窗口就有足够的信息,于是我们搞了一个新的类(通过一个IDXGIInfoQueue):
DxgiInfoManager.h:
#pragma once
#include "ChiliWin.h"
#include <vector>class DxgiInfoManager
{
public:DxgiInfoManager();~DxgiInfoManager();DxgiInfoManager(const DxgiInfoManager&) = delete;DxgiInfoManager& operator=(const DxgiInfoManager&) = delete;void Set() noexcept;std::vector<std::string> GetMessages() const;
private:unsigned long long next = 0u;struct IDXGIInfoQueue* pDxgiInfoQueue = nullptr;
};
实现中我们会加载这样的一个dll,然后在 DLL 中查找该接口的名称,然后调用函数来处理该接口:
当我们获取消息时,本质上是遍历消息队列:
通过调用 GetMessage ,传递nullptr,这将用索引对于消息的长度赋值给 messageLength
我们还用了这个函数便于中间更改:
这里我们传入了 DXGI_DEBUG_ALL ,但也可以仅调试来自 DXGI 或 D3D 的消息,详见 MSDN:
比如此时我故意写错:
sd.OutputWindow = (HWND)216487;
运行就会有报错窗口:
15:智能指针
之前没用智能指针管理,比如:
// gain access to texture subresource in swap chain (back buffer)
ID3D11Resource* pBackBuffer = nullptr;
GFX_THROW_INFO(pSwap->GetBuffer(0, __uuidof(ID3D11Resource), reinterpret_cast<void**>(&pBackBuffer)));
GFX_THROW_INFO(pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &pTarget));
pBackBuffer->Release();
如果中间两句抛异常,那么 Release 不被执行,内存泄漏。
于是这里我们直接上 ComPtr(需要包含头文件#include <wrl.h>
),运用 RAII:
namespace wrl = Microsoft::WRL;// gain access to texture subresource in swap chain (back buffer)
wrl::ComPtr<ID3D11Resource> pBackBuffer;
GFX_THROW_INFO(pSwap->GetBuffer(0, __uuidof(ID3D11Resource), &pBackBuffer));
GFX_THROW_INFO(pDevice->CreateRenderTargetView(pBackBuffer.Get(), nullptr, &pTarget));
而我们之前要传递的部分就用 Get 方法:
并且由于智能指针重载了方法,之前的 reinterpret_cast 也可以直接取地址了。
我们之所以不用比如 unique_ptr 之类的,是因为 unique_ptr 默认的删除器不会调用 COM 的release方法。所以我们用 ComPtr
并且,当要获取接口时,我们需要传递一个 pp (pointer to pointer,指向指针的指针),然后函数将帮助你填充这个接口的指针。而使用 Unique 指针时实际上把指针封装了,就无法得到这个 pp 值。再者,ComPtr还有引用计数等等。综上我们需要用 ComPtr 。
ComPtr 也有一些坑,比如我们之前写的函数:
GFX_THROW_INFO(D3D11CreateDeviceAndSwapChain(nullptr,D3D_DRIVER_TYPE_HARDWARE,nullptr,swapCreateFlags,nullptr,0,D3D11_SDK_VERSION,&sd,&pSwap,&pDevice,nullptr,&pContext));
这里的交换链pSwap之类的都用ComPtr包起来了:
Graphics.h:
private:
#ifndef NDEBUGDxgiInfoManager infoManager;
#endifMicrosoft::WRL::ComPtr<ID3D11Device> pDevice;Microsoft::WRL::ComPtr<IDXGISwapChain> pSwap;Microsoft::WRL::ComPtr<ID3D11DeviceContext> pContext;Microsoft::WRL::ComPtr<ID3D11RenderTargetView> pTarget;
而这里要传 pp 的时候,如果pSwap指向一个实际的 COM 对象,传入我们写的 &pSwap ,它将首先调用释放函数(release)然后再返回地址。这很合理,如果要填充它(传 pp 不就是为了填充这个指针吗),就必须先把以前的东西释放掉。这样就不会泄漏内存资源。
但是有时你只想获取要获取指针的指针的地址,但不想填充指针:
那么就不能使用这个 operator & (不然就把资源释放了,不是我们想要的),可以使用 GetAddressOf 方法:
16:画一个三角形(上集)
可以从官方看流水线:
https://docs.microsoft.com/zh-cn/windows-hardware/drivers/display/pipelines-for-direct3d-version-11
关于缓冲:
https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-buffers-intro
https://docs.microsoft.com/zh-cn/windows/win32/direct3d11/overviews-direct3d-11-resources-buffers-intro
这里 IA 就是渲染管线的 Input Assembler (输入装配阶段)的意思,可以看到第三个参数是一个 pp 表示可以指定多个缓冲区(相当于指针数组了):
IASetVertexBuffers文档:
https://docs.microsoft.com/zh-cn/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-iasetvertexbuffers
我们还必须要一个 vertex shader,否则会报错。着色器的输出输入必须用语义标记。
我们可以直接 Build ,VS内置编译,会将其编译成 cso 形式,还会报错之类的:
1>compilation object save succeeded; see E:\MyD3D11Learn\D3D11_Chili_Tutorial\D3D11_Chili_Tutorial\bin\Win32\Debug\VertexShader.cso
我们链接#pragma comment(lib,"D3DCompiler.lib")
,可以使用它在运行时编译着色器。不过我们现在只需要使用它的着色器加载功能就行了。还需要包含头文件#include <d3dcompiler.h>
。
wrl::ComPtr<ID3DBlob> pBlob;
GFX_THROW_INFO(D3DReadFileToBlob(L"VertexShader.cso", &pBlob));
但是我们这样写,还需要配置每次编译的 cso 文件输出位置才行(hlsl文件右键->Properties)。
改成了:$(ProjectDir)%(Filename).cso
还可以选择着色器类型:
17:画一个三角形(下集)
D3D允许我们渲染到离线目标 Off-Screen Target 上。
这里有个坑就是上讲将 ComPtr 取地址会释放的坑,所以我们要用 GetAddressOf 而不能用 & :
// bind render target
pContext->OMSetRenderTargets(1u, pTarget.GetAddressOf(), nullptr);
当然这一节我们先写好 pixel shader:
float4 main() : SV_TARGET
{return float4(1.0f, 1.0f, 1.0f, 1.0f);
}
这里我们还必须要指定 D3D11_VIEWPORT 。从 NDC 到 屏幕空间,如下图:
D3D11_VIEWPORT 可以不满屏幕空间,比如上图的黄色框框只占屏幕的四分之一,也可以用作 D3D11_VIEWPORT 。
我们还需要设置渲染图元:
参考链接:
https://docs.microsoft.com/zh-cn/windows/win32/direct3d11/d3d10-graphics-programming-guide-primitive-topologies
// Set primitive topology to triangle list (groups of 3 vertices)
pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
要让着色器正确解析 buffer 数据,还需要 input layout,我们顶点着色器输入是这样的:
float2 pos : Position
这里默认就是 Position0 了,这个0就对应着
// input (vertex) layout (2d position only)
wrl::ComPtr<ID3D11InputLayout> pInputLayout;
const D3D11_INPUT_ELEMENT_DESC ied[] =
{{ "Position",0,DXGI_FORMAT_R32G32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 },
};
GFX_THROW_INFO(pDevice->CreateInputLayout(ied, (UINT)std::size(ied),pBlob->GetBufferPointer(),pBlob->GetBufferSize(),&pInputLayout
));
D3D11_INPUT_ELEMENT_DESC 的第二个参数(对应上面代码"Position"后面那个0)。
比如:
顶点着色器代码:
float4 main( float2 pos : Hbh2 ) : SV_Position
{return float4(pos.x,pos.y,0.0f,1.0f);
}
input layout:
const D3D11_INPUT_ELEMENT_DESC ied[] =
{{ "Hbh",2,DXGI_FORMAT_R32G32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 },
};
这样写照样是对的。
查阅MSDN我们知道:
可以看见,我们这里的 BytecodeLength 写的是 pBlob->GetBufferSize(),
,其实这里的 BytecodeLength 就是为了检查数据描述符与着色器确实匹配。
画一个三角形函数的所有代码:
void Graphics::DrawTestTriangle()
{namespace wrl = Microsoft::WRL;HRESULT hr;struct Vertex{float x;float y;};// create vertex buffer (1 2d triangle at center of screen)const Vertex vertices[] ={{ 0.0f,0.5f },{ 0.5f,-0.5f },{ -0.5f,-0.5f },};wrl::ComPtr<ID3D11Buffer> pVertexBuffer;D3D11_BUFFER_DESC bd = {};bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;bd.Usage = D3D11_USAGE_DEFAULT;bd.CPUAccessFlags = 0u;bd.MiscFlags = 0u;bd.ByteWidth = sizeof(vertices);bd.StructureByteStride = sizeof(Vertex);D3D11_SUBRESOURCE_DATA sd = {};sd.pSysMem = vertices;GFX_THROW_INFO(pDevice->CreateBuffer(&bd, &sd, &pVertexBuffer));// Bind vertex buffer to pipelineconst UINT stride = sizeof(Vertex);const UINT offset = 0u;pContext->IASetVertexBuffers(0u, 1u, pVertexBuffer.GetAddressOf(), &stride, &offset);// create pixel shaderwrl::ComPtr<ID3D11PixelShader> pPixelShader;wrl::ComPtr<ID3DBlob> pBlob;GFX_THROW_INFO(D3DReadFileToBlob(L"PixelShader.cso", &pBlob));GFX_THROW_INFO(pDevice->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &pPixelShader));// bind pixel shaderpContext->PSSetShader(pPixelShader.Get(), nullptr, 0u);// create vertex shaderwrl::ComPtr<ID3D11VertexShader> pVertexShader;GFX_THROW_INFO(D3DReadFileToBlob(L"VertexShader.cso", &pBlob));GFX_THROW_INFO(pDevice->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &pVertexShader));// bind vertex shaderpContext->VSSetShader(pVertexShader.Get(), nullptr, 0u);// input (vertex) layout (2d position only)wrl::ComPtr<ID3D11InputLayout> pInputLayout;const D3D11_INPUT_ELEMENT_DESC ied[] ={{ "Position",0,DXGI_FORMAT_R32G32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 },};GFX_THROW_INFO(pDevice->CreateInputLayout(ied, (UINT)std::size(ied),pBlob->GetBufferPointer(),pBlob->GetBufferSize(),&pInputLayout));// bind vertex layoutpContext->IASetInputLayout(pInputLayout.Get());// bind render targetpContext->OMSetRenderTargets(1u, pTarget.GetAddressOf(), nullptr);// Set primitive topology to triangle list (groups of 3 vertices)pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);// configure viewportD3D11_VIEWPORT vp;vp.Width = 800;vp.Height = 600;vp.MinDepth = 0;vp.MaxDepth = 1;vp.TopLeftX = 0;vp.TopLeftY = 0;pContext->RSSetViewports(1u, &vp);GFX_THROW_INFO_ONLY(pContext->Draw((UINT)std::size(vertices), 0u));
}
18:做实验
默认情况下,渲染管线将进行背面剔除(back-face culling),三角形点顺序逆时针被认为是背面,会被剔除。
可以看到我们之前的顶点:
const Vertex vertices[] =
{{ 0.0f,0.5f },{ 0.5f,-0.5f },{ -0.5f,-0.5f },
};
是顺时针的,所以不会被剔除。
这里我们想得到彩色的三角形,我们给顶点加颜色属性:
struct Vertex
{struct{float x;float y;} pos;struct{unsigned char r;unsigned char g;unsigned char b;unsigned char a;} color;
};Vertex vertices[] =
{{ 0.0f,0.5f,255,0,0,0 },{ 0.5f,-0.5f,0,255,0,0 },{ -0.5f,-0.5f,0,0,255,0 },{ -0.3f,0.3f,0,255,0,0 },{ 0.3f,0.3f,0,0,255,0 },{ 0.0f,-0.8f,255,0,0,0 },
};
着色器我们将这样写:
VS:
struct VSOut
{float3 color : Color;float4 pos : SV_Position;
};VSOut main( float2 pos : Position,float3 color : Color )
{VSOut vso;vso.pos = float4(pos.x,pos.y,0.0f,1.0f);vso.color = color;return vso;
}
PS:
float4 main( float3 color : Color ) : SV_Target
{return float4( color,1.0f );
}
由于 PS 中我们只想传一个 Color,不需要 Position,所以VS中我们的VSOut内部顺序是先 color 再 pos,不能调换,否则 PS 解析的第一个就不是 color 了就会出错。
同时我们在VS中指定了float3 color : Color
,d3d就会把你的输入转换为这个指定的类型。但是我们还可以指定一些规则,通过我们指定的类型:
UINT将会被转换为确切的整数值,但UNORM将会把输入类型归一化。比如此时输入255就会被转换为1.0. 这正是我们想要的(颜色在 0 到 1 浮点的范围)。
所以我们在指定 input layout 的时候指定的是DXGI_FORMAT_R8G8B8A8_UNORM:
const D3D11_INPUT_ELEMENT_DESC ied[] =
{{ "Position",0,DXGI_FORMAT_R32G32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 },{ "Color",0,DXGI_FORMAT_R8G8B8A8_UNORM,0,8u,D3D11_INPUT_PER_VERTEX_DATA,0 },
};
为了避免顶点重复,我们这一节引入 index buffer:
// create index buffer
const unsigned short indices[] =
{0,1,2,0,2,3,0,4,1,2,1,5,
};
wrl::ComPtr<ID3D11Buffer> pIndexBuffer;
D3D11_BUFFER_DESC ibd = {};
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.Usage = D3D11_USAGE_DEFAULT;
ibd.CPUAccessFlags = 0u;
ibd.MiscFlags = 0u;
ibd.ByteWidth = sizeof( indices );
ibd.StructureByteStride = sizeof( unsigned short );
D3D11_SUBRESOURCE_DATA isd = {};
isd.pSysMem = indices;
GFX_THROW_INFO( pDevice->CreateBuffer( &ibd,&isd,&pIndexBuffer ) );// bind index buffer
pContext->IASetIndexBuffer( pIndexBuffer.Get(),DXGI_FORMAT_R16_UINT,0u );
drawcall也就要从原来的 pContext->Draw((UINT)std::size(vertices), 0u)
改为:
pContext->DrawIndexed( (UINT)std::size( indices ),0u,0u )
此时我们能输出一个漂亮的六边形了:
测试视口:
我们的视口代码是这样的
// configure viewport
D3D11_VIEWPORT vp;
vp.Width = 800;
vp.Height = 600;
vp.MinDepth = 0;
vp.MaxDepth = 1;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
pContext->RSSetViewports(1u, &vp);
我们改一下:
vp.Width = 400;
vp.Height = 300;
然后就会发现只在左上角渲染了(全屏 800 * 600,视口大小 400 * 300,视口左上角指定的为 0, 0 ):
全屏的大小在我们之前的 App 框架中指定:
App::App():wnd(800, 600, "The Donkey Fart Box")
{}
19:常数缓存
对于每一次移动,我们当然可以在CPU计算好再传给GPU,但是,对于上千个点,这样做每次都要传上千个数据,占用大量带宽。所以一般我们用 dynamic constant 数据,每次通过变换来移动。即改变上千个点不如改变只有16个数的变换矩阵。
在测试代码中我们是每一帧传输的,但是真正的引擎是不会这样做的,那只是测试代码。
做法是用一种叫做 着色器常数缓存(shader constant buffer) 的东西。这将允许我们将一些常量值绑定到着色器阶段,可用于该着色器的每次调用。
代码如下:
// create constant buffer for transformation matrix
struct ConstantBuffer
{struct{float element[4][4];} transformation;
};
const ConstantBuffer cb =
{{(3.0f / 4.0f) * std::cos(angle), std::sin(angle), 0.0f, 0.0f,(3.0f / 4.0f) * -std::sin(angle), std::cos(angle), 0.0f, 0.0f,0.0f, 0.0f, 1.0f, 0.0f,0.0f, 0.0f, 0.0f, 1.0f,}
};
wrl::ComPtr<ID3D11Buffer> pConstantBuffer;
D3D11_BUFFER_DESC cbd;
cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
cbd.Usage = D3D11_USAGE_DYNAMIC;
cbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
cbd.MiscFlags = 0u;
cbd.ByteWidth = sizeof(cb);
cbd.StructureByteStride = 0u;
D3D11_SUBRESOURCE_DATA csd = {};
csd.pSysMem = &cb;
GFX_THROW_INFO(pDevice->CreateBuffer(&cbd, &csd, &pConstantBuffer));
基本上就是围绕 Z 轴旋转的矩阵。
(angle是我们传入的参数void Graphics::DrawTestTriangle(float angle)
)
这里我们把 USAGE 设置为动态,这将通常是您使用常数缓存的方式:
(本地文档:file:///E:/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9B%BE%E5%BD%A2%E5%AD%A6%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/D3D11/%E6%96%B0%E5%BB%BA%E6%96%87%E4%BB%B6%E5%A4%B9/DX11+%E4%B8%AD%E8%AF%91.pdf)
注:参考文档https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-subresources,一个buffer就是一个简单的 subresource ,Textures 则有一点复杂。
创建一个buffer通常就是三步:
然后绑定一下:
// bind constant buffer to vertex shader
pContext->VSSetConstantBuffers(0u, 1u, pConstantBuffer.GetAddressOf());
最后就是 shader 里头用一下了:
VS中先定义一下,cbuffer是hlsl关键字:
cbuffer CBuf
{matrix transform;
};
然后注意D3D中矩阵乘法是右乘,向量在左边矩阵在右边:
VSOut main( float2 pos : Position,float3 color : Color )
{VSOut vso;vso.pos = mul(float4(pos.x,pos.y,0.0f,1.0f), transform);vso.color = color;return vso;
}
还有一个小细节:CPU里的二维数组按行存储(row-major ordering),但GPU(HLSL中)则是按列存储(column-major ordering)。所以我们应该传入的时候进行一波转置,但是我们也可以用另一种方法,就是告诉 HLSL ,这个矩阵是按行排列的:
但是缺点是在 GPU 上乘以行主矩阵要比列主矩阵稍慢。但这样我们更轻松。将来我们实际上要在GPU获取矩阵之前将其转置。但现在我们就这样做。
流水线
参考:https://zhuanlan.zhihu.com/p/259535556
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- LabVIEW生成应用程序(exe)和安装程序(installer)
目录 1、生成应用程序(exe) 2、生成安装程序(installer) 使用LabVIEW编写好的程序最后往往需要将程序拿到目标电脑上去运行,如何将程序从开发电脑上移植到目标电脑上呢?有两种方法: 1、在目标…...
2024/4/18 14:59:07 - HTTP超文本传输协议——简单认识
HTTP协议 概述 在网络上的不同计算机之间必须使用相同的网络协议才能进行通信,HTTP(超文本传输协议)协议就是用于规范客户端浏览器和服务器以什么样的格式进行通信数据交互的,是属于应用层的面向对象的协议,适用于分…...
2024/4/19 1:24:08 - 氢能-储氢发展适度超前,高压储氢优先实现-平安证券(附下载)
导读:氢能产业链整体可以分为氢能制取氢能储运氢能应用三大环节其中储运环节是高效利用氢能的关键是影响氢能向大 规模方向发展的重要环节在氢能全产业链中氢的储运是制约我国氢能和燃料电池产业发展的关键环节因为氢气特殊的 物理化学性能使得它储运难度大成本高安…...
2024/4/26 23:21:43 - Python-玩转数据-数据分析之分析思维
一、说明 当下时代的社会生产发展,人们都开始习惯于用数据来说明某个观点和反映事物的内在规律或享用自动化和人工智能带来的便利。但这些轻松快捷的方便背后,都是相关工作者的专业流程作为源源不断的支撑。 二、大数据思维 自从几年前大数据开始兴起…...
2024/4/25 19:53:52 - python开发积累及其他资源
1. visual studio code comment python: 注释/取消注释: ctrlKC/ctrlKU 2. 字符串为空或空格判断: python基础之字符串为空或空格判断 - blueteer - 博客园 3. 一些有用的关于数据结构和算法的资源: https://github.com/Karti…...
2024/4/13 4:32:40 - 开源与节流促进节能减排,科技助力双碳达标-西部证券(附下载)
导读:作为通信行业两大能耗增长点,5G基站和数据中心节能减耗重要性日益凸显。国内外电信运营商与科技巨头开源节流,实现节能减排。 如需查看完整报告和报告下载或了解更多,公众号:碳中和报告之家...
2024/4/19 8:19:00 - Nginx实现如何解决高并发
什么是动静分离 1、动静分离就是将动态资源(jsp/ftl)与静态资源(img/css/js)分开,从而提高网站响应的速度。 2、传统的架构模式中,静态资源(js、css、img)与动态资源(js…...
2024/4/13 4:32:50 - 蓝桥杯嵌入式_STM32_新建工程文件_详解
注:此学习基于野火学习视频,推荐先看完固件库之前的所有视频,以打下一个良好的基础。详见野火论坛。 (因为这里还是需要一些野火的基础的,我就先按照自己理解的逻辑编写,看不懂的同学推荐补完野火关于寄存…...
2024/4/18 5:26:37 - 标普碳效率指数策略如何助力机构投资者践行ESG投资理念-SP
导读:标普道琼斯指数作为 ESG 指数编制领域的先驱,至今仍保持领导者的地位。进行严谨的公司分析,采用稳健而强大的编制方法,进行最尖端的指数建构,为广泛的 ESG 基准和投资应用提供顶尖指数。 如需查看完整报告和报告下…...
2024/4/13 4:32:50 - C++入门(基础语法)之函数重载
文章目录写在前面1 函数重载的概念2 函数重载原理写在前面 关于C语言的编译与链接不懂的可以看一下下面的文章,先回顾一下以前的知识。 详解C语言的编译与链接 1 函数重载的概念 函数重载:是函数的一种特殊情况,C允许在同一作用域中声明几个功能类似的…...
2024/4/13 4:32:35 - MySQL笔记第四篇之函数
一、常用的函数 1、数据函数 SELECT ABS(-8); /*绝对值*/SELECT CEILING(9.4); /*向上取整*/SELECT FLOOR(9.4); /*向下取整*/SELECT RAND(); /*随机数,返回一个0-1之间的随机数*/SELECT SIGN(0); /*符号函数: 负数返回-1,正数返回1,0返回0*/我并没有进入到某一个数据库就…...
2024/4/8 19:31:32 - [牛客-程序员代码面试指南]最长的可整合子数组的长度
题目描述 先给出可整合数组的定义:如果一个数组在排序之后,每相邻两个数的差的绝对值都为1,或者该数组长度为1,则该数组为可整合数组。例如,[5, 3, 4, 6, 2]排序后为[2, 3, 4, 5, 6],符合每相邻两个数差的…...
2024/4/13 4:32:25 - python小作业简单的学生管理系统
1.需求 2.代码如下 import tkinter.messagebox#定义界面函数 def info_print():print(请选择功能------------)print(1.添加学员)print(2.删除学员)print(3.修改学员)print(4.查询学员)print(5.显示所有学员)print(6.退出系统)print(- * 20)#空列表 info []#添加学员信息函数…...
2024/4/18 14:57:42 - 2022内蒙古最新建筑施工塔式起重机(建筑特种作业)模拟考试题库及答案
百分百题库提供特种工(塔式起重机)考试试题、特种工(塔式起重机)考试预测题、特种工(塔式起重机)考试真题、特种工(塔式起重机)证考试题库等,提供在线做题刷题,在线模拟考…...
2024/4/13 4:32:45 - Redis 命令
前台启动命令 redis-server 复制一份配置文件到etc 中 将daem下的no改成yes 后台启动 redis-server /etc/redis.conf 使用redis-cli 连接redis 输入ping 响应pong 则连接正常 使用Kill -9 进程号 关闭redis 或 redis-cli shutdown 默认16个数据库 0-15号库 使用select 0-…...
2024/4/18 18:36:33 - 北京大学计算机考研机试KY37 小白鼠排队
题目 描述 N只小白鼠(1 < N < 100),每只鼠头上戴着一顶有颜色的帽子。现在称出每只白鼠的重量,要求按照白鼠重量从大到小的顺序输出它们头上帽子的颜色。帽子的颜色用“red”,“blue”等字符串来表示。不同的小白鼠可以戴相同颜色的帽…...
2024/4/25 1:14:16 - 4.2.3拷贝构造函数调用时机
c中拷贝构造函数调用时机通常有三种情况 使用一个已经创建完毕的对象来初始化一个对象 值传递的方式给函数参数传值 以值方式返回局部对象 //4.2.3 拷贝构造函数调用时机 #include<iostream> using namespace std; class Person { public: Person() { …...
2024/4/21 20:49:36 - [iOS开发]UIPickerView学习
今天学习了iOS常见的滚动选择器,一起来看看👀 新建一个选择器 _pickerView [[UIPickerView alloc] initWithFrame:CGRectMake(40, 100, self.view.frame.size.width - 80, 200);]; _pickerView.backgroundColor [UIColor whiteColor]; //记得设置代理…...
2024/4/19 23:44:38 - 数组理解,二分查找,临界条件
描述 有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定…...
2024/4/5 1:58:36 - error during connect: This error may indicate that the docker daemon is not running解决方法
因为我的截图工具截屏快捷键是ctrlq,docker desktop退出的快捷键也是ctrlq,所以当我按了ctrlq之后,docker desktop退出了,然后我在控制台中输入docker命令时 爆出了这行错误 error during connect: This error may indicate tha…...
2024/4/15 6:14:52
最新文章
- 【C语言】/*数据类型和变量*/
目录 前言 一、数据类型的介绍 二、内置数据类型的介绍 2.1 字符型 2.2 整型 2.3 浮点型 2.4 布尔类型 三、数据类型长度的计算 3.1 sizeof 操作符 3.2 数据类型的长度(VS2022) 3.3 sizeof中表达式不计算 四、signed 和 unsigned 五、数据类型的取值范围 六、变…...
2024/5/4 2:10:45 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 前端开发攻略---Vue通过自定义指令实现元素平滑上升的动画效果(可以自定义动画时间、动画效果、动画速度等等)。
1、演示 2、介绍 这个指令不是原生自带的,需要手动去书写,但是这辈子只需要编写这一次就好了,后边可以反复利用。 3、关键API IntersectionObserver IntersectionObserver 是一个用于监测元素是否进入或离开视口(viewport&#x…...
2024/5/3 4:46:37 - Go语言中如何实现继承
完整课程请点击以下链接 Go 语言项目开发实战_Go_实战_项目开发_孔令飞_Commit 规范_最佳实践_企业应用代码-极客时间 Go语言中没有传统意义上的类和继承的概念,但可以通过嵌入类型(embedded types)来实现类似的功能。嵌入类型允许一个结构…...
2024/4/30 4:14:53 - MySQL 底层数据结构 聚簇索引以及二级索引 Explain的使用
数据结构 我们知道MySQL的存储引擎Innodb默认底层是使用B树的变种来存储数据的 下面我们来复习一下B树存储 B树存储 哈希存储的区别 哈希存储,只能使用等值查询 B树与B树存储 我们知道B树实际上就是B树的变种 那么为啥使用B树而不是使用B树呢? 我们知道效率的高低主要取决于…...
2024/5/2 2:42:20 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/1 17:30:59 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/2 16:16:39 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/29 2:29:43 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/3 23:10:03 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/30 9:43:09 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/2 15:04:34 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/29 20:46:55 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/30 22:21:04 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/1 4:32:01 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/27 23:24:42 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/30 9:42:22 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/2 9:07:46 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/30 9:42:49 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57