DirectX3D 虚拟现实项目 三维物体的光照及着色(五个不同着色效果的旋转茶壶)

文章目录

    • 任务要求
    • 原始代码
      • CPP文件代码
      • 着色器文件代码
    • 效果展示

任务要求

本篇文章是中国农业大学虚拟现实课程的一次作业内容,需要对五个茶壶模型使用不同的光照进行着色和渲染,然后旋转展示。

本人的代码也是在其他人的代码的基础上修改来的,主要用于服务下一届,没有商业用途,侵删。

原始代码

代码包括CPP文件代码和FX(着色器文件)代码两部分

CPP文件代码

//导入用于创建基于DirectX3D的桌面应用程序的相关库
#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#include "resource.h"
//导入其他的库文件
#include <cimport.h>
#include <scene.h>
#include <stdio.h>
#include <postprocess.h>
#include <vector>//定义一个“简单顶点”结构体,包含位置和法线两个向量
struct SimpleVertex
{XMFLOAT3 Pos;     //用于记录顶点位置的三维向量XMFLOAT3 Normal;  //用于记录顶点法线的三维向量(用于计算光照和渲染)
};//定义一个常量缓冲器结构体,用于传递常量数据给着色器
struct ConstantBuffer
{XMMATRIX mWorld;          //定义世界矩阵XMMATRIX mView;           //定义视图矩阵XMMATRIX mProjection;     //定义投影矩阵XMFLOAT4 vLightDir;       //定义光源方向XMFLOAT4 vLightColor;     //定义光源颜色XMFLOAT4 vOutputColor;    //定义环境光的颜色XMFLOAT4 objectColor;     //定义光谱反射率(物体自身的颜色)XMFLOAT4 hightLightColor; //定义光谱反射率(高光颜色)XMFLOAT4 eye;             //定义观察位置
};//全局变量定义部分(初始化部分就是分别对这里的每一个变量进行初始化)
HINSTANCE               g_hInst = NULL;                           //程序实例句柄
HWND                    g_hWnd = NULL;                            //创建的窗口
D3D_DRIVER_TYPE         g_driverType = D3D_DRIVER_TYPE_NULL;      //驱动器类型
D3D_FEATURE_LEVEL       g_featureLevel = D3D_FEATURE_LEVEL_11_0;  //DirectX3D的特性级别
ID3D11Device*           g_pd3dDevice = NULL;                      //DirectX3D设备类型
ID3D11DeviceContext*    g_pImmediateContext = NULL;               //设备的上下文
IDXGISwapChain*         g_pSwapChain = NULL;                      //交换链
ID3D11RenderTargetView* g_pRenderTargetView = NULL;               //渲染目标视图ID3D11Texture2D* g_pDepthStencil = NULL;                          //深度模板纹理
ID3D11DepthStencilView* g_pDepthStencilView = NULL;               //深度模板视图ID3D11VertexShader* g_pVertexShader = NULL;                       //顶点着色器
ID3D11PixelShader* g_pPixelShader = NULL;                         //像素着色器
ID3D11PixelShader* g_pPixelShaderSolid = NULL;                    //另一个像素着色器
ID3D11PixelShader** g_pPixelSh = new ID3D11PixelShader * [5];     //本次作业中指向五种像素着色器指针的指针ID3D11InputLayout* g_pVertexLayout = NULL;                       //顶点布局方式
ID3D11Buffer* g_pVertexBuffer = NULL;                            //顶点缓冲区
ID3D11Buffer* g_pIndexBuffer = NULL;                             //索引缓冲区
ID3D11Buffer* g_pConstantBuffer = NULL;                          //常量缓冲区XMMATRIX                g_World;                                 //世界矩阵
XMMATRIX                g_View;                                  //视角矩阵
XMMATRIX                g_Projection;                            //投影矩阵ID3D11ShaderResourceView* g_pTextureRV = NULL;
ID3D11SamplerState* g_pSamplerLinear = NULL;//自定义的全局变量
unsigned int numVerticeTotal = 0;  //记录导入的模型的顶点总数
unsigned int faceNum = 0;          //记录导入的模型的面的总数//函数的前向引用声明
HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow);    //用于初始化窗口的函数
HRESULT InitDevice(void);                                 //用于初始化设备的函数
void CleanupDevice(void);                                 //用于清空设备资源的函数
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);  //窗口消息处理函数
void Render(void);                                        //用于进行渲染的函数//Windows图形应用程序的入口点,相当于命令行程序的main函数
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{//告诉编译器在编译过程中忽视函数中传入的两个参数,不要产生警告(这两个参数通常都不被使用)UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);//尝试初始化一个窗口(传入的参数是程序实例句柄和窗口的显示状态,如果初始化失败则函数退出if (FAILED(InitWindow(hInstance, nCmdShow)))return 0;//尝试初始化应用程序的DirectX3D图形设备,如果初始化失败则清理设备资源并函数退出if (FAILED(InitDevice())){//清理和释放图形设备的资源CleanupDevice();  return 0;}//主消息循环部分MSG msg = { 0 };//只有收到退出消息之后程序才会退出while (WM_QUIT != msg.message){//检查消息队列中是否有消息存在,如果有消息则处理这些消息if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}//如果没有消息,则进行场景渲染else{Render();}}//清理和释放图形设备的资源CleanupDevice();//返回应用程序的退出状态码return (int)msg.wParam;
}//用于初始化一个窗口的函数
HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow)
{//注册一个对各项属性进行了设置的窗口类WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);                                 //【通常的设置】wcex.style = CS_HREDRAW | CS_VREDRAW;                             //窗口类的样式设置(窗口尺寸发生改变时进行重新绘制)wcex.lpfnWndProc = WndProc;                                       //设置处理窗口类消息的函数(WndProc)wcex.cbClsExtra = 0;                                              //【通常的设置】wcex.cbWndExtra = 0;                                              //【通常的设置】wcex.hInstance = hInstance;                                       //设置窗口类的应用程序句柄wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDC_TUTORIAL1);         //设置窗口类的图标wcex.hCursor = LoadCursor(NULL, IDC_ARROW);                       //【通常的设置】wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);                  //【通常的设置】wcex.lpszMenuName = NULL;                                         //设置窗口的wcex.lpszClassName = L"TutorialWindowClass";                      //设置窗口类的名称wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDC_TUTORIAL1);  //设置窗口类的图标//根据上述的设置注册一个窗口类,如果失败则返回错误信息if (!RegisterClassEx(&wcex))return E_FAIL;//根据注册的窗口类创建一个窗口g_hInst = hInstance;//设置窗口的初始位置和大小RECT rc = { 0, 0, 1500, 1000 };//根据给定的窗口位置和大小调整窗口(另外两个参数是窗口的样式和是否有菜单栏)AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);//创建一个窗口(可以设置窗口的标题)g_hWnd = CreateWindow(L"TutorialWindowClass", L"Lighting and coloring of three-dimensional objects  计算机201 旷欣然", WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance,NULL);//如果创建窗体失败,则返回失败信息if (!g_hWnd)return E_FAIL;//根据指定的显示方式显示窗口ShowWindow(g_hWnd, nCmdShow);return S_OK;
}//编译着色器代码的辅助函数
HRESULT CompileShaderFromFile(WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
{HRESULT hr = S_OK;DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.// Setting this flag improves the shader debugging experience, but still allows // the shaders to be optimized and to run exactly the way they will run in // the release configuration of this program.dwShaderFlags |= D3DCOMPILE_DEBUG;
#endifID3DBlob* pErrorBlob;hr = D3DX11CompileFromFile(szFileName, NULL, NULL, szEntryPoint, szShaderModel,dwShaderFlags, 0, NULL, ppBlobOut, &pErrorBlob, NULL);if (FAILED(hr)){if (pErrorBlob != NULL)OutputDebugStringA((char*)pErrorBlob->GetBufferPointer());if (pErrorBlob) pErrorBlob->Release();return hr;}if (pErrorBlob) pErrorBlob->Release();return S_OK;
}//自定义的用于导入指定的模型文件的函数
const struct aiScene* load_obj(char* path)
{//借助Assimp库中的函数以高质量导入指定路径的模型文件const aiScene* scene = aiImportFile(path, aiProcessPreset_TargetRealtime_MaxQuality);//遍历模型的每一个网格,累加每个网格的顶点总数和面数并通过全局变量存储for (unsigned int i = 0; i < scene->mNumMeshes; i++){numVerticeTotal += scene->mMeshes[i]->mNumVertices;faceNum += scene->mMeshes[i]->mNumFaces;}//将导入模型文件的结果返回return scene;
}//用于初始化DirectX3D设备并创建交换链的函数
HRESULT InitDevice(void)
{//借助于Assimp模块和自定义的函数导入茶壶文件const struct aiScene* teapot = NULL;teapot = load_obj("teapot2.obj");HRESULT hr = S_OK;//获取客户窗口区的尺寸并记录宽度和高度RECT rc;GetClientRect(g_hWnd, &rc);UINT width = rc.right - rc.left;UINT height = rc.bottom - rc.top;//条件预编译指令:程序在调试模式下则在创建设备时创建调试功能,从而从调试器中获取调用和调试信息UINT createDeviceFlags = 0;
#ifdef _DEBUGcreateDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif//通过数组存储不同的DirectX3D设备的类型并记录数组大小D3D_DRIVER_TYPE driverTypes[] ={D3D_DRIVER_TYPE_HARDWARE,   //显卡的硬件驱动器(通常具有最好的性能)D3D_DRIVER_TYPE_WARP,       //软件驱动器(性能较低)D3D_DRIVER_TYPE_REFERENCE,  //参考驱动器(用于调试和开发的过程)};UINT numDriverTypes = ARRAYSIZE(driverTypes);//通过数组存储DirectX3D不同的特性级别并记录数组的大小D3D_FEATURE_LEVEL featureLevels[] ={D3D_FEATURE_LEVEL_11_0,     //DirectX3D 11.0特性级别,通常具有最好的性能D3D_FEATURE_LEVEL_10_1,     //DirectX3D 10.1特性级别,一些功能受到限制D3D_FEATURE_LEVEL_10_0,     //DirectX3D 10.0特性级别,更低的硬件要求和功能};UINT numFeatureLevels = ARRAYSIZE(featureLevels);//设置一个交换链的属性和配置DXGI_SWAP_CHAIN_DESC sd;ZeroMemory(&sd, sizeof(sd));                       //初始清空操作,确保变量都被正确初始化sd.BufferCount = 1;                                //设置不使用双缓冲区(一般都会使用前缓冲区和后缓冲区)sd.BufferDesc.Width = width;                       //设置交换链的宽度sd.BufferDesc.Height = height;                     //设置交换链的高度sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; //设置交换链缓冲区的格式sd.BufferDesc.RefreshRate.Numerator = 60;          //设置刷新率的分母sd.BufferDesc.RefreshRate.Denominator = 1;         //设置刷新率的分子(与上面的分母组合,就是屏幕的刷新率为60Hz)sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;  //设置缓冲区的用途是渲染目标sd.OutputWindow = g_hWnd;                          //设置呈现的窗口句柄(为全局窗口句柄)sd.SampleDesc.Count = 1;                           //设置不使用多重采样sd.SampleDesc.Quality = 0;                         //【不使用多重采样的正常设置】sd.Windowed = TRUE;                                //设置交换链在窗口模式下运行//通过循环尝试不同的驱动器类型,从而确定能够成功创建设备和交换链for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++){//使用全局变量记录当前迭代的驱动器类型g_driverType = driverTypes[driverTypeIndex];//根据指定的驱动器类型和DirectX3D的版本尝试创建驱动器hr = D3D11CreateDeviceAndSwapChain(NULL, g_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext);//如果创建成功则提前退出循环if (SUCCEEDED(hr))break;}//如果创建失败则返回错误信息if (FAILED(hr))return hr;//创建渲染目标视图(需要后缓冲区中的纹理数据)ID3D11Texture2D* pBackBuffer = NULL;//尝试获取后缓冲区的纹理数据,获取失败则返回提示信息hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);if (FAILED(hr))return hr;//尝试创建一个目标视图并将其与后缓冲区的纹理相关联hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);//创建完成后则释放后缓冲区的数据防止内存泄露pBackBuffer->Release();if (FAILED(hr))return hr;//创建深度模板纹理并对其相关属性进行设置D3D11_TEXTURE2D_DESC descDepth;ZeroMemory(&descDepth, sizeof(descDepth));        //清空改变量的缓冲区内容防止出错descDepth.Width = width;                          //设置宽度descDepth.Height = height;                        //设置高度descDepth.MipLevels = 1;                          //表示不使用纹理数组descDepth.ArraySize = 1;                          //表示不使用纹理数组descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; //设置纹理格式descDepth.SampleDesc.Count = 1;                   //不使用多重采样descDepth.SampleDesc.Quality = 0;                 //不使用多重采样的默认设置descDepth.Usage = D3D11_USAGE_DEFAULT;            //设置纹理用途(被GPU读写)descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;   //设置绑定标志descDepth.CPUAccessFlags = 0;                     //设置CPU不允许访问纹理descDepth.MiscFlags = 0;                          //不设置其他标志//尝试创建一个深度模板纹理hr = g_pd3dDevice->CreateTexture2D(&descDepth, NULL, &g_pDepthStencil);if (FAILED(hr))return hr;//创建深度模板视图并将其与渲染目标相关联D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;ZeroMemory(&descDSV, sizeof(descDSV));  //将结构体的内容初始化为0确保每一个字段都被正常初始化descDSV.Format = descDepth.Format;      //将深度模板视图的格式设置为与深度模板纹理相同的格式descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;  //设置视图维度(2D视图)descDSV.Texture2D.MipSlice = 0;                         //【通常设置】//创建深度模板视图并将其与渲染目标相关联hr = g_pd3dDevice->CreateDepthStencilView(g_pDepthStencil, &descDSV, &g_pDepthStencilView);//如果创建失败则返回错误信息if (FAILED(hr))return hr;//将渲染目标视图和深度模板视图设置为当前的渲染目标(意味着渲染操作将绘制到这些视图中)g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);//设置视口(用于确定渲染目标的可见区域的矩形)D3D11_VIEWPORT vp;vp.Width = (FLOAT)width;   //设置视口的宽度(与客户区的宽度匹配)vp.Height = (FLOAT)height; //设置高度(与客户区的高度匹配)vp.MinDepth = 0.0f;        //设置深度范围为0.0f-1.0fvp.MaxDepth = 1.0f;vp.TopLeftX = 0;           //【通常设置】vp.TopLeftY = 0;           //【通常设置】//将配置好的视口设置为当前渲染上下文的视口g_pImmediateContext->RSSetViewports(1, &vp);//编译顶点着色器ID3DBlob* pVSBlob = NULL;   //接收编译完成的着色器代码//对顶点着色器进行编译(传入的参数分别是着色器文件路径、入口点名称、着色器模型版本、保存的指针)hr = CompileShaderFromFile(L"Test4.fx", "VS", "vs_4_0", &pVSBlob);//如果编译过程出错,则通过消息框输出提示信息if (FAILED(hr)){MessageBox(NULL,L"啊哦,您所提供的FX文件路径好像不正确呢!请给出正确的文件路径", L"Error", MB_OK);return hr;}//根据顶点着色器代码的编译结果创建一个顶点着色器对象hr = g_pd3dDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader);//如果创建失败则会将之前的顶点着色器编译结果释放并返回if (FAILED(hr)){pVSBlob->Release();return hr;}//定义输入布局(描述顶点数据的组织方式:由位置、法线和纹理三部分组成)D3D11_INPUT_ELEMENT_DESC layout[] ={{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },};//获取输入布局数组的元素数量UINT numElements = ARRAYSIZE(layout);//根据上面的定义的输入布局创建输入布局hr = g_pd3dDevice->CreateInputLayout(layout, numElements, pVSBlob->GetBufferPointer(),pVSBlob->GetBufferSize(), &g_pVertexLayout);//释放已经不需要使用的顶点着色器编译结果pVSBlob->Release();//如果创建失败则返回失败代码if (FAILED(hr))return hr;//根据创建的输入布局进行设置(确保顶点数据按照正确的格式传递给顶点着色器)g_pImmediateContext->IASetInputLayout(g_pVertexLayout);//编译像素着色器文件ID3DBlob* pPSBlob = NULL;hr = CompileShaderFromFile(L"Test4.fx", "PS", "ps_4_0", &pPSBlob);//编译失败则通过错误框给出提示if (FAILED(hr)){MessageBox(NULL,L"啊哦,您所提供的FX文件路径好像不正确呢!请给出正确的文件路径", L"Error", MB_OK);return hr;}//根据像素着色器的编译结果创建像素着色器hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader);//将已经不需要使用的像素着色器编译结果释放pPSBlob->Release();//如果出错则给出错误代码if (FAILED(hr))return hr;//编译另一个像素着色器(在同一个文件中)用于进行五种光照的展示pPSBlob = NULL;hr = CompileShaderFromFile(L"Test4.fx", "PSSolid", "ps_4_0", &pPSBlob);if (FAILED(hr)){MessageBox(NULL,L"啊哦,您所提供的FX文件路径好像不正确呢!请给出正确的文件路径.", L"Error", MB_OK);return hr;}//根据编译结果创建另一个像素着色器hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShaderSolid);//释放已经不需要使用了的编译结果pPSBlob->Release();if (FAILED(hr))return hr;//使用STL向量存储五种类型的光照std::vector<LPCSTR> shaders{ "PSAmbient","PSLambertian","PSBlinn","PSToon","PSTexture" };//分别对五种不同的光照类型做初始化for (size_t i = 0; i < 5; i++){//对着色器文件种当前编号的对应的光照进行编译pPSBlob = NULL;hr = CompileShaderFromFile(L"Test4.fx", shaders[i], "ps_4_0", &pPSBlob);//如果编译失败则给出错误提示信息if (FAILED(hr)){MessageBox(NULL,L"啊哦,您所提供的FX文件路径好像不正确呢!请给出正确的文件路径C.", L"Error", MB_OK);return hr;}//根据编译好的结果创建对应的像素着色器hr = g_pd3dDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelSh[i]);//释放像素着色器的编译结果防止内存泄露pPSBlob->Release();if (FAILED(hr))return hr;}//创建一个长度为茶壶的顶点总数的数组SimpleVertex* vertices = new SimpleVertex[numVerticeTotal];int index = 0;//遍历茶壶文件的所有网格并将茶壶的大小进行缩放(不然图中无法展示五个茶壶)for (unsigned int i = 0; i < teapot->mNumMeshes; i++){auto pMesh = teapot->mMeshes[i];for (unsigned int j = 0; j < pMesh->mNumVertices; j++) {//修改网格的大小(进行缩放)float x = pMesh->mVertices[j].x * 0.4;float y = pMesh->mVertices[j].y * 0.4;float z = pMesh->mVertices[j].z * 0.4;//调整法线的方向(用于调整光照效果)float a = pMesh->mNormals[j].x * 0.3;float b = pMesh->mNormals[j].y * 0.3;float c = pMesh->mNormals[j].z * 0.3;//存储缩放后的顶点位置和法线vertices[index++] = { XMFLOAT3(x,y,z), XMFLOAT3(a,b,c) };}}//创建顶点缓冲区用于存储顶点数据D3D11_BUFFER_DESC bd;ZeroMemory(&bd, sizeof(bd));    //清空内存用于初始化bd.Usage = D3D11_USAGE_DEFAULT; //设置缓冲区的用途(GPU读写)bd.ByteWidth = sizeof(SimpleVertex) * numVerticeTotal;  //设置缓冲区的字节宽度bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;                //设置缓冲区的绑定标志bd.CPUAccessFlags = 0;                                  //设置CPU不可访问缓冲区//创建初始化顶点缓冲区所用的数据D3D11_SUBRESOURCE_DATA InitData;ZeroMemory(&InitData, sizeof(InitData));  //清空内存用于初始化InitData.pSysMem = vertices;              //使用vertices数组中的内容初始化缓冲区//指定顶点缓冲区指针、初始化的数据和设备来创建顶点缓冲区hr = g_pd3dDevice->CreateBuffer(&bd, &InitData, &g_pVertexBuffer);if (FAILED(hr))return hr;//设置顶点缓冲区UINT stride = sizeof(SimpleVertex);UINT offset = 0;//根据指定的设置设置顶点缓冲区g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);//创建索引缓冲区//由于每个三角形有三个点,因此索引数量是三角形的数量的三倍WORD* indices = new WORD[faceNum * 3];unsigned int pos = 0;unsigned int meshPos = 0;for (int i = 0; i < teapot->mNumMeshes; i++){for (int j = 0; j < teapot->mMeshes[i]->mNumFaces; j++){struct aiFace face = teapot->mMeshes[i]->mFaces[j];for (int k = 0; k < face.mNumIndices; k++){int index = face.mIndices[k];indices[pos++] = index + meshPos;}}meshPos += teapot->mMeshes[i]->mNumVertices;}//对索引缓冲区进行设置bd.Usage = D3D11_USAGE_DEFAULT;            //设置用途为在GPU上进行读写bd.ByteWidth = sizeof(WORD) * faceNum * 3; //设置缓冲区的字节宽度bd.BindFlags = D3D11_BIND_INDEX_BUFFER;    //设置缓冲区标志bd.CPUAccessFlags = 0;                     //设置CPU不可访问InitData.pSysMem = indices;                //使用上面的indices数组初始化缓冲区//根据上述的索引缓冲区设置创建一个索引缓冲区hr = g_pd3dDevice->CreateBuffer(&bd, &InitData, &g_pIndexBuffer);if (FAILED(hr))return hr;//将创建好的索引缓冲区绑定到输入装配阶段g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);//设置图元拓扑类型为三角形列表g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);//创建常量缓冲区(相关的设置和前面的缓冲区设置相同)bd.Usage = D3D11_USAGE_DEFAULT;bd.ByteWidth = sizeof(ConstantBuffer);bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;bd.CPUAccessFlags = 0;hr = g_pd3dDevice->CreateBuffer(&bd, NULL, &g_pConstantBuffer);if (FAILED(hr))return hr;//创建着色器资源视图,将教学平台提供的tile_wood图像加载到设备中以便在渲染中使用hr = D3DX11CreateShaderResourceViewFromFile(g_pd3dDevice, L"tile_wood.jpg", NULL, NULL, &g_pTextureRV, NULL);if (FAILED(hr))return hr;//创建一个采样器状态,确定如何从纹理图像中获取颜色样本进行渲染D3D11_SAMPLER_DESC sampDesc;ZeroMemory(&sampDesc, sizeof(sampDesc));sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;sampDesc.MinLOD = 0;sampDesc.MaxLOD = D3D11_FLOAT32_MAX;hr = g_pd3dDevice->CreateSamplerState(&sampDesc, &g_pSamplerLinear);if (FAILED(hr))return hr;//初始化世界矩阵g_World = XMMatrixIdentity();//初始化视角矩阵(也就是人的观察位置)XMVECTOR Eye = XMVectorSet(0.0f, 4.0f, -10.0f, 0.0f);XMVECTOR At = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);g_View = XMMatrixLookAtLH(Eye, At, Up);//初始化投影矩阵g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, width / (FLOAT)height, 0.01f, 100.0f);return S_OK;
}//清理已经创建的设备的函数
inline void CleanupDevice(void)
{if (g_pImmediateContext) g_pImmediateContext->ClearState();if (g_pConstantBuffer) g_pConstantBuffer->Release();if (g_pVertexBuffer) g_pVertexBuffer->Release();if (g_pIndexBuffer) g_pIndexBuffer->Release();if (g_pVertexLayout) g_pVertexLayout->Release();if (g_pVertexShader) g_pVertexShader->Release();if (g_pPixelShaderSolid) g_pPixelShaderSolid->Release();if (g_pPixelShader) g_pPixelShader->Release();if (g_pDepthStencil) g_pDepthStencil->Release();if (g_pDepthStencilView) g_pDepthStencilView->Release();if (g_pRenderTargetView) g_pRenderTargetView->Release();if (g_pSwapChain) g_pSwapChain->Release();if (g_pImmediateContext) g_pImmediateContext->Release();if (g_pd3dDevice) g_pd3dDevice->Release();
}//处理窗口消息的函数(传入的参数包括窗口、消息类型和附加参数)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{PAINTSTRUCT ps;HDC hdc;//根据消息类型进行对应的操作switch (message){//重绘窗口内容case WM_PAINT:hdc = BeginPaint(hWnd, &ps);EndPaint(hWnd, &ps);break;//窗口关闭case WM_DESTROY:PostQuitMessage(0);break;//其他类型消息:调用默认的窗口消息处理函数default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;
}//对一帧图像进行渲染的函数
void Render(void)
{//更新时间static float t = 0.0f;//对于参考类型的设备,以固定的速度旋转if (g_driverType == D3D_DRIVER_TYPE_REFERENCE){t += (float)XM_PI * 0.0125f;}//对于其他类型的设备,时间的修改是根据当前获取的时间进行的else{static DWORD dwTimeStart = 0;DWORD dwTimeCur = GetTickCount();if (dwTimeStart == 0)dwTimeStart = dwTimeCur;t = (dwTimeCur - dwTimeStart) / 1200.0f;}//绕着原点进行旋转g_World = XMMatrixRotationY(t);//设置背景颜色float ClearColor[4] = { 0.25f, 0.25f, 0.25f, 1.0f }; g_pImmediateContext->ClearRenderTargetView(g_pRenderTargetView, ClearColor);//清空深度缓冲区的内容准备进行深度测试g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);//创建一个常量缓冲区用于将新的信息传递到着色器(包括三种矩阵、视角和光照效果)ConstantBuffer cb1;cb1.mWorld = XMMatrixTranspose(g_World);cb1.mView = XMMatrixTranspose(g_View);cb1.mProjection = XMMatrixTranspose(g_Projection);cb1.vLightDir = XMFLOAT4(-1.0f, 1.0f, -1.5f, 1.0f);cb1.vLightColor = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);cb1.vOutputColor = XMFLOAT4(0.0f, 1.0f, 0.0f, 0.0f);cb1.objectColor = XMFLOAT4(0.8f, 1.0f, 0.8f, 1.0f);cb1.hightLightColor = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);cb1.eye = XMFLOAT4(0.0f, 4.0f, -10.0f, 1.0f);//更新全局变量中的常量缓冲区g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, NULL, &cb1, 0, 0);//对五个茶壶模型分别进行渲染(通过迭代的方法)for (size_t i = 0; i < 5; i++){cb1.mWorld = XMMatrixTranspose(g_World * XMMatrixTranslation(-4.0f + i * 2, 0.0f, 0.0f));g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, NULL, &cb1, 0, 0);g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);g_pImmediateContext->PSSetShader(g_pPixelSh[i], NULL, 0);g_pImmediateContext->PSSetConstantBuffers(0, 1, &g_pConstantBuffer);g_pImmediateContext->PSSetShaderResources(0, 1, &g_pTextureRV);g_pImmediateContext->PSSetSamplers(0, 1, &g_pSamplerLinear);g_pImmediateContext->DrawIndexed(faceNum * 3, 0, 0);}//将后台缓冲区的内容呈现到前台缓冲区(屏幕)来展示渲染结果g_pSwapChain->Present(0, 0);
}

着色器文件代码

Texture2D txDiffuse : register(t0);
SamplerState samLinear : register(s0);
cbuffer ConstantBuffer : register(b0)
{matrix World;matrix View;matrix Projection;float4 vLightDir;float4 vLightColor;float4 vOutputColor;float4 objectColor;float4 hightLightColor;float4 eye;
}//顶点着色器输入数据格式
struct VS_INPUT
{float4 Pos : POSITION;float3 Norm : NORMAL;float2 Tex : TEXCOORD0;
};//像素着色器输入数据格式
struct PS_INPUT
{float4 Pos : SV_POSITION;float3 Norm : NORMAL;float4 Pos_world : Position;float2 Tex : TEXCOORD0;
};//顶点着色器函数
PS_INPUT VS(VS_INPUT input)
{PS_INPUT output = (PS_INPUT)0;output.Pos = mul(input.Pos, World);output.Pos_world = output.Pos;output.Pos = mul(output.Pos, View);output.Pos = mul(output.Pos, Projection);output.Norm = mul(input.Norm, World);output.Tex = input.Tex;return output;
}//原始的像素着色器函数
float4 PS(PS_INPUT input) : SV_Target
{float4 finalColor = 0;//do NdotL lighting for 2 lightsfor (int i = 0; i < 2; i++){finalColor += saturate(dot((float3)vLightDir[i],input.Norm) * vLightColor[i]);}finalColor.a = 1;return finalColor;
}//固定颜色像素着色器
float4 PSSolid(PS_INPUT input) : SV_Target
{return vOutputColor;
}//环境光着色器
float4 PSAmbient(PS_INPUT input) : SV_Target
{return vOutputColor;
}//漫反射光照着色器
float4 PSLambertian(PS_INPUT input) : SV_Target
{return saturate(objectColor * vLightColor * max(0, dot(input.Norm,vLightDir))) + vOutputColor;
}//Blinn-Phong光照着色器
float4 PSBlinn(PS_INPUT input) : SV_Target
{float4 posLight = normalize(vLightDir - input.Pos_world);float4 posView = normalize(eye - input.Pos_world);float4 h = posLight + posView;float4 b = normalize(h);return saturate(hightLightColor * objectColor * pow(max(0, dot(input.Norm, b)), 0.9)) + PSLambertian(input);
}//卡通渲染着色器
float4 PSToon(PS_INPUT input) : SV_Target
{float a = max(0, dot(input.Norm, vLightDir));float4 L1 = float4(0.1f, 0.2f, 0.1f, 0.0f);float4 L2 = float4(0.2f, 0.4f, 0.2f, 0.0f);float4 L3 = float4(0.4f, 0.6f, 0.4f, 0.0f);float4 L4 = float4(0.6f, 0.8f, 0.6f, 0.0f);float TH1 = 0.2;float TH2 = 0.4;float TH3 = 0.6;float TH4 = 1;if (a < TH1)return L1;if (a >= TH1 && a < TH2)return L2;if (a >= TH2 && a < TH3)return L3;if (a >= TH3 && a < TH4)return L4;return 0;
}//纹理映射着色器
float4 PSTexture(PS_INPUT input) : SV_Target
{return txDiffuse.Sample(samLinear, input.Tex) * vLightColor * max(0, dot(input.Norm, vLightDir));
}

效果展示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/185568.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Studio导入,删除第三方库

Android项目经常用到无私的程序员们提供的第三方类库。本篇博客就是实现第三方库的导入和删除。 一、导入第三方库 1、将需要的库下载到本地&#xff1b; 2、新建Moudle (1)File --- New Moudle (2)选择Android Library --- Next (3)填写Moudle名 --- Finish。一个新的Mou…

TikTok shop美国小店适合哪些人做?附常见运营问题解答

一、Tiktok shop小店分类 大家都知道&#xff0c;美国小店可以分为5 种&#xff1a; 美国本土个人店: 最灵活&#xff0c;有扶持政策&#xff1b;美国法人企业店&#xff1a;要求高&#xff0c;有扶持政策&#xff1b;美国公司中国人占股店 (ACCU店) : 权重相对低&#xff0c…

配置资源管理

Secret Secret 是用来保存密码、token、密钥等敏感数据的 k8s 资源&#xff0c;这类数据虽然也可以存放在 Pod 或者镜像中&#xff0c;但是放在 Secret 中是为了更方便的控制如何使用数据&#xff0c;并减少暴露的风险。 三种类型&#xff1a; kubernetes.io/service-accoun…

Unity游戏开发基础之数据结构部分

设计模式 含义&#xff1a;帮助我们降低对象之间的耦合度常用的方法称为设计模式。使用设计模式是为了可重用代码&#xff0c;让代码更容易被其他人所理解&#xff0c;保证代码可靠性&#xff0c;使代码编制真正工程化&#xff0c;这是软件工程的基石。 分类&#xff1a; 创建…

如何上传自己的Jar到Maven中央仓库

在项目开发过程中&#xff0c;我们常常会使用 Maven 从仓库拉取开源的第三方 Jar 包。本文将带领大家将自己写好的代码或开源项目发布到 Maven中央仓库中&#xff0c;让其他人可以直接依赖你的 Jar 包&#xff0c;而不需要先下载你的代码后 install 到本地。 注册帐号 点击以…

驾考在线答题系统源码:含PC+手机版驾考宝典多题库

安装说明&#xff1a; 1、上传到网站根目录 2、用 phpMyadmin 导入数据库文件 db.sql 3、修改数据库链接文件 /ThinkPHP/Conf/convention.php# &#xff08;记得不要用记事本修改&#xff0c;否则可能会出现验证码显示不了问题&#xff0c;建议用 Notepad 4、 帐号 admin 密码…

ChinaSoft 论坛巡礼 | 系统与网络安全论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

Stable Diffusion webui 源码调试(二)

Stable Diffusion webui 源码调试&#xff08;二&#xff09; 个人模型主页&#xff1a;LibLibai stable-diffusion-webui 版本&#xff1a;v1.4.1 内容更新随机&#xff0c;看心情调试代码~ 分析StableDiffusionProcessingTxt2Img类中的sample函数 Sampler /work/stable-d…

常见面试题-MySQL专栏(三)MVCC、BufferPool

typora-copy-images-to: imgs 了解 MVCC 吗&#xff1f; 答&#xff1a; MVCC&#xff08;Multi-Version Concurrency Control&#xff09; 是用来保证 MySQL 的事务隔离性的&#xff0c;对一行数据的读和写两个操作默认是不会通过加锁互斥来保证隔离性&#xff0c;避免了频…

安卓 车轮视图 WheelView kotlin

安卓 车轮视图 WheelView kotlin 前言一、代码解析1.初始化2.初始化数据3.onMeasure4.onDraw5.onTouchEvent6.其他 6.ItemObject二、完整代码总结 前言 有个需求涉及到类似这个视图&#xff0c;于是在网上找了个轮子&#xff0c;自己改吧改吧用&#xff0c;拿来主义当然后&…

idea使用lombok编译问题

idea编译报错问题如下&#xff1a; java: You arent using a compiler supported by lombok, so lombok will not work and has been disabled.Your processor is: com.sun.proxy.$Proxy26Lombok supports: OpenJDK javac, ECJ解决方案 1.先将jdk替换为openjdk,随后将项目配置…

体制内人,知道这个工具,写什么都有底气

体制内&#xff0c;每天都在写各种材料&#xff01;&#xff01; 用词、结构、形式什么的都要严谨&#xff0c;但有时候写完又不行&#xff0c;还要改改改&#xff0c;家人们谁懂啊&#xff01;&#xff01;&#xff01; 这个工具&#xff0c;输入要求就可以快速生成文案&…

基于SSM框架的共享单车管理系统小程序系统的设计和实现

基于SSM框架的共享单车管理系统小程序系统的设计和实现 源码传送入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码传送入口 前言 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;…

SpectralDiff论文阅读笔记

高光谱图像分类是遥感领域的一个重要问题&#xff0c;在地球科学中有着广泛的应用。近年来&#xff0c;人们提出了大量基于深度学习的HSI分类方法。然而&#xff0c;现有方法处理高维、高冗余和复杂数据的能力有限&#xff0c;这使得捕获数据的光谱空间分布和样本之间的关系具有…

调试 Mahony 滤波算法的思考 10

调试 Mahony 滤波算法的思考 1. 说在前面的2.Mahony滤波算法的核心思想3. 易懂的理解 Mahony 滤波算法的过程4. 其他的一些思考5. 民间 9轴评估板 1. 说在前面的 之前调试基于QMI8658 6轴姿态解算的时候&#xff0c;我对Mahony滤波的认识还比较浅薄。初次的学习和代码的移植让…

平凯星辰 TiDB 携手广发银行荣膺第十四届金融科技创新奖

近日&#xff0c;由《金融电子化》杂志社、苏州市金融科技协会共同主办的“第十四届金融科技创新奖颁奖典礼”在苏州隆重举行。 会上&#xff0c;由平凯星辰&#xff08;北京&#xff09;科技有限公司&#xff08;简称&#xff1a; 平凯星辰&#xff09;和广发银行共同申报的 “…

[unity]深色模式/浅色模式

这里用的是Windows版的unity&#xff0c;具体版本号如下&#xff1a; 选项的路径如下&#xff1a;Edit—Preferences—General—Editor Theme 然后就可以选是dark还是light了&#xff1a;

国产小体积超低成本电动车仪表智能刷卡解锁13.56M非接触式读写芯片CI522兼容替代RC522

Ci522电动车仪表一键启动芯片 Ci522是一个高度集成的&#xff0c;工作在13.56MHz的非接触式读写器芯片&#xff0c;阅读器支持ISO/IEC 14443 A/MIFARE。 无需外围其他电路&#xff0c;Ci522的内部发送器可驱动读写器天线与ISO/IEC 14443 A/MIFARE卡和应答机通信。接收器模块提…

JWT简介 JWT结构 JWT示例 前端添加JWT令牌功能 后端程序

目录 1. JWT简述 1.1 什么是JWT 1.2 为什么使用JWT 1.3 JWT结构 1.4 验证过程 2. JWT示例 2.1 后台程序 2.2 前台加入jwt令牌功能 1. JWT简述 1.1 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准&#xff08;(RFC 7…

通过创建自定义标签来扩展HTML

使用HTML时&#xff0c;例如&#xff0c;使用<b>标记显示粗体文本。 如果需要列表&#xff0c;则对每个列表项使用<ul>标记及其子标记<li> 。 标签由浏览器解释&#xff0c;并与CSS一起确定网页内容的显示方式以及部分内容的行为。 有时&#xff0c;仅使用一…