Direct3D 12 尝鲜(四): 旋转的彩色立方体

(转载请注明出处)

有点时间没更新了,原因是找了一个多星期的bug结果发现是少了一次加法运算。。。。

不过反正没人看也就没影响啦!_(:3」∠)_



这次的目的是做一个旋转的彩色立方体:

这是自己在学D3D11的时候做过的一个例子,现在搬到D3D12上, 这次增加的内容有:

    // 创建常量缓存
    if (SUCCEEDED(hr)) {
        hr = m_pd3dDevice->CreateCommittedResource(
            &CD3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
            D3D12_HEAP_MISC_NONE,
            &CD3D12_RESOURCE_DESC::Buffer(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT),
            D3D12_RESOURCE_USAGE_GENERIC_READ,
            nullptr,
            IID_ID3D12Resource,
            reinterpret_cast<void**>(&m_pCBufferMatrix)
            );

    }
    // 绑定到常量缓存视图
    if (SUCCEEDED(hr)) {
        D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
        cbvDesc.BufferLocation = m_pCBufferMatrix->GetGPUVirtualAddress();
        cbvDesc.SizeInBytes = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
        m_pd3dDevice->CreateConstantBufferView(
            &cbvDesc,
            m_aCpuHandleCSU[CSU_MatrixCBuffer]
            );
    }

这部分代码中, 使用D3D12_HEAP_TYPE_UPLOAD是因为我们每帧都要改写,这样比较方便, 相应的, 效率可能就会损失点.

还有就是之前提到的把所有相同的DESCRIPTOR集中放到一起, 所以写了个简单的框架, 使用m_aCpuHandleXXX数组存放的.

我们在这里存放3个矩阵: 世界、视角、透视转换矩阵

2. 深度缓存, 深度缓存的作用就不用说了, 灵活使用可以获取到不错的效果, 创建DSV绑定到DESCRIPTOR. 这里不使用模板, 仅仅使用深度:

    // 创建深度缓存
    if (SUCCEEDED(hr)) {
        D3D12_RESOURCE_DESC resourceDesc = CD3D12_RESOURCE_DESC::Tex2D(
            DXGI_FORMAT_R32_TYPELESS, m_uBufferWidth, m_uBufferHeight,
            1, 1, 1, 0,
            D3D12_RESOURCE_MISC_ALLOW_DEPTH_STENCIL,
            D3D12_TEXTURE_LAYOUT_UNKNOWN, 0
            );
        D3D12_CLEAR_VALUE dsvClearValue;
        dsvClearValue.Format = DXGI_FORMAT_D32_FLOAT;
        dsvClearValue.DepthStencil.Depth = 1.0f;
        dsvClearValue.DepthStencil.Stencil = 0;
        hr = m_pd3dDevice->CreateCommittedResource(
            &CD3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
            D3D12_HEAP_MISC_NONE,
            &resourceDesc,
            D3D12_RESOURCE_USAGE_DEPTH,
            &dsvClearValue,
            IID_ID3D12Resource,
            reinterpret_cast<void**>(&m_pDepthBuffer)
            );
    }
    // 绑定深度缓存到DSV
    if (SUCCEEDED(hr)) {
        D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
        dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
        dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
        dsvDesc.Texture2D.MipSlice = 0;
        dsvDesc.Flags = D3D12_DSV_NONE;
        /*no return*/m_pd3dDevice->CreateDepthStencilView(
            m_pDepthBuffer, &dsvDesc,
            m_aCpuHandleDSV[DSV_MainDSV]
            );
    }

感觉没什么可以说的, D3D12提供的Helper很方便, 默认值就行,详细的可以查看官方文档.

3. 顶点/索引缓存, 渲染一个立方体所需要的东西, 目前我们需要: 顶点颜色与顶点坐标, 索引就是三角索引了

// 创建带颜色的正方体
auto SceneRenderer::CreateColoredCube(
    ID3D12Resource*& vibuffer,
    D3D12_VERTEX_BUFFER_VIEW& vbuffer_view,
    D3D12_INDEX_BUFFER_VIEW& ibuffer_view) noexcept -> HRESULT {
    HRESULT hr = S_OK;
    ID3D12Resource* pVIBuffer = nullptr;
    // 立方体的8个顶点 与相应颜色
    VertexColor vertices[] = {
            { DirectX::XMFLOAT3(-1.f, -1.f, -1.f), DirectX::XMFLOAT4(0.f, 0.f, 0.f, 1.f) },
            { DirectX::XMFLOAT3(-1.f,  1.f, -1.f), DirectX::XMFLOAT4(1.f, 0.f, 0.f, 1.f) },
            { DirectX::XMFLOAT3(1.f,  1.f, -1.f), DirectX::XMFLOAT4(0.f, 1.f, 0.f, 1.f) },
            { DirectX::XMFLOAT3(1.f, -1.f, -1.f), DirectX::XMFLOAT4(0.f, 0.f, 1.f, 1.f) },
            { DirectX::XMFLOAT3(-1.f, -1.f,  1.f), DirectX::XMFLOAT4(0.f, 1.f, 1.f, 1.f) },
            { DirectX::XMFLOAT3(-1.f,  1.f,  1.f), DirectX::XMFLOAT4(1.f, 1.f, 0.f, 1.f) },
            { DirectX::XMFLOAT3(1.f,  1.f,  1.f), DirectX::XMFLOAT4(1.f, 0.f, 1.f, 1.f) },
            { DirectX::XMFLOAT3(1.f, -1.f,  1.f), DirectX::XMFLOAT4(1.f, 1.f, 1.f, 1.f) }
    };
    // 立方体 6个面 12个三角面 36个顶点
    uint16_t indices[] = {
        0, 1, 2, 0, 2, 3,
        4, 5, 1, 4, 1, 0,
        7, 6, 5, 7, 5, 4,
        3, 2, 6, 3, 6, 7,
        1, 5, 6, 1, 6, 2,
        4, 0, 3, 4, 3, 7
    };

    // 创建顶点缓存-索引缓存共用缓冲区
    if (SUCCEEDED(hr)) {
        hr = m_pd3dDevice->CreateCommittedResource(
            &CD3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
            D3D12_HEAP_MISC_NONE,
            &CD3D12_RESOURCE_DESC::Buffer(sizeof(vertices)+sizeof(indices)),
            D3D12_RESOURCE_USAGE_GENERIC_READ,
            nullptr,
            IID_ID3D12Resource,
            reinterpret_cast<void**>(&pVIBuffer)
            );
    }
    // 映射
    void* buffer = nullptr;
    if (SUCCEEDED(hr)) {
        hr = pVIBuffer->Map(0, nullptr, &buffer);
    }
    // 复制-取消映射-设置
    if (SUCCEEDED(hr)) {
        ::memcpy(buffer, vertices, sizeof(vertices));
        ::memcpy(
            reinterpret_cast<uint8_t*>(buffer)+ sizeof(vertices),
            indices, sizeof(indices)
            );
        pVIBuffer->Unmap(0, nullptr);
        // 设置
        vbuffer_view.BufferLocation = pVIBuffer->GetGPUVirtualAddress();
        vbuffer_view.StrideInBytes = sizeof(VertexColor);
        vbuffer_view.SizeInBytes = sizeof(vertices);
        ibuffer_view.BufferLocation = vbuffer_view.BufferLocation + sizeof(vertices);
        ibuffer_view.Format = DXGI_FORMAT_R16_UINT;
        ibuffer_view.SizeInBytes = sizeof(indices);
        vibuffer = ::SafeAcquire(pVIBuffer);
    }
    ::SafeRelease(pVIBuffer);
    return hr;
}

得益于D3D12/Win10的虚拟GPU地址, 我们可以将顶点缓存缓存与索引缓存一起申请, 提高效率. 对应的输入布局:

    // 输入布局
    D3D12_INPUT_ELEMENT_DESC inputLayout[] = {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_PER_VERTEX_DATA, 0 },
        { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, sizeof(DirectX::XMFLOAT3), D3D12_INPUT_PER_VERTEX_DATA, 0 },
    };

其实颜色也是可以用3个浮点数就行, 这样每个节点就能节约1个浮点了.对应的shader就是:

// C Buffer 0 : 储存转换矩阵
cbuffer MatrixBuffer : register (b0) {
    matrix worldMatrix;
    matrix viewMatrix;
    matrix projectionMatrix;
};

// VS 输入
struct VertexInputType {
    float4 position     : POSITION;
    float4 color        : COLOR;
};

// VS 输出
struct PixelInputType {
    float4 position     : SV_POSITION;
    float4 color        : COLOR;
};

// 处理
PixelInputType ColorVertexShader(VertexInputType input) {
    PixelInputType output;
    // 坐标转换
    output.position = mul(float4(input.position.xyz, 1), worldMatrix);
    output.position = mul(output.position, viewMatrix);
    output.position = mul(output.position, projectionMatrix);
    // 直接输出
    output.color = input.color;

    return output;
}

// 像素着色器处理
float4 ColorPixelShader(PixelInputType input) : SV_TARGET {
    return input.color;
}

请注意, 因为都算是“固定管线”,所以我们在着色器里面使用的一切都要说明:

这里使用了在b0寄存器上cbuffer.

毕竟输入小,管线占用资源就少, 序列化RootSignature时提供的参数D3D12_ROOT_SIGNATURE表明了这个:

        D3D12_ROOT_SIGNATURE rootSigDesc = D3D12_ROOT_SIGNATURE();
        D3D12_ROOT_PARAMETER params[1];
        D3D12_DESCRIPTOR_RANGE descRange[1];
        descRange[0].Init(D3D12_DESCRIPTOR_RANGE_CBV, 1, 0);
        params[0].InitAsDescriptorTable(lengthof(descRange), descRange);
        // 初始化
        rootSigDesc.NumParameters = lengthof(params);
        rootSigDesc.pParameters = params;
        rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;

目前仅需一个DESCRIPTOR表即可,并且只有一个常量缓存视图(CBV), 所以才是descRange[0].Init(D3D12_DESCRIPTOR_RANGE_CBV, 1, 0);

这次清空命令多了个清空深度缓存:

    }
    // 执行清空命令
    if (SUCCEEDED(hr)) {
        this->SetResourceBarrier(m_pCmdClear, m_pTargetBuffer, D3D12_RESOURCE_USAGE_PRESENT, D3D12_RESOURCE_USAGE_RENDER_TARGET);
        m_pCmdClear->RSSetViewports(1, &view);
        float clearColor[4] = { 0.4f, 0.8f, 1.0f, 1.0f};
        m_pCmdClear->ClearRenderTargetView(
            m_aCpuHandleRTV[RTV_MainRTV],
            clearColor, nullptr, 0
            );
        m_pCmdClear->ClearDepthStencilView(
            m_aCpuHandleDSV[DSV_MainDSV], D3D12_CLEAR_DEPTH, 1.0f,
            0, nullptr, 0
            );
        this->SetResourceBarrier(m_pCmdClear, m_pTargetBuffer, D3D12_RESOURCE_USAGE_RENDER_TARGET, D3D12_RESOURCE_USAGE_PRESENT);
        hr = m_pCmdClear->Close();
    }

刻画命令多了: 设置DESCRIPTOR表(对应管线), 与DESCRIPTOR堆(提供资源),以及设置顶点缓存和索引缓存:

    // 执行命令
    if (SUCCEEDED(hr)) {
        ID3D12DescriptorHeap* heaps[] = {
            m_pCSUDescriptors
        };
        D3D12_RECT scissor = {};
        scissor.right = m_uBufferWidth;
        scissor.bottom = m_uBufferHeight;
        //
        this->SetResourceBarrier(m_pCmdDraw, m_pTargetBuffer, D3D12_RESOURCE_USAGE_PRESENT, D3D12_RESOURCE_USAGE_RENDER_TARGET);
        m_pCmdDraw->RSSetViewports(1, &view);
        m_pCmdDraw->RSSetScissorRects(1, &scissor);
        m_pCmdDraw->SetRenderTargets(m_aCpuHandleRTV + RTV_MainRTV, true, 1, m_aCpuHandleDSV + DSV_MainDSV);
        m_pCmdDraw->SetGraphicsRootSignature(m_prsPipeline);
        m_pCmdDraw->SetDescriptorHeaps(heaps, lengthof(heaps));
        m_pCmdDraw->SetGraphicsRootDescriptorTable(0, m_pCSUDescriptors->GetGPUDescriptorHandleForHeapStart());
        m_pCmdDraw->SetPipelineState(m_pPipelineState);
        m_pCmdDraw->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
        m_pCmdDraw->SetVertexBuffers(0, &m_cubeVBV, 1);
        m_pCmdDraw->SetIndexBuffer(&m_cubeIBV);
        m_pCmdDraw->DrawIndexedInstanced(36, 1, 0, 0, 0);
        this->SetResourceBarrier(m_pCmdDraw, m_pTargetBuffer, D3D12_RESOURCE_USAGE_RENDER_TARGET, D3D12_RESOURCE_USAGE_PRESENT);
        hr = m_pCmdDraw->Close();

    }

更新常量缓存直接修改即可, 会自动上传的:



代码下载地址: 点击这里


时间: 2024-10-13 05:30:06

Direct3D 12 尝鲜(四): 旋转的彩色立方体的相关文章

Direct3D 12 尝鲜(五): SDK 更新

(转载请注明出处) 又是一个月, 微软在Build2015中公布了不少关于Win10的新闻, 又在N卡公布的支持DX12显卡中看到了我的垃圾显卡(GT640M LE)居然在支持范围,高高兴兴地直接换物理机安装上Win10, 升级了SDK, VS2015变成了RC版. 不过失望了是显卡支持的仅仅是D3D12 level11.0, 不能用level12.0,不知道会不会更新支持. Win10SDK也更新了, 我们在意的自然是D3D12部分. 对于目前, 改变如下: 1. Helper类/函数 被分离

Direct3D 12 尝鲜: 基本呈现

(转载请注明出处) 请叫我挖坑狂魔_(:3」∠)_ 微软前几天发布了Win10的开发工具,希望使用的童鞋可以加入windows insider计划 进行下载. 下面是我的环境: Windows 10 Technical Preview Build 10041 Visual Studio 2015 CTP 6 Visual Studio Tools for Windows 10 当然,使用的是虚拟机. D3D12文档可以在官方文档里面进行查看,里面有编程向导与API文档. 不过, 这个文档也是初步

Direct3D 12 尝鲜(二): Fence

(转载请注明出处) 正如上节末尾所说, 出现了运行时错误: D3D12 ERROR: ID3D12CommandAllocator::Reset: A command allocator is being reset before previous executions associated with the allocator have completed. [ EXECUTION ERROR #548: COMMAND_ALLOCATOR_SYNC] 就是说要在相关执行完成后才能重置, 在自

Directx11学习笔记【十二】 画一个旋转的彩色立方体

上一次我们学习了如何画一个2D三角形,现在让我们进一步学习如何画一个旋转的彩色立方体吧. 具体流程同画三角形类似,因此不再给出完整代码了,不同的部分会再说明. 由于我们要画彩色的立方体,所以顶点结构体中加入颜色变量 struct Vertex { XMFLOAT3 pos; XMFLOAT4 color; }; 着色器代码 1 cbuffer cbPerObject 2 { 3 float4x4 gWorldViewProj; 4 }; 5 6 struct VertexIn 7 { 8 flo

15.EVE-NG小众镜像,助力尝鲜!

文章列表(关注微信公众号EmulatedLab,及时获取文章以及下载链接) 1.EVE-NG介绍(EVE-NG最好用的模拟器,仿真环境时代来临!) 2.EVE-NG安装过程介绍 3.EVE-NG导入Dynamips和IOL 4.EVE-NG导入QEMU镜像 5.EVE-NG关联SecureCRT,VNC,Wireshark 6.EVE-NG网卡桥接,带您走进更高级的实验 7.EVE-NG硬盘扩容,存储海量镜像 8.EVE-NG定制个人镜像,脚本快速导入 9.EVE-NG容纳H3C.Huawei,

【响应式】foundation栅格布局的“尝鲜”与“填坑”

提到响应式,就不得不提两个响应式框架--bootstrap和foundation.在标题上我已经说明白啦,今天给大家介绍的是foundation框架. 何为"尝鲜"?就是带大伙初步一下foundation的灵活和强大 何为"踩坑"?就是我把我使用的时候踩过的坑给标个记号,这样大伙用的时候就可以"绕道而行"啦! 没错今天我这篇文章讲的就是北方酱左手边的那个看起来温(diao)文(de)尔(yi)雅(bi)的山羊先生:foundation!: 文章主

屌丝就爱尝鲜头——java8总结晒一晒

前两节讨论了那么多,这节就是两个议题,讨论了新增的日期的api,再说一说我的Java8的一些心得体会了. 首先,我们必须要搞清楚Java 8 为什么要增加新的日期的api,这是由于老的日期api非常的繁琐,使用起来非常不方便,Java作者奉行这变者通不变者死的原则,于是增加了这些api.下面,我们总点介绍这几个类--LocalDate类.LocalTime类.LocalDateTime类.DateTimeFormatter类,zoneDate类.一个个来看: Ⅰ.LocalDate类--返回日期

屌丝就爱尝鲜头——java8初体验

Java8已经推出,让我们看看他的魅力.让我们看看他改变较大的部分. 一.java8概述 Java8是由Oracle(甲骨文)公司与2014年3月27日正式推出的.Java8同时推出有3套语言系统,分别是Java SE8.Java SE Emebbled 8.Java ME8. Java SE8较以往的系统增强的功能有: ①增强了对集合式操作语言--lambda表达式的支持,"Lambda 表达式"(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演

Cocos2d-x v3.0正式版尝鲜体验【3】 Label文本标签

Cocos2d-x在新版本中加入了新的Label API,和以往不同的是,2.x的版本是通过三个不同的类来创建不同的文本标签,而现在是模仿着精灵的创建方式,一个类创建不同形式的文本,不过核心内容还是差不多的. 这是新的Label类结构图 在2.x的系列中,有三种文本,分别是TTF,BMFont和Atlas.在3.0中,将TTF拆分成两种,下面就分别看一下这四种文本的创建. 1.Label::createWithTTF 这是需要使用ttf格式字体文件的创建方式 TTFConfig config("