在上一个列子的基础上加了一个地面。这个地面是光照效果生成的。
看图:
先说明:
光照 需要重写一个 lightshader 就是光照的渲染器
// Define the input layout D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, };你会发现之前的第二行是Color而不是现在的Normal 。 因为光照的颜色是有外界 环境光 透射光 漫反射光 形成的。
这些光的计算全部写在一个效果文件lightShader.fx里面
//-------------------------------------------------------------------------------------- // Constant Buffer Variables //-------------------------------------------------------------------------------------- cbuffer ConstantBuffer { matrix World; matrix View; matrix Projection; }; cbuffer LightBuffer { float3 cameraPosition; float padding; }; //-------------------------------------------------------------------------------------- struct VS_INPUT { float4 Pos : POSITION; float3 Normal : NORMAL; }; struct VS_OUTPUT { float4 Pos : SV_POSITION; float4 Color : COLOR; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output = (VS_OUTPUT)0; float4 worldPosition; // 改变顶点为四个分量其次坐标. input.Pos.w = 1.0f; output.Pos = mul( input.Pos, World ); output.Pos = mul( output.Pos, View ); output.Pos = mul( output.Pos, Projection ); // 世界坐标系中的顶点法向. float3 N = mul(input.Normal, (float3x3)World); N = normalize(N); //世界坐标系顶点位置 float3 P = output.Pos.xyz; //自发射颜色 float3 emissive = float3(0.0, 0.0, 0.0); //计算环境光 float3 ambient = float3(0.3, 0.3, 0.3); //计算漫反射光 float3 L = normalize(float3(-1.0, -1.0, 1.0)); float diffuseLight = max(dot(N, L), 0); float3 diffuse = diffuseLight; //计算高光 float3 V = normalize(cameraPosition - P); float3 H = normalize(L + V); float specularLight = pow(max(dot(N, H), 0), 5.0); if (diffuseLight <= 0) specularLight = 0; float3 specular = specularLight; output.Color.xyz = emissive + ambient + diffuse + specular; // float3 tt = float3(1.0, 0.0, 0.0); // output.color.xyz = float3(1.0, 0.0, 0.0); output.Color.w = 1.0f; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( VS_OUTPUT input ) : SV_Target { return input.Color; }
cbuffer LightBuffer { float3 cameraPosition; float padding; };目前只存了光照的颜色 主要 要为4的倍数 对齐float地址
//create the light buffer ZeroMemory( &bd, sizeof(bd) ); bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof(LightBuffer); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = 0; hr = device->CreateBuffer( &bd, NULL, &m_lightmaterialBuffer ); if( FAILED( hr ) ) return hr;
// // Update variables // ConstantBuffer cb; cb.mWorld = XMMatrixTranspose( worldMatrix); cb.mView = XMMatrixTranspose( viewMatrix ); cb.mProjection = XMMatrixTranspose( projectionMatrix ); deviceContext->UpdateSubresource( m_matrixBuffer, 0, NULL, &cb, 0, 0 ); deviceContext->VSSetConstantBuffers( 0, 1, &m_matrixBuffer ); LightBuffer lb; lb.cameraPosition=cameraPos; deviceContext->UpdateSubresource( m_lightmaterialBuffer, 0, NULL, &lb, 0, 0 ); deviceContext->VSSetConstantBuffers( 1, 1, &m_matrixBuffer );
有了光照效果文件 光照渲染器 还差一个承载物
这里是一个四边形,作为大地吧
PlaneModel.h
#pragma once #include "XComm.h" class PlaneModel { protected: struct SimpleVertexN { XMFLOAT3 Pos; XMFLOAT3 Normal; }; public://顶点缓冲和顶点索引缓冲 ID3D11Buffer *m_vertexBuffer, *m_indexBuffer; int m_vertexCount, m_indexCount; public: PlaneModel():m_vertexCount(0),m_indexCount(0){}; bool init(ID3D11Device*); void close(); void render(ID3D11DeviceContext*); };
PlaneModel.cpp
#include "PlaneModel.h" bool PlaneModel::init(ID3D11Device* device) { SimpleVertexN* vertices; unsigned long* indices; D3D11_BUFFER_DESC vertexBufferDesc, indexBufferDesc; D3D11_SUBRESOURCE_DATA vertexData, indexData; HRESULT result; //首先,我们创建2个临时缓冲存放顶点和索引数据,以便后面使用。. // 设置顶点缓冲大小为4,一个平面. m_vertexCount = 4; // 设置索引缓冲大小.,两个三角形 m_indexCount = 6; // 创建顶点临时缓冲. vertices = new SimpleVertexN[m_vertexCount]; if(!vertices) { return false; } // 创建索引缓冲. indices = new unsigned long[m_indexCount]; if(!indices) { return false; } //创建顺时针方向的三角形,左手规则 // 设置顶点数据. vertices[0].Pos = XMFLOAT3(-50.0f, -3.0f, -50.0f); vertices[0].Normal = XMFLOAT3(0.0f, 1.0f, 0.0f); vertices[1].Pos = XMFLOAT3(-50.0f,-3.0f, 50.0f); vertices[1].Normal = XMFLOAT3(0.0f, 1.0f, 0.0f); vertices[2].Pos = XMFLOAT3(50.0f, -3.0f, 50.0f); vertices[2].Normal= XMFLOAT3(0.0f, 1.0f, 0.0f); vertices[3].Pos = XMFLOAT3(50.0f, -3.0f, -50.0f); vertices[3].Normal = XMFLOAT3(0.0f, 1.0f, 0.0f); // 设置索引缓冲数据. indices[0] = 0; // 前面 indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; // 设置顶点缓冲描述 vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT; vertexBufferDesc.ByteWidth = sizeof(SimpleVertexN) * m_vertexCount; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = 0; vertexBufferDesc.MiscFlags = 0; vertexBufferDesc.StructureByteStride = 0; // 指向保存顶点数据的临时缓冲. vertexData.pSysMem = vertices; vertexData.SysMemPitch = 0; vertexData.SysMemSlicePitch = 0; // 创建顶点缓冲. result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer); if(FAILED(result)) { HR(result); return false; } // 设置索引缓冲描述. indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; indexBufferDesc.StructureByteStride = 0; // 指向存临时索引缓冲. indexData.pSysMem = indices; indexData.SysMemPitch = 0; indexData.SysMemSlicePitch = 0; // 创建索引缓冲. result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer); if(FAILED(result)) { HR(result); return false; } // 释放临时缓冲. delete [] vertices; vertices = 0; delete [] indices; indices = 0; } void PlaneModel::close() { // 释放顶点缓冲. if(m_indexBuffer) { m_indexBuffer->Release(); m_indexBuffer = 0; } // 释放索引缓冲 if(m_vertexBuffer) { m_vertexBuffer->Release(); m_vertexBuffer = 0; } } void PlaneModel::render(ID3D11DeviceContext* deviceContext) { unsigned int stride; unsigned int offset; // 设置顶点缓冲跨度和偏移. stride = sizeof(SimpleVertexN); offset = 0; //在input assemberl阶段绑定顶点缓冲,以便能够被渲染 deviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset); //在input assemberl阶段绑定索引缓冲,以便能够被渲染 deviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0); // 设置体元语义,渲染三角形列表. //注意这里和XModel不一样 deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); }