FEATURED · 精选文章

Direct3D图形绘制全流程解析:从管线原理到实战渲染三角形

发布时间 / 2026/9/5 19:35:30
来源 / 创域科博编辑部
栏目 / 资讯中心
Direct3D图形绘制全流程解析:从管线原理到实战渲染三角形 简介本资源是一套基于VC与Direct3D的3D图形绘制入门实践项目面向计算机图形学初学者及Windows平台三维开发爱好者旨在降低Direct3D硬件加速渲染的学习门槛同时融合现代UI交互设计。项目采用MFC框架构建主界面并集成Ribbon菜单系统显著提升触摸屏操作体验与功能组织效率避免传统级联菜单查找繁琐的问题。压缩包共35个文件279KB涵盖8个图像资源bmp/png图标、8个头文件h/FPoint.h等定义核心数据结构与接口、5个C源文件含View、Doc、MainFrm等MFC模块实现、1个Visual Studio解决方案sln及配套工程配置vcxproj、filters、rc等结构完整、模块清晰便于理解Direct3D初始化、设备创建、顶点缓冲绘制、消息循环与Ribbon命令响应的全流程。目前已有86人学习下载适合动手复现基础3D渲染、掌握MFCDirect3D协同开发范式、并参考规范化工程组织方式的开发者。1. 项目概述从像素到世界Direct3D的图形绘制之旅如果你是一名游戏开发者、图形程序员或者对计算机如何渲染出那些令人惊叹的3D世界感到好奇那么“Direct3D图形绘制”这个话题就是你绕不开的核心。这不仅仅是调用几个API那么简单它关乎如何将一堆抽象的数学数据通过GPU的流水线最终变成屏幕上一个个有颜色、有光影、有深度的像素。我从业十几年从固定管线时代一路走到现在的可编程管线踩过的坑、调过的参数不计其数。今天我就以一个老兵的视角带你深入Direct3D图形绘制的腹地不聊空泛的概念只讲从零到一构建一个可绘制物体的完整流程、背后的原理以及那些只有亲手写过代码才能体会到的“坑点”。简单来说Direct3D是微软DirectX API家族中专门负责3D图形渲染的部分。它定义了你的程序CPU端如何与显卡GPU端沟通告诉GPU“嘿这里有一堆三角形用这个纹理在那个光源下按照这个视角给我画出来。”整个过程就是一场精密的、数据驱动的协作。对于初学者可能会被顶点缓冲区、索引缓冲区、着色器、纹理采样这些术语吓到但别担心我会把它们拆解成一个个具体的、可操作的步骤。而对于有经验的开发者我也会分享一些关于性能优化、高级特性如实例化渲染、计算着色器的实战心得。无论你是想入门还是想深化理解这篇文章都将提供一个结构清晰、可直接参考复现的路线图。2. 核心架构与管线流程拆解理解Direct3D图形绘制首先要抛弃“画图”这个二维思维建立起“三维空间数据加工流水线”的概念。这条流水线就是著名的“渲染管线”。在Direct3D中尤其是现代版本如11、12这条管线是可编程的意味着你可以在关键节点注入自己编写的程序着色器实现无限可能的效果。2.1 现代可编程渲染管线全景固定功能管线早已成为历史现代Direct3D以D3D11为典型代表的管线核心是几个可编程着色器阶段。我们可以把整个流程想象成一个汽车装配厂输入装配阶段这是流水线的起点。你的3D模型数据顶点位置、法线、纹理坐标等就像一堆散乱的汽车零件。输入装配阶段的工作就是读取这些零件顶点并按照说明书图元拓扑如三角形列表把它们组装成基本的车架图元。这里的关键数据结构是顶点缓冲区和索引缓冲区。顶点缓冲区存放所有顶点的属性数据索引缓冲区则定义了如何用这些顶点来组装三角形可以极大地减少重复顶点的存储。顶点着色器阶段这是第一个你可以编程的环节。每个顶点都会独立地执行一次你写的顶点着色器程序。它的核心任务通常是坐标变换。模型自带的顶点坐标是在“模型局部空间”里的顶点着色器要将其依次变换到“世界空间”物体在游戏世界中的位置和姿态、“观察空间”以摄像机为原点的空间最后是“齐次裁剪空间”。这个空间下的坐标会被用于后续的光栅化。此外顶点着色器也可以计算并输出一些需要传递给后续阶段的数据如纹理坐标、顶点颜色等。曲面细分阶段这是一个可选但强大的阶段。它允许你在GPU上动态地增加模型的几何细节。比如一个低精度的地面模型在摄像机靠近时通过曲面细分自动生成更多三角形表现出丰富的凹凸细节。这包括外壳着色器、曲面细分器和域着色器三个子阶段属于进阶内容。几何着色器阶段另一个可选的可编程阶段。它以完整的图元如一个三角形、一条线为输入可以输出新的、任意数量的图元。常用于粒子系统生成、几何体动态扩增如把点变成广告牌等。但需谨慎使用因为其性能开销较大。光栅化阶段这是一个固定功能阶段但至关重要。它将经过变换的、处于齐次裁剪空间的三角形转换为屏幕上的像素片段。这个过程决定了哪些像素被三角形覆盖并为每个被覆盖的像素生成一个“片段”。同时它还会对顶点着色器输出的各种属性如纹理坐标、颜色在三角形面上进行插值这样每个像素片段都能获得自己对应的属性值。像素着色器阶段这是第二个核心的可编程阶段。每个像素片段都会执行一次像素着色器。这里是决定像素最终颜色的地方。你会在这里进行纹理采样根据插值得到的纹理坐标从纹理图片中取颜色、光照计算结合法线、光源信息计算漫反射、高光等、以及应用各种材质效果。输出的结果是一个或多个颜色值。输出合并阶段这是流水线的终点。像素着色器输出的颜色会来到这里与当前渲染目标如后台缓冲区中已有的颜色进行合并。这个阶段处理深度测试决定哪个片段更靠近摄像机应该被显示和模板测试以及混合操作如实现半透明效果。最终颜色被写入后台缓冲区。注意理解这个管线流程是理解一切Direct3D渲染的基础。在调试渲染问题时你必须清晰地知道当前问题发生在哪个阶段是顶点数据错了着色器计算错了还是深度测试被意外关闭了2.2 关键对象与资源管理在Direct3D中一切皆“资源”。CPU和GPU通过资源进行通信。管理好这些资源是高效渲染的前提。设备与上下文ID3D11Device代表显卡本身用于创建各种资源。ID3D11DeviceContext是渲染上下文代表当前正在进行的渲染操作用于设置状态、绑定资源、发起绘制调用。你可以把它理解为给GPU下命令的指挥官。缓冲区用于存储数据。顶点缓冲区存储顶点数据数组。索引缓冲区存储顶点索引数组。常量缓冲区这是着色器与CPU端通信的桥梁。用于传递每帧变化的矩阵如世界、观察、投影矩阵、光源参数、材质属性等。常量缓冲区需要精心设计按更新频率分组例如分为“每帧更新”的缓冲区和“每个物体更新”的缓冲区以减少不必要的GPU更新。纹理与资源视图纹理是存储图像数据的资源可用于贴图、存储渲染结果等。但着色器不能直接访问纹理资源必须通过对应的着色器资源视图来读取。同样如果你想用着色器向一个纹理写入数据需要无序访问视图如果用作渲染目标需要渲染目标视图如果用作深度/模板缓冲区需要深度模板视图。这种“资源-视图”的分离设计提供了极大的灵活性。着色器编译后的HLSL代码。需要分别创建顶点着色器、像素着色器等并与输入布局描述顶点数据格式正确绑定。状态对象描述GPU固定功能阶段的行为。混合状态控制颜色混合方式。深度模板状态控制深度测试和模板测试的规则。光栅化状态控制多边形如何被光栅化如填充模式、裁剪模式等。实操心得在D3D11中资源创建开销较大。对于静态几何体如场景中的建筑、岩石其顶点/索引/常量缓冲区应在初始化时创建并上传数据。对于动态物体可以考虑使用动态缓冲区D3D11_USAGE_DYNAMIC并通过Map/Unmap来更新但要注意同步和性能。在D3D12中资源管理和同步的责任完全交给了开发者复杂度更高但控制粒度更细性能潜力更大。3. 从零到一一个三角形的绘制全流程理论说再多不如动手画一个三角形来得实在。下面我将详细拆解用Direct3D 11绘制一个彩色三角形的每一个步骤并解释每一步的“为什么”。3.1 初始化与窗口准备首先你需要一个窗口来展示渲染结果。这通常通过Win32 API或更上层的框架如GLFW、SDL来完成。这里以Win32为例核心是创建一个窗口并获取其HWND。然后你需要初始化Direct3D创建设备与交换链使用D3D11CreateDeviceAndSwapChain函数。交换链管理着用于显示的后台缓冲区队列通常是双缓冲或三缓冲它负责在垂直同步时将渲染完成的后台缓冲区呈现到屏幕。驱动类型通常选择D3D_DRIVER_TYPE_HARDWARE以使用显卡硬件加速。特性等级指定你需要的Direct3D功能级别如D3D_FEATURE_LEVEL_11_0。系统会返回设备实际支持的最高等级。交换链描述你需要填写DXGI_SWAP_CHAIN_DESC结构指定后台缓冲区的格式如DXGI_FORMAT_R8G8B8A8_UNORM、宽度、高度、刷新率、采样数量等。其中BufferCount通常为2双缓冲SwapEffect常用DXGI_SWAP_EFFECT_DISCARD。创建渲染目标视图从交换链获取后台缓冲区纹理然后为其创建渲染目标视图。这个视图将被绑定到输出合并阶段作为像素着色器输出的目的地。ID3D11Texture2D* pBackBuffer nullptr; swapChain-GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)pBackBuffer); device-CreateRenderTargetView(pBackBuffer, nullptr, renderTargetView); pBackBuffer-Release();设置视口视口定义了渲染目标后台缓冲区上用于绘制的矩形区域以及深度值的范围。通常你会将视口设置为整个后台缓冲区的大小。D3D11_VIEWPORT viewport; viewport.TopLeftX 0; viewport.TopLeftY 0; viewport.Width (float)screenWidth; viewport.Height (float)screenHeight; viewport.MinDepth 0.0f; viewport.MaxDepth 1.0f; deviceContext-RSSetViewports(1, viewport);3.2 定义与上传几何数据现在我们来定义三角形的三个顶点。每个顶点我们不仅包含位置Pos还包含颜色Color。定义顶点结构体struct Vertex { XMFLOAT3 Pos; // 位置 (x, y, z) XMFLOAT4 Color; // 颜色 (r, g, b, a) };创建顶点数据数组Vertex vertices[] { { XMFLOAT3(0.0f, 0.5f, 0.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) }, // 顶点0顶部红色 { XMFLOAT3(0.5f, -0.5f, 0.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) }, // 顶点1右下绿色 { XMFLOAT3(-0.5f, -0.5f, 0.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) } // 顶点2左下蓝色 };这里的坐标是归一化设备坐标范围在[-1, 1]之间中心是(0,0)。这简化了我们初次尝试省去了矩阵变换。创建顶点缓冲区首先填充缓冲区描述D3D11_BUFFER_DESC。ByteWidth是数据总字节数Usage通常为D3D11_USAGE_DEFAULT表示GPU读写BindFlags必须包含D3D11_BIND_VERTEX_BUFFER。然后填充子资源数据D3D11_SUBRESOURCE_DATA将pSysMem指向我们的顶点数组。最后调用CreateBuffer。创建输入布局这个对象描述了顶点结构体的格式告诉GPU如何解析顶点缓冲区里的数据。它必须与顶点着色器的输入签名严格匹配。D3D11_INPUT_ELEMENT_DESC layout[] { { POSITION, 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { COLOR, 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; UINT numElements ARRAYSIZE(layout); device-CreateInputLayout(layout, numElements, vsBlob-GetBufferPointer(), vsBlob-GetBufferSize(), vertexLayout);这里的“POSITION”和“COLOR”是语义名必须与着色器代码中的输入变量名对应。AlignedByteOffset是每个元素在顶点结构体中的字节偏移量POSITION从0开始COLOR从12开始因为3个float占12字节。3.3 编写与编译着色器我们将编写一个非常简单的HLSL着色器对。顶点着色器因为我们使用了NDC坐标所以顶点着色器几乎什么也不用做直接传递位置和颜色即可。// SimpleVS.hlsl struct VS_INPUT { float3 Pos : POSITION; float4 Color : COLOR; }; struct VS_OUTPUT { float4 Pos : SV_POSITION; float4 Color : COLOR; }; VS_OUTPUT main(VS_INPUT input) { VS_OUTPUT output; output.Pos float4(input.Pos, 1.0f); // 将float3扩展为齐次坐标float4 output.Color input.Color; return output; }像素着色器同样简单直接输出插值后的颜色。// SimplePS.hlsl struct PS_INPUT { float4 Pos : SV_POSITION; float4 Color : COLOR; }; float4 main(PS_INPUT input) : SV_TARGET { return input.Color; }编译与创建在运行时你需要使用D3DCompileFromFile函数或离线工具如fxc.exe将HLSL代码编译成字节码。然后用字节码创建顶点着色器对象CreateVertexShader和像素着色器对象CreatePixelShader。创建顶点着色器时会同时得到编译后的字节码Blob用于创建之前提到的输入布局。3.4 渲染循环与绘制调用一切准备就绪进入主渲染循环。清屏每一帧开始通常需要清除渲染目标视图背景色和深度模板视图如果使用了。float clearColor[4] { 0.0f, 0.2f, 0.4f, 1.0f }; // RGBA: 深蓝色 deviceContext-ClearRenderTargetView(renderTargetView, clearColor); // 如果使用了深度缓冲区deviceContext-ClearDepthStencilView(...);绑定管线状态告诉GPU这一帧我们要用什么配置来绘制。// 1. 设置渲染目标 deviceContext-OMSetRenderTargets(1, renderTargetView, nullptr); // 2. 设置顶点缓冲区 UINT stride sizeof(Vertex); UINT offset 0; deviceContext-IASetVertexBuffers(0, 1, vertexBuffer, stride, offset); // 3. 设置输入布局 deviceContext-IASetInputLayout(vertexLayout); // 4. 设置图元拓扑告诉GPU我们画的是三角形列表 deviceContext-IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 5. 绑定着色器 deviceContext-VSSetShader(vertexShader, nullptr, 0); deviceContext-PSSetShader(pixelShader, nullptr, 0);发起绘制调用这是最关键的一步命令GPU开始工作。deviceContext-Draw(3, 0); // 绘制3个顶点从第0个顶点开始Draw调用会启动渲染管线处理我们绑定的3个顶点组装成一个三角形经过顶点着色器、光栅化、像素着色器最终输出到渲染目标。呈现绘制完成后后台缓冲区里已经有了我们渲染的三角形。调用交换链的Present方法将其呈现到屏幕。swapChain-Present(1, 0); // 第一个参数是同步间隔1表示等待一次垂直同步如果一切正确你将看到一个由红、绿、蓝顶点组成的彩色渐变三角形显示在窗口中央。这个简单的流程是所有复杂渲染的基石。4. 核心进阶从三角形到三维世界画出一个三角形只是第一步。真正的3D图形绘制涉及坐标变换、纹理贴图、光照模型等。下面我们深入几个核心进阶主题。4.1 矩阵变换与常量缓冲区在真实场景中物体的顶点坐标是在自己的模型空间中的。我们需要通过一系列矩阵变换将其转换到屏幕空间。三大变换矩阵世界矩阵将顶点从模型局部空间变换到世界空间。它包含了物体的平移、旋转、缩放信息。观察矩阵将顶点从世界空间变换到摄像机空间观察空间。它本质上是一个将世界坐标系原点移动到摄像机位置并旋转对齐摄像机方向的逆变换。投影矩阵将顶点从观察空间变换到齐次裁剪空间。这个矩阵定义了视锥体摄像机能看到的空间范围并执行透视除法为后续的光栅化做准备。常用的是透视投影矩阵。在HLSL中应用变换 我们需要在顶点着色器中应用这些矩阵。矩阵通常通过常量缓冲区从CPU传递到GPU。// 在HLSL中定义常量缓冲区 cbuffer TransformCB : register(b0) { matrix world; matrix view; matrix projection; }; VS_OUTPUT main(VS_INPUT input) { VS_OUTPUT output; // 组合变换矩阵 matrix mvp mul(mul(world, view), projection); // 应用变换 output.Pos mul(float4(input.Pos, 1.0f), mvp); output.Color input.Color; return output; }CPU端的矩阵更新 每帧你需要根据物体和摄像机的变化在CPU端重新计算这些矩阵可以使用DirectXMath库然后通过Map/Unmap更新对应的常量缓冲区。// 假设有一个常量缓冲区结构体 struct TransformConstants { XMMATRIX world; XMMATRIX view; XMMATRIX proj; }; // 更新数据 TransformConstants cbData; cbData.world XMMatrixTranspose(worldMatrix); // 注意HLSL默认按列优先DXMath按行优先需要转置 cbData.view XMMatrixTranspose(viewMatrix); cbData.proj XMMatrixTranspose(projMatrix); // 映射并拷贝数据到常量缓冲区...实操心得矩阵乘法顺序至关重要。HLSL中的mul函数当参数是向量和矩阵时默认将向量视为行向量因此变换顺序是向量 * 世界 * 观察 * 投影。而使用float4(pos,1) * (W*V*P)是更常见的写法。另外永远记得转置这是DirectXMath行主序与HLSL默认矩阵列主序之间的差异导致的最常见错误之一。4.2 纹理采样与采样器状态让物体表面呈现图片细节就需要纹理。加载纹理从图片文件如PNG、DDS加载数据创建ID3D11Texture2D资源并为其创建着色器资源视图。纹理坐标顶点数据中需要包含纹理坐标UV这是一个二维坐标通常范围[0,1]告诉GPU这个顶点对应纹理图片上的哪个点。像素着色器采样在像素着色器中使用Texture2D对象和SamplerState采样器状态来获取纹理颜色。Texture2D diffuseMap : register(t0); // 纹理寄存器 t0 SamplerState linearSampler : register(s0); // 采样器寄存器 s0 float4 main(PS_INPUT input) : SV_TARGET { float4 texColor diffuseMap.Sample(linearSampler, input.TexCoord); return texColor * input.Color; // 可以与其他颜色混合 }Sample函数会根据input.TexCoord和linearSampler定义的过滤方式如线性过滤、各向异性过滤和寻址模式如重复、钳制来获取最终颜色。创建采样器状态在CPU端你需要定义并创建一个采样器状态对象描述采样行为。D3D11_SAMPLER_DESC sampDesc {}; sampDesc.Filter D3D11_FILTER_MIN_MAG_MIP_LINEAR; // 线性过滤 sampDesc.AddressU D3D11_TEXTURE_ADDRESS_WRAP; // U方向重复 sampDesc.AddressV D3D11_TEXTURE_ADDRESS_WRAP; // V方向重复 device-CreateSamplerState(sampDesc, samplerState); // 绑定到管线 deviceContext-PSSetSamplers(0, 1, samplerState);4.3 深度测试与混合没有深度测试3D场景将无法正确显示前后关系。没有混合就无法实现半透明效果。深度缓冲区你需要创建一个纹理资源格式为DXGI_FORMAT_D24_UNORM_S8_UINT24位深度8位模板并为其创建深度模板视图和纹理视图如果需要在着色器中读取深度值。深度模板状态创建一个ID3D11DepthStencilState对象定义深度测试的规则如“小于等于时通过”和模板测试规则。在渲染循环开始时将其绑定到输出合并阶段OMSetDepthStencilState并在清屏时清除深度缓冲区。混合状态对于需要半透明的物体如玻璃、火焰特效需要在绘制它们之前创建并绑定混合状态。混合状态定义了源颜色来自像素着色器和目标颜色已在渲染目标中如何混合。常见的混合模式是Alpha混合FinalColor SrcColor * SrcAlpha DestColor * (1 - SrcAlpha)。注意事项渲染顺序对深度测试和混合至关重要。通常的渲染顺序是先绘制所有不透明物体开启深度写入再按从后到前的顺序绘制半透明物体关闭深度写入开启混合。如果顺序错误半透明效果会显示异常。5. 性能优化与常见问题排查当你的场景从几个三角形变成成千上万个模型时性能就成了关键。同时渲染问题也接踵而至。5.1 性能优化核心策略减少绘制调用每次Draw调用都有CPU开销。合并使用相同材质和着色器的物体使用实例化渲染来一次性绘制多个相同网格的物体是减少绘制调用的最有效手段。高效的状态管理频繁切换管线状态如着色器、纹理、采样器、混合状态会造成GPU管线停顿。将使用相同状态的对象组织在一起进行绘制。纹理与资源优化纹理图集将多个小纹理合并到一张大纹理中减少纹理切换。Mipmap为纹理生成多级渐远纹理GPU会根据物体距离屏幕的远近自动选择合适的级别采样提高缓存效率。纹理格式根据需求选择合适的压缩纹理格式如BC1/BC3/DXT可以大幅减少显存占用和带宽。CPU-GPU同步避免在每帧频繁Map/Unmap动态资源这会导致GPU流水线停滞。使用多缓冲如双缓冲或三缓冲的常量缓冲区或使用D3D11_USAGE_DYNAMIC配合合适的更新策略。裁剪与视锥剔除在CPU端或使用计算着色器剔除那些完全在摄像机视锥体之外的物体避免提交无效的绘制调用。5.2 常见渲染问题与调试技巧即使对老手图形调试也是家常便饭。下面是一些常见问题及排查思路问题现象可能原因排查步骤屏幕一片黑/纯色渲染目标未正确绑定或清屏1. 检查OMSetRenderTargets调用。2. 检查ClearRenderTargetView的颜色值。3. 使用图形调试器如Visual Studio Graphics Debugger捕获一帧查看渲染目标状态。三角形不显示或位置奇怪顶点数据/着色器错误1. 检查顶点缓冲区数据是否正确上传。2. 检查输入布局是否与着色器签名匹配。3.检查矩阵变换特别是转置问题。4. 在顶点着色器中输出固定颜色测试管线是否通畅。纹理显示为纯黑或纯白纹理未正确加载或绑定1. 检查纹理文件路径和加载是否成功。2. 检查是否创建了SRV并正确绑定到像素着色器PSSetShaderResources。3. 检查采样器状态是否绑定。4. 检查纹理坐标是否在[0,1]合理范围内。深度测试失效物体穿透深度缓冲区/状态问题1. 确认创建并绑定了深度模板视图。2. 确认清除了深度缓冲区。3. 检查深度模板状态确认深度测试函数DepthFunc正确通常是D3D11_COMPARISON_LESS。4. 检查近/远裁剪平面设置是否合理。半透明物体渲染异常混合状态或渲染顺序问题1. 确认创建并绑定了正确的混合状态OMSetBlendState。2.确认渲染顺序先画不透明再画半透明从后往前。3. 检查混合参数SrcBlend,DestBlend等。性能突然下降资源泄露或状态抖动1. 使用工具检查是否存在资源未释放ID3D11Debug接口。2. 使用性能分析工具如NVIDIA Nsight, RenderDoc查看每帧的绘制调用次数和状态切换次数。图形调试器是你的最佳伙伴Visual Studio自带的图形调试器、或者独立的RenderDoc可以让你“暂停”某一帧查看当时所有的API调用、管线状态、资源内容甚至一步步回放像素着色器的执行。遇到诡异问题时不要盲目猜测抓一帧下来分析效率极高。从绘制一个简单的彩色三角形到构建一个包含变换、纹理、光照的完整3D物体再到管理一个复杂场景的性能Direct3D图形绘制的学习曲线是陡峭但清晰的。关键在于理解数据如何在管线中流动以及CPU如何通过API指挥GPU工作。每一个效果背后都是对缓冲区、着色器、状态对象的精确编排。我个人的体会是图形编程既是科学也是工程需要严谨的数学思维也需要解决实际问题的工程能力。多写代码多调试多使用工具分析每一次解决问题的过程都会让你对这条渲染管线有更深的理解。当你第一次看到自己编写的着色器让模型“活”起来第一次成功优化让帧率大幅提升时那种成就感是无与伦比的。这条路没有捷径但每一步都算数。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻