第十八章 Post-Processing

2023-11-12

第十八章 Post-Processing

Post-processing是指在场景渲染之后,使用一些图形技术对场景进行处理。比如,把整个场景转换为grayscale(灰度)样式或使场景中明亮的区域发光。本章将编写一些post-processing effects,并集成到C++渲染引擎框架中。

Render Targets

到目前为止,所有的示例程序都是直接把场景渲染到back buffer,这是一个2D texture用于在渲染完成之后把图像显示到屏幕上。但是在post-processing应用程序中,首先把场景渲染到一个中间层的texture buffer中,然后把post-processing effect应用到该texture。最后使用一个全屏的四边形(由两个三角形组成,包含整个屏幕区域)渲染最终要显示到屏幕上的图像。
下面的步骤概括了post-processing的处理过程:
1、将一个off-screen render target(离屏渲染目标)绑定到管线的output-merger阶段。
2、在off-scrent render target上绘制场景。
3、恢复back buffer,并作为绑定到output-merger阶段的render target。
4、使用off-scrent render target的texture作为一种post-processing effect的输入buffer,绘制一个全屏的四边形。
为了更容易的执行这些步骤,首先创建一个FullScreenRenderTarget类,该类的声明代码如列表18.1所示。

列表18.1 Declaration of the FullScreenRenderTarget Class

[cpp]  view plain  copy  print ?
  1. #pragma once  
  2.   
  3. #include "Common.h"  
  4.   
  5. namespace Library  
  6. {  
  7.     class Game;  
  8.   
  9.     class FullScreenRenderTarget  
  10.     {  
  11.     public:  
  12.         FullScreenRenderTarget(Game& game);  
  13.         ~FullScreenRenderTarget();  
  14.   
  15.         ID3D11ShaderResourceView* OutputTexture() const;  
  16.         ID3D11RenderTargetView* RenderTargetView() const;  
  17.         ID3D11DepthStencilView* DepthStencilView() const;  
  18.   
  19.         void Begin();  
  20.         void End();  
  21.   
  22.     private:  
  23.         FullScreenRenderTarget();  
  24.         FullScreenRenderTarget(const FullScreenRenderTarget& rhs);  
  25.         FullScreenRenderTarget& operator=(const FullScreenRenderTarget& rhs);  
  26.   
  27.         Game* mGame;  
  28.         ID3D11RenderTargetView* mRenderTargetView;  
  29.         ID3D11DepthStencilView* mDepthStencilView;  
  30.         ID3D11ShaderResourceView* mOutputTexture;  
  31.     };  
  32. }  

FullScreenRenderTarget类中的成员变量看起来非常熟悉,在Game类中已经包含了同样的数据类型ID3D11RenderTargetView和ID3D11DepthStencilView。这些类型的变量是用于把一个render target和depth-stencil buffer绑定到管线的output-merger阶段。与Game类不同的是,在FullScrentRenderTarget类中还包含有一个ID3D11ShaderResourceView类型的成员变量,表示render target底层的2D texture buffer。这种类型的输出texture可以作为post-processing shaders的输入数据。FullScreenRenderTarget::Begin()和FullScreenRenderTarget::End()函数分别用于把render target绑定以output-merger阶段和恢复back buffer。列表18.2列出了FullScrennRenderTarget类的实现代码。

列表18.2 Implementation of the FullScreenRenderTarget Class

[cpp]  view plain  copy  print ?
  1. #include "FullScreenRenderTarget.h"  
  2. #include "Game.h"  
  3. #include "GameException.h"  
  4.   
  5. namespace Library  
  6. {  
  7.     FullScreenRenderTarget::FullScreenRenderTarget(Game& game)  
  8.         : mGame(&game), mRenderTargetView(nullptr), mDepthStencilView(nullptr), mOutputTexture(nullptr)  
  9.     {  
  10.         D3D11_TEXTURE2D_DESC fullScreenTextureDesc;  
  11.         ZeroMemory(&fullScreenTextureDesc, sizeof(fullScreenTextureDesc));  
  12.         fullScreenTextureDesc.Width = game.ScreenWidth();  
  13.         fullScreenTextureDesc.Height = game.ScreenHeight();  
  14.         fullScreenTextureDesc.MipLevels = 1;  
  15.         fullScreenTextureDesc.ArraySize = 1;  
  16.         fullScreenTextureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;  
  17.         fullScreenTextureDesc.SampleDesc.Count = 1;  
  18.         fullScreenTextureDesc.SampleDesc.Quality = 0;  
  19.         fullScreenTextureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;  
  20.         fullScreenTextureDesc.Usage = D3D11_USAGE_DEFAULT;  
  21.   
  22.         HRESULT hr;  
  23.         ID3D11Texture2D* fullScreenTexture = nullptr;  
  24.         if (FAILED(hr = game.Direct3DDevice()->CreateTexture2D(&fullScreenTextureDesc, nullptr, &fullScreenTexture)))  
  25.         {  
  26.             throw GameException("IDXGIDevice::CreateTexture2D() failed.", hr);  
  27.         }  
  28.   
  29.         if (FAILED(hr = game.Direct3DDevice()->CreateShaderResourceView(fullScreenTexture, nullptr, &mOutputTexture)))  
  30.         {  
  31.             throw GameException("IDXGIDevice::CreateShaderResourceView() failed.", hr);  
  32.         }  
  33.   
  34.         if (FAILED(hr = game.Direct3DDevice()->CreateRenderTargetView(fullScreenTexture, nullptr, &mRenderTargetView)))  
  35.         {  
  36.             ReleaseObject(fullScreenTexture);  
  37.             throw GameException("IDXGIDevice::CreateRenderTargetView() failed.", hr);  
  38.         }  
  39.   
  40.         ReleaseObject(fullScreenTexture);  
  41.   
  42.         D3D11_TEXTURE2D_DESC depthStencilDesc;  
  43.         ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));  
  44.         depthStencilDesc.Width = game.ScreenWidth();  
  45.         depthStencilDesc.Height = game.ScreenHeight();  
  46.         depthStencilDesc.MipLevels = 1;  
  47.         depthStencilDesc.ArraySize = 1;  
  48.         depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;  
  49.         depthStencilDesc.SampleDesc.Count = 1;  
  50.         depthStencilDesc.SampleDesc.Quality = 0;  
  51.         depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;  
  52.         depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;              
  53.   
  54.         ID3D11Texture2D* depthStencilBuffer = nullptr;  
  55.         if (FAILED(hr = game.Direct3DDevice()->CreateTexture2D(&depthStencilDesc, nullptr, &depthStencilBuffer)))  
  56.         {  
  57.             throw GameException("IDXGIDevice::CreateTexture2D() failed.", hr);  
  58.         }  
  59.   
  60.         if (FAILED(hr = game.Direct3DDevice()->CreateDepthStencilView(depthStencilBuffer, nullptr, &mDepthStencilView)))  
  61.         {  
  62.             ReleaseObject(depthStencilBuffer);  
  63.             throw GameException("IDXGIDevice::CreateDepthStencilView() failed.", hr);  
  64.         }  
  65.   
  66.         ReleaseObject(depthStencilBuffer);  
  67.     }  
  68.   
  69.     FullScreenRenderTarget::~FullScreenRenderTarget()  
  70.     {  
  71.         ReleaseObject(mOutputTexture);  
  72.         ReleaseObject(mDepthStencilView);  
  73.         ReleaseObject(mRenderTargetView);  
  74.     }  
  75.   
  76.     ID3D11ShaderResourceView* FullScreenRenderTarget::OutputTexture() const  
  77.     {  
  78.         return mOutputTexture;  
  79.     }  
  80.   
  81.     ID3D11RenderTargetView* FullScreenRenderTarget::RenderTargetView() const  
  82.     {  
  83.         return mRenderTargetView;  
  84.     }  
  85.   
  86.     ID3D11DepthStencilView* FullScreenRenderTarget::DepthStencilView() const  
  87.     {  
  88.         return mDepthStencilView;  
  89.     }  
  90.   
  91.     void FullScreenRenderTarget::Begin()  
  92.     {     
  93.         mGame->Direct3DDeviceContext()->OMSetRenderTargets(1, &mRenderTargetView, mDepthStencilView);  
  94.     }  
  95.   
  96.     void FullScreenRenderTarget::End()  
  97.     {  
  98.         mGame->ResetRenderTargets();  
  99.     }  
  100. }  

在FullScreenRenderTarget类的构造函数中,包含了该类的大部分实现代码。在该构造函数中,首先构建一个D3D11_TEXTURE2D_DESC结构体类型的实例,并用于创建render target的底层texture buffer。在Game类的初始化过程中这些步骤并不是显式定义的,因为在构建swap chain时就会隐含的创建back buffer。其中在D3D11_TEXTURE2D_DESC结构体实例化时指定了两个bind flags:D3D11_BIND_RENDER_TARGET和D3D_BIND_SHADER_RESOURCE。这两个flags值表示该texture可以同时作为一个render target和一个shader的输入数据。
创建完ID3D11Texture2D类型的texture之后,就可以使用该texture创建shader resource view和render target view。并对外提供了访问这两个views变量的公有函数接口;并且在这两个变量初始化之后就可以释放对texture的引用了。对于depth-stencil view变量的初始化使用类似的操作步骤。
在FullScrentRenderTarget::Begin()函数中,直接调用ID3D11DeviceContext::OMSetRenderTargets()函数把render target view和depth-stencil view绑定到管线的output-merger阶段。而FullScreenRenderTarget::End()函数中则是调用Game::ResetRenderTargets()函数,该函数同样是调用OMSetRenderTargets()函数重置绑定为Game类的中render target view和detph-stencil view变量。
对于FullScreenRenderTarget类的调用方式如下:
mRenderTarget->Begin();
// 1. Clear mRenderTarget->RenderTargetView()
// 2. Clear mRenderTarget->DepthStencilView()
// 3. Draw Objects

mRenderTarget->End();


这种方法首先把objects渲染到FullScreenRenderTarget实例下的2D texture,并且可以通过调用FullScreenRenderTarget::OutputTexture()函数访问该texture变量。最后调用FullScreenRenderTarget::End()函数,就可以把所有的渲染数据写到back buffer中。

A Full-Screen Quad Component

现在我们可以把场景渲染到一个off-screen texture中,接下来需要把一种effect应用到该texture并在屏幕上显示应用的输出结果。在这样一个系统结构中需要封装渲染部分的代码,否则在程序之间将会出现重复多余的代码,但是又要使渲染代码足够灵活,以及支持任意的post-processing effects。列表18.3列出了FullScreenQuad类的声明代码。

列表18.3 Declaration of the FullScreenQuad Class

[cpp]  view plain  copy  print ?
  1. #pragma once  
  2.   
  3. #include <functional>  
  4. #include "DrawableGameComponent.h"  
  5.   
  6. namespace Library  
  7. {  
  8.     class Effect;  
  9.     class Material;  
  10.     class Pass;  
  11.   
  12.     class FullScreenQuad : public DrawableGameComponent  
  13.     {  
  14.         RTTI_DECLARATIONS(FullScreenQuad, DrawableGameComponent)  
  15.   
  16.     public:  
  17.         FullScreenQuad(Game& game);  
  18.         FullScreenQuad(Game& game, Material& material);  
  19.         ~FullScreenQuad();  
  20.   
  21.         Material* GetMaterial();  
  22.         void SetMaterial(Material& material, const std::string& techniqueName, const std::string& passName);  
  23.         void SetActiveTechnique(const std::string& techniqueName, const std::string& passName);  
  24.         void SetCustomUpdateMaterial(std::function<void()> callback);  
  25.   
  26.         virtual void Initialize() override;  
  27.         virtual void Draw(const GameTime& gameTime) override;  
  28.   
  29.     private:  
  30.         FullScreenQuad();  
  31.         FullScreenQuad(const FullScreenQuad& rhs);  
  32.         FullScreenQuad& operator=(const FullScreenQuad& rhs);  
  33.   
  34.         Material* mMaterial;  
  35.         Pass* mPass;  
  36.         ID3D11InputLayout* mInputLayout;  
  37.   
  38.         ID3D11Buffer* mVertexBuffer;  
  39.         ID3D11Buffer* mIndexBuffer;  
  40.         UINT mIndexCount;  
  41.         std::function<void()> mCustomUpdateMaterial;  
  42.     };  
  43. }  

在FullScreenQuad类中,成员变量mMaterial指向一个用于绘制四边形的material对象,并可以通过调用SetMaterial函数对该变量进行赋值。这样就可以在同一个FullScreenQuad实例对象的生存期内使用不同的materials。成员变量mPass和mInputLayout中存储了Draw()函数中使用的相关数据。另外两个非常熟悉的变量vertex和index buffers存储了该四边形对象的vertices和indices。在FullScreenQuad类中使用了一种新的数据类型std::function<T>,如果你之前没有见过的话,这是一种通用的函数封装语法,用于存储并调用函数,bind表达式,lambda表达式(回调以及关闭)。在这里是为了支持FullScreenQuad的调用者更新material shader中的变量。之所以这样做是因为在FullScreenQuad类中并不知道用于渲染四边形的是哪种material(因此也就无法知道material使用的shader输入变量)。FullScreenQuad类要完成的全部操作就是渲染一个四边形;而更新material变量的操作由该类对象的调用者完成。
列表18.4中列出了FullScreenQuad类的实现代码。

列表18.4 Implementation of the FullScreenQuad Class

[cpp]  view plain  copy  print ?
  1. #include "FullScreenQuad.h"  
  2. #include "Game.h"  
  3. #include "GameException.h"  
  4. #include "Material.h"  
  5. #include "VertexDeclarations.h"  
  6.   
  7. namespace Library  
  8. {  
  9.     RTTI_DEFINITIONS(FullScreenQuad)  
  10.   
  11.         FullScreenQuad::FullScreenQuad(Game& game)  
  12.         : DrawableGameComponent(game),  
  13.         mMaterial(nullptr), mPass(nullptr), mInputLayout(nullptr),  
  14.         mVertexBuffer(nullptr), mIndexBuffer(nullptr), mIndexCount(0), mCustomUpdateMaterial(nullptr)  
  15.     {  
  16.     }  
  17.   
  18.     FullScreenQuad::FullScreenQuad(Game& game, Material& material)  
  19.         : DrawableGameComponent(game),  
  20.         mMaterial(&material), mPass(nullptr), mInputLayout(nullptr),  
  21.         mVertexBuffer(nullptr), mIndexBuffer(nullptr), mIndexCount(0), mCustomUpdateMaterial(nullptr)  
  22.     {  
  23.     }  
  24.   
  25.     FullScreenQuad::~FullScreenQuad()  
  26.     {  
  27.         ReleaseObject(mIndexBuffer);  
  28.         ReleaseObject(mVertexBuffer);  
  29.     }  
  30.   
  31.     Material* FullScreenQuad::GetMaterial()  
  32.     {  
  33.         return mMaterial;  
  34.     }  
  35.   
  36.     void FullScreenQuad::SetMaterial(Material& material, const std::string& techniqueName, const std::string& passName)  
  37.     {  
  38.         mMaterial = &material;  
  39.         SetActiveTechnique(techniqueName, passName);  
  40.     }  
  41.   
  42.     void FullScreenQuad::SetActiveTechnique(const std::string& techniqueName, const std::string& passName)  
  43.     {  
  44.         Technique* technique = mMaterial->GetEffect()->TechniquesByName().at(techniqueName);  
  45.         assert(technique != nullptr);  
  46.   
  47.         mPass = technique->PassesByName().at(passName);  
  48.         assert(mPass != nullptr);  
  49.         mInputLayout = mMaterial->InputLayouts().at(mPass);  
  50.     }  
  51.   
  52.     void FullScreenQuad::SetCustomUpdateMaterial(std::function<void()> callback)  
  53.     {  
  54.         mCustomUpdateMaterial = callback;  
  55.     }  
  56.   
  57.     void FullScreenQuad::Initialize()  
  58.     {  
  59.         VertexPositionTexture vertices[] =  
  60.         {  
  61.             VertexPositionTexture(XMFLOAT4(-1.0f, -1.0f, 0.0f, 1.0f), XMFLOAT2(0.0f, 1.0f)),  
  62.             VertexPositionTexture(XMFLOAT4(-1.0f, 1.0f, 0.0f, 1.0f), XMFLOAT2(0.0f, 0.0f)),  
  63.             VertexPositionTexture(XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f), XMFLOAT2(1.0f, 0.0f)),  
  64.             VertexPositionTexture(XMFLOAT4(1.0f, -1.0f, 0.0f, 1.0f), XMFLOAT2(1.0f, 1.0f)),  
  65.         };  
  66.   
  67.         D3D11_BUFFER_DESC vertexBufferDesc;  
  68.         ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));  
  69.         vertexBufferDesc.ByteWidth = sizeof(VertexPositionTexture)* ARRAYSIZE(vertices);  
  70.         vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;  
  71.         vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;  
  72.   
  73.         D3D11_SUBRESOURCE_DATA vertexSubResourceData;  
  74.         ZeroMemory(&vertexSubResourceData, sizeof(vertexSubResourceData));  
  75.         vertexSubResourceData.pSysMem = vertices;  
  76.         if (FAILED(mGame->Direct3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexSubResourceData, &mVertexBuffer)))  
  77.         {  
  78.             throw GameException("ID3D11Device::CreateBuffer() failed.");  
  79.         }  
  80.   
  81.         UINT indices[] =  
  82.         {  
  83.             0, 1, 2,  
  84.             0, 2, 3  
  85.         };  
  86.   
  87.         mIndexCount = ARRAYSIZE(indices);  
  88.   
  89.         D3D11_BUFFER_DESC indexBufferDesc;  
  90.         ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));  
  91.         indexBufferDesc.ByteWidth = sizeof(UINT)* mIndexCount;  
  92.         indexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;  
  93.         indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;  
  94.   
  95.         D3D11_SUBRESOURCE_DATA indexSubResourceData;  
  96.         ZeroMemory(&indexSubResourceData, sizeof(indexSubResourceData));  
  97.         indexSubResourceData.pSysMem = indices;  
  98.         if (FAILED(mGame->Direct3DDevice()->CreateBuffer(&indexBufferDesc, &indexSubResourceData, &mIndexBuffer)))  
  99.         {  
  100.             throw GameException("ID3D11Device::CreateBuffer() failed.");  
  101.         }  
  102.     }  
  103.   
  104.     void FullScreenQuad::Draw(const GameTime& gameTime)  
  105.     {  
  106.         assert(mPass != nullptr);  
  107.         assert(mInputLayout != nullptr);  
  108.   
  109.         ID3D11DeviceContext* direct3DDeviceContext = mGame->Direct3DDeviceContext();  
  110.         direct3DDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);  
  111.         direct3DDeviceContext->IASetInputLayout(mInputLayout);  
  112.   
  113.         UINT stride = sizeof(VertexPositionTexture);  
  114.         UINT offset = 0;  
  115.         direct3DDeviceContext->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &offset);  
  116.         direct3DDeviceContext->IASetIndexBuffer(mIndexBuffer, DXGI_FORMAT_R32_UINT, 0);  
  117.   
  118.         if (mCustomUpdateMaterial != nullptr)  
  119.         {  
  120.             mCustomUpdateMaterial();  
  121.         }  
  122.   
  123.         mPass->Apply(0, direct3DDeviceContext);  
  124.   
  125.         direct3DDeviceContext->DrawIndexed(mIndexCount, 0, 0);  
  126.     }  
  127. }  

首先分析FullScreenQuad::Initialize()函数,该函数的实现与之前示例中的代码基本相同,主要不同的地方是4个vertices所处的空间位置。在screen space中,(-1, -1)表示屏幕的左上角,(1, 1)表示右下角。因为vertices的坐标位置已经是处于screen space中,所以在vertext shader中不需要对这些坐标执行变换。
接下来,分析FullScreen::Draw()函数。除了执行std::function类型的mCustomUpdateMaterial()语句之外,在Draw()函数没有特别需要说明的地方。其中std::function<T>类是一个函数对象(或函数),并提供了公有的operator()函数(重载()运算符)。使用这种方式,看起来就像是调用了一个命名为mCustomUpdateMaterial的函数;实际上,只是调用了std::function<T>::operation()运算符重载函数,真正的目的是用于回调函数或lambda表达式。
最后,需要注意的是四边形的vertices由一个position和texture coordinates表示。这种表示方式限制了在FullScreenQuad类中能够使用的material种类,但是该依然具有多种应用。只需要对该类做一点点扩展,就可以根据具体的material动态的创建vertex buffer。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第十八章 Post-Processing 的相关文章

  • win10下载编译webrtc源码

    win10系统下载编译webrtc源码 一 下载安装VS2017 目前最新版本的webrtc已经可以用Vs2019 但是因为我们要使用的webrtc版本是以前的版本 旧版webrtc源码中vs toolchain py中指定了vs2017
  • AI日报|哈佛“AI教授”即将上线;首个生成式AI技能专业证书来了;电话推销员很烦?AI帮你“制裁”他

    今日值得关注的人工智能新动态 将GPT 4用在课程设计中 哈佛大学 AI教授 即将上线 微软推出首个生成式AI技能专业证书 纽约州议会 伤害或羞辱他人的deepfake是非法的 阿诺德 施瓦辛格 终结者 中的AI已成现实 AI诊断 老年痴呆
  • 函数粘合云服务提供端到端解决方案

    作者 西流 阿里云技术专家 导读 阿里云Serverless 产品函数计算可以作为粘合剂 串联其他云服务提供端到端解决方案 从而简化编程模型 快速实现最上层的业务目标 传统单体应用的拆解 首先我们来看下单体应用里面常见的两个编程模型 如上图
  • 【华为OD统一考试B卷

    华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一修改为OD统一考试 A卷 和OD统一考试 B卷 你收到的链接上面会标注A卷还是B卷 请注意 根据反馈 目前大部分收到的都是
  • Hive SQL 2023必考常用窗口函数及面试题

    一 窗口函数概述 窗口函数也称为OLAP函数 OLAP 是OnLine Analytical Processing 的简称 意思是对数据库数据进行实时分析处理 例如 市场分析 创建财务报表 创建计划等日常性商务工作 窗口函数就是为了实现OL
  • 使用TensorFlow、Keras和深度学习实现像素无序超分辨率

    使用TensorFlow Keras和深度学习实现像素无序超分辨率 pixel shuffle Super Resolution 像素无序 洗牌超分辨率 Deep Learning Super Sampling DLSS 深度学习超级采样
  • flask_sqlalchemy中的db.session.query()和model.query()的区别

    先申明一下 我喜欢从问题入手 问题描述 使用db session commit 提交数据后 使用model query 查不到新增加的数据 问题原因分析 db session commit 是提交了数据到数据库 但是没有刷新模型映射中的数据
  • 使用Fabric8 kubernetes-client java client 操作kuberntes 自定义资源CR

    kubernetes client fabric8 to interact with kubernetes custom resources kubernetes中的一切东西都叫做 resource k8s 默认的提供了很多 resourc
  • 【Python】初识Python

    目录 执行Python的文件有三种方式 注释的细节 算术运算符 变量 输入与输出函数 input函数 print函数 强制类型转换函数 Python程序的特点 Python源程序本质上是一个特殊格式的文本文件 只不过它的后缀扩展名是 py
  • python将秒数转化为时间格式

    1 转化成时间格式 seconds 35400 m s divmod seconds 60 h m divmod m 60 print d 02d 02d h m s 结果 9 50 00 2 转化成日期时间格式 import time t
  • 服务service设置

    2017 03 10 一点简单的讲解 http cwtea blog 51cto com 4500217 842002 service命令只有很简单的几个参数 start restart reload status stop 不能利用这个命
  • 自学Python能学会吗?

    这是一个非常好的问题 作为一名IT从业者 同时也是一名教育工作者 我来回答一下 首先 随着当前Python语言的应用越来越普遍 很多职场人和大学生都希望能够通过掌握Python语言来提升职场价值和岗位竞争力 由于Python语言本身比较简单
  • FreeRTOS-信号量详解

    作者简介 嵌入式入坑者 与大家一起加油 希望文章能够帮助各位 个人主页 rivencode的个人主页 系列专栏 玩转FreeRTOS 保持学习 保持热爱 认真分享 一起进步 目录 前言 一 信号量的简介 二 FreeRTOS信号量 1 二值
  • 牛客题:Java静态块、构造块执行顺序

    public class Test public static Test t1 new Test 静态变量 构造块 System out println AAA 静态块 static System out println BBB publi
  • 【C++】模拟实现二叉搜索树(附源码、测试用例)

    二叉搜索树 一 前言 二 模拟实现 1 构建树的单个节点 2 二叉搜索树的概念 3 构造函数与析构函数 4 赋值与拷贝构造 5 实现插入 6 实现删除 7 实现查找 8 实现遍历 三 源码及部分测试用例 一 前言 二叉搜索树 和普通的二叉树
  • 立创梁山派学习笔记——GPIO输入检测

    按键检测 前言 按键的硬件电路 BOOT选择 复位按键 唤醒按键 GPIO输入框图 软件配置 寄存器简介 1 端口控制寄存器 GPIOx CTL x A I 2 端口上拉 下拉寄存器 GPIOx PUD x A I 3 端口输入状态寄存器
  • 上传代码到gitee:常用命令详解

    目录 一 创建仓库 二 首次上传 三 添加代码后在上传 四 创建分支 创建dev分支 五 合并分支 六 删除分支 看个人需求 一 创建仓库 下面是创建好的仓库 无任何代码上传的状态 二 首次上传 第一步 git config global
  • 2022-3-26 Leetcode 09.字符串轮转

    class Solution public bool isFlipedString string s1 string s2 if s1 size s2 size return false string s s2 s2 return s fi

随机推荐

  • Bridging ConvNeXt and U-Net for medical image segmentation

    最近在收集论文时发现一篇比较有趣的论文 当提到ConvNeXt时 大家应该都知道 比较这个网络跟Transformer 一较高低的网络 在前段时间transformer 很多的时候 涌现了许多将transformer和U Net 相结合的网
  • 轻量应用服务器性能如何?CPU带宽流量系统盘测评

    轻量应用服务器性能如何 腾讯云轻量应用服务器是一种轻量级搭建小型网站和应用的服务器 相对于其他更高性能配置的服务器CVM 性价比更高 虽然其性能不如高性能云服务器CVM 但对于小型网站和应用来说 能够提供基本的计算和存储资源 可以满足基础的
  • STM32之模拟IIC总线通信(C++)

    目录 前言 主要内容 头文件 辅助函数 相关信号函数 起始信号 停止信号 接收应答信号 发送应答信号 发送非应答信号 发送一个字节数据 接收一个字节数据 应用 前言 上一篇也讲解了STM32的模拟IIC总线通信 其所使用的语言为C语言 但也
  • 人脸论文集选

    人脸论文集选 一 Face Detection 级联网络用于人脸检测 A Convolutional Neural Network Cascade for Face Detection CVPR2015 code https github
  • org.hibernate.id.IdentifierGenerationException

    问题 org hibernate id IdentifierGenerationException ids for this class must be manually assigned before calling save 原因 在添
  • Linux 上安装 Go 环境

    如果你向自己下载并编译 Go 的源代码的话 你可以根据这个页面找到安装指南和下载地址 Download the Go distribution 接下来也会带你一步步地完成安装过程 设置 Go 环境变量 我们在 Linux 系统下一般通过文件
  • 来点动力吧,存够300W退休

    这样写也可以 11年后退休 加油吧
  • pytorch学习总结(一)(SGD随机梯度下降、学习率调整策略、train模式)

    看了几个月的理论 总算是开始实践了 学习了几个月 这门学问中数学的应用还挺有意思的 比现在的工作有意思多了 1 torch optim SGD trainer torch optim SGD net parameters lr lr mom
  • linux怎么用代码做扣扣,如何在Linux上安装程序员喜爱的文本编辑器NotepadQQ

    原标题 如何在Linux上安装程序员喜爱的文本编辑器NotepadQQ 来自 Linux迷 链接 https www linuxmi com pop os 20 04 ubuntu html NotepadQQ是一个令人兴奋的应用程序 它试
  • 王垠的40行代码,究竟diao在哪里

    王垠是谁 不用我说了吧 别傻谈 亮码瞧 A simple CPS transformer which does proper tail call and does not duplicate contexts for if expressi
  • element-ui el-table 如何实现合并单元格

    el table的组件的可以合并单元格 先定义参数span method 方法objectSpanMethod 在方法内控制当前单元格渲染成几个单元格或者删除掉当前单元格 比如 代码中定义 span method objectSpanMet
  • Frameset布局

    原文地址 http captaincook iteye com blog 365634
  • angularjs 1.6.x 教程学习心得

    依赖注入 依赖注入是angularJs的核心 应用启动时 angular会创建一个injector 它会寻找并注入所有应用需要的服务 必须先被正确的定义 延迟实例化 lazily instantiate providers Provider
  • vsftpd主动模式和被动模式

    vsftpd主动模式和被动模式 主动模式 PORT 所谓主动模式 指的是FTP服务器主动去连接客户端的数据端口来传输数据 其过程具体来说就是 客户端从一个任意的非特权端口N N gt 1024 连接到FTP服务器的命令端口 即tcp 21端
  • 看看UE4源码: Pawn中默认InputComponent是控制器还是Pawn的

    Pawn中的InputComponent是谁的 结论 默认情况下 如果Pawn首次被PlayerController控制 则会在Pawn中创建一个InputComponent 写在Pawn中SetupPlayerInputComponent
  • 数据结构编程视频

    来源 我是码农 转载请保留出处和链接 本文链接 http www 54manong com cate 3 数据结构与算法是计算机专业一门相当重要的专业必修课 同时数据结构与算法也是电气电子类等一些需要涉及到编程的专业学生一门很重要的基础课程
  • WVP+ZLMediaKit+MediaServerUI实现摄像头GB28181推流播放录制

    本文主要介绍使用 WVP ZLMediaKit MediaServerUI 实现通过 GB28181 进行海康 大华 宇视等品牌的 IPC NVR DVR 接入 完成摄像头监控播放 控制 录制 准备工作 服务运行环境 Linux OS X
  • 分布式缓存原理----Hash环/一致性Hash原理/Hash槽

    Memcached 为分布式客户端做分发 hash环 TWY Redis 为分布式客户端做分发 hash环 Redis Cluster 点对点 2Khash槽 当前 Memcached Redis这类分布式kv缓存已经非常普遍 从本篇开始
  • Java jackson配置类,Java jackson工具类,SpringBoot Jackson类配置

    Java jackson配置类 Java jackson工具类 SpringBoot Jackson类配置 Copyright 蕃薯耀 2021 04 27 https blog csdn net w995223851 一 SpringBo
  • 第十八章 Post-Processing

    第十八章 Post Processing Post processing是指在场景渲染之后 使用一些图形技术对场景进行处理 比如 把整个场景转换为grayscale 灰度 样式或使场景中明亮的区域发光 本章将编写一些post process