• Advertisement
Sign in to follow this  

3D model is not visualized [DirectX12]

This topic is 408 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

I am trying to load a 3d model into my project. I used assimp to load a .x model and it seems to work ( I can print correctly vertices and indices values) but the model is not shown in the window. At this point I thing the problem can be on the camera position but I need your help to sort this out. The code is uploaded as file so you can view it more clearly. 

The program runs without errors.

 

main.cpp:

 

model = new ModelMesh();
std::vector<XMFLOAT3> positions;
std::vector<XMFLOAT3> normals;
std::vector<XMFLOAT2> texCoords;
std::vector<unsigned int> indices;
model->LoadMesh("beast.x", positions, normals,
texCoords, indices);
// Create vertex buffer


if (positions.size() == 0)
{
MessageBox(0, L"Vertices vector is empty.",
L"Error", MB_OK);
}
Vertex* vList = new Vertex[positions.size()];
for (size_t i = 0; i < positions.size(); i++)
{
Vertex vert;
XMFLOAT3 pos = positions[i];
vert.position = XMFLOAT3(pos.x, pos.y, pos.z);
XMFLOAT3 norm = normals[i];
vert.normal = XMFLOAT3(norm.x, norm.y, norm.z);
XMFLOAT2 tex = texCoords[i];
vert.texture = XMFLOAT2(tex.x, tex.y);
vList[i] = vert;
}




int vBufferSize = sizeof(Vertex) * positions.size();


// create default heap
// default heap is memory on the GPU. Only the GPU has access to this memory
// To get data into this heap, we will have to upload the data using
// an upload heap
device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), // a default heap
D3D12_HEAP_FLAG_NONE, // no flags
&CD3DX12_RESOURCE_DESC::Buffer(vBufferSize), // resource description for a buffer
D3D12_RESOURCE_STATE_COPY_DEST, // we will start this heap in the copy destination state since we will copy data
// from the upload heap to this heap
nullptr, // optimized clear value must be null for this type of resource. used for render targets and depth/stencil buffers
IID_PPV_ARGS(&vertexBuffer));


// we can give resource heaps a name so when we debug with the graphics debugger we know what resource we are looking at
vertexBuffer->SetName(L"Vertex Buffer Resource Heap");


// create upload heap
// upload heaps are used to upload data to the GPU. CPU can write to it, GPU can read from it
// We will upload the vertex buffer using this heap to the default heap
ID3D12Resource* vBufferUploadHeap;
device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), // upload heap
D3D12_HEAP_FLAG_NONE, // no flags
&CD3DX12_RESOURCE_DESC::Buffer(vBufferSize), // resource description for a buffer
D3D12_RESOURCE_STATE_GENERIC_READ, // GPU will read from this buffer and copy its contents to the default heap
nullptr,
IID_PPV_ARGS(&vBufferUploadHeap));
vBufferUploadHeap->SetName(L"Vertex Buffer Upload Resource Heap");


// store vertex buffer in upload heap
D3D12_SUBRESOURCE_DATA vertexData = {};
vertexData.pData = reinterpret_cast<BYTE*>(vList); // pointer to our vertex array
vertexData.RowPitch = vBufferSize; // size of all our triangle vertex data
vertexData.SlicePitch = vBufferSize; // also the size of our triangle vertex data


// we are now creating a command with the command list to copy the data from
// the upload heap to the default heap
UpdateSubresources(commandList, vertexBuffer, vBufferUploadHeap, 0, 0, 1, &vertexData);


// transition the vertex buffer data from copy destination state to vertex buffer state
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(vertexBuffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));




// Create index buffer
unsigned int* iList = &indices[0];
//unsigned int iList = *iiList;
// a quad (2 triangles)






std::ofstream outputFile;
outputFile.open("data.txt");


outputFile << vList[0].position.x << "  " << vList[0].position.y << "  "
<< vList[0].position.z << std::endl;
outputFile << vList[1].position.x << "  " << vList[1].position.y << "  "
<< vList[1].position.z << std::endl;
outputFile << vList[2].position.x << "  " << vList[2].position.y << "  "
<< vList[2].position.z << std::endl;
outputFile << vList[2400].position.x << "  " << vList[2400].position.y << "  "
<< vList[2400].position.z << std::endl;
outputFile << indices[11000] << "  " << indices[11001] << "  " << indices[11002] << "  " << indices[11003] << "      " << indices.size() <<std::endl;
outputFile.close();






int iBufferSize = sizeof(unsigned int) * indices.size();


numModelIndices = sizeof(iList) / sizeof(unsigned int);


// create default heap to hold index buffer
device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), // a default heap
D3D12_HEAP_FLAG_NONE, // no flags
&CD3DX12_RESOURCE_DESC::Buffer(iBufferSize), // resource description for a buffer
D3D12_RESOURCE_STATE_COPY_DEST, // start in the copy destination state
nullptr, // optimized clear value must be null for this type of resource
IID_PPV_ARGS(&indexBuffer));


// we can give resource heaps a name so when we debug with the graphics debugger we know what resource we are looking at
vertexBuffer->SetName(L"Index Buffer Resource Heap");


// create upload heap to upload index buffer
ID3D12Resource* iBufferUploadHeap;
device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), // upload heap
D3D12_HEAP_FLAG_NONE, // no flags
&CD3DX12_RESOURCE_DESC::Buffer(iBufferSize), // resource description for a buffer
D3D12_RESOURCE_STATE_GENERIC_READ, // GPU will read from this buffer and copy its contents to the default heap
nullptr,
IID_PPV_ARGS(&iBufferUploadHeap));
vBufferUploadHeap->SetName(L"Index Buffer Upload Resource Heap");


// store vertex buffer in upload heap
D3D12_SUBRESOURCE_DATA indexData = {};
indexData.pData =  reinterpret_cast<BYTE*>(iList); // pointer to our index array
indexData.RowPitch = iBufferSize; // size of all our index buffer
indexData.SlicePitch = iBufferSize; // also the size of our index buffer


// we are now creating a command with the command list to copy the data from
// the upload heap to the default heap
UpdateSubresources(commandList, indexBuffer, iBufferUploadHeap, 0, 0, 1, &indexData);


// transition the vertex buffer data from copy destination state to vertex buffer state
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(indexBuffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER));


// Create the depth/stencil buffer


// create a depth stencil descriptor heap so we can get a pointer to the depth stencil buffer
D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
dsvHeapDesc.NumDescriptors = 1;
dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
hr = device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&dsDescriptorHeap));
if (FAILED(hr))
{
Running = false;
}


D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {};
depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE;


D3D12_CLEAR_VALUE depthOptimizedClearValue = {};
depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT;
depthOptimizedClearValue.DepthStencil.Depth = 1.0f;
depthOptimizedClearValue.DepthStencil.Stencil = 0;


device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
D3D12_HEAP_FLAG_NONE,
&CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, Width, Height, 1, 0, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL),
D3D12_RESOURCE_STATE_DEPTH_WRITE,
&depthOptimizedClearValue,
IID_PPV_ARGS(&depthStencilBuffer)
);
dsDescriptorHeap->SetName(L"Depth/Stencil Resource Heap");


device->CreateDepthStencilView(depthStencilBuffer, &depthStencilDesc, dsDescriptorHeap->GetCPUDescriptorHandleForHeapStart());


for (int i = 0; i < frameBufferCount; ++i)
{
// create resource for cube 1
hr = device->CreateCommittedResource(
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), // this heap will be used to upload the constant buffer data
D3D12_HEAP_FLAG_NONE, // no flags
&CD3DX12_RESOURCE_DESC::Buffer(1024 * 64), // size of the resource heap. Must be a multiple of 64KB for single-textures and constant buffers
D3D12_RESOURCE_STATE_GENERIC_READ, // will be data that is read from so we keep it in the generic read state
nullptr, // we do not have use an optimized clear value for constant buffers
IID_PPV_ARGS(&constantBufferUploadHeaps[i]));
constantBufferUploadHeaps[i]->SetName(L"Constant Buffer Upload Resource Heap");


ZeroMemory(&cbPerObject, sizeof(cbPerObject));


CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. (so end is less than or equal to begin)


// map the resource heap to get a gpu virtual address to the beginning of the heap
hr = constantBufferUploadHeaps[i]->Map(0, &readRange, reinterpret_cast<void**>(&cbvGPUAddress[i]));


// Because of the constant read alignment requirements, constant buffer views must be 256 bit aligned. Our buffers are smaller than 256 bits,
// so we need to add spacing between the two buffers, so that the second buffer starts at 256 bits from the beginning of the resource heap.
memcpy(cbvGPUAddress[i], &cbPerObject, sizeof(cbPerObject)); // cube1's constant buffer data
memcpy(cbvGPUAddress[i] + ConstantBufferPerObjectAlignedSize, &cbPerObject, sizeof(cbPerObject)); // cube2's constant buffer data
}


// Now we execute the command list to upload the initial assets (triangle data)
commandList->Close();
ID3D12CommandList* ppCommandLists[] = { commandList };
commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);


// increment the fence value now, otherwise the buffer might not be uploaded by the time we start drawing
fenceValue[frameIndex]++;
hr = commandQueue->Signal(fence[frameIndex], fenceValue[frameIndex]);
if (FAILED(hr))
{
Running = false;
}


// create a vertex buffer view for the triangle. We get the GPU memory address to the vertex pointer using the GetGPUVirtualAddress() method
vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress();
vertexBufferView.StrideInBytes = sizeof(Vertex);
vertexBufferView.SizeInBytes = vBufferSize;


// create a vertex buffer view for the triangle. We get the GPU memory address to the vertex pointer using the GetGPUVirtualAddress() method
indexBufferView.BufferLocation = indexBuffer->GetGPUVirtualAddress();
indexBufferView.Format = DXGI_FORMAT_R32_UINT; // 32-bit unsigned integer (this is what a dword is, double word, a word is 2 bytes)
indexBufferView.SizeInBytes = iBufferSize;


// Fill out the Viewport
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = Width;
viewport.Height = Height;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;


// Fill out a scissor rect
scissorRect.left = 0;
scissorRect.top = 0;
scissorRect.right = Width;
scissorRect.bottom = Height;


// build projection and view matrix
XMMATRIX tmpMat = XMMatrixPerspectiveFovLH(45.0f*(3.14f/180.0f), (float)Width / (float)Height, 0.1f, 1000.0f);
XMStoreFloat4x4(&cameraProjMat, tmpMat);


// set starting camera state
cameraPosition = XMFLOAT4(0.0f, 2.0f, 10.0f, 1.0f);
cameraTarget = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
cameraUp = XMFLOAT4(0.0f, 1.0f, 0.0f, 0.0f);


// build view matrix
XMVECTOR cPos = XMLoadFloat4(&cameraPosition);
XMVECTOR cTarg = XMLoadFloat4(&cameraTarget);
XMVECTOR cUp = XMLoadFloat4(&cameraUp);
tmpMat = XMMatrixLookAtLH(cPos, cTarg, cUp);
XMStoreFloat4x4(&cameraViewMat, tmpMat);


modelPosition = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f); // set cube 1's position
XMVECTOR posVec = XMLoadFloat4(&modelPosition); // create xmvector for cube1's position


tmpMat = XMMatrixTranslationFromVector(posVec); // create translation matrix from cube1's position vector
XMStoreFloat4x4(&modelRotMat, XMMatrixIdentity()); // initialize cube1's rotation matrix to identity matrix
XMStoreFloat4x4(&modelWorldMat, tmpMat); // store cube1's world matrix




return true;
}


void Update()
{
// update app logic, such as moving the camera or figuring out what objects are in view


// create rotation matrices
XMMATRIX rotXMat = XMMatrixRotationX(0.000f);
XMMATRIX rotYMat = XMMatrixRotationY(0.000f);
XMMATRIX rotZMat = XMMatrixRotationZ(0.000f);


// add rotation to cube1's rotation matrix and store it
XMMATRIX rotMat = XMLoadFloat4x4(&modelRotMat) * rotXMat * rotYMat * rotZMat;
XMStoreFloat4x4(&modelRotMat, rotMat);


// create translation matrix for cube 1 from cube 1's position vector
XMMATRIX translationMat = XMMatrixTranslationFromVector(XMLoadFloat4(&modelPosition));


// create cube1's world matrix by first rotating the cube, then positioning the rotated cube
XMMATRIX worldMat = rotMat * translationMat;


// store cube1's world matrix
XMStoreFloat4x4(&modelWorldMat, worldMat);


// update constant buffer for cube1
// create the wvp matrix and store in constant buffer
XMMATRIX viewMat = XMLoadFloat4x4(&cameraViewMat); // load view matrix
XMMATRIX projMat = XMLoadFloat4x4(&cameraProjMat); // load projection matrix
XMMATRIX wvpMat = XMLoadFloat4x4(&modelWorldMat) * viewMat * projMat; // create wvp matrix
XMMATRIX transposed = XMMatrixTranspose(wvpMat); // must transpose wvp matrix for the gpu
XMStoreFloat4x4(&cbPerObject.wvpMat, transposed); // store transposed wvp matrix in constant buffer


// copy our ConstantBuffer instance to the mapped constant buffer resource
memcpy(cbvGPUAddress[frameIndex], &cbPerObject, sizeof(cbPerObject));
}


void UpdatePipeline()
{
HRESULT hr;


// We have to wait for the gpu to finish with the command allocator before we reset it
WaitForPreviousFrame();


// we can only reset an allocator once the gpu is done with it
// resetting an allocator frees the memory that the command list was stored in
hr = commandAllocator[frameIndex]->Reset();
if (FAILED(hr))
{
Running = false;
}


hr = commandList->Reset(commandAllocator[frameIndex], pipelineStateObject);
if (FAILED(hr))
{
Running = false;
}


// here we start recording commands into the commandList (which all the commands will be stored in the commandAllocator)


// transition the "frameIndex" render target from the present state to the render target state so the command list draws to it starting from here
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(renderTargets[frameIndex], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));


// here we again get the handle to our current render target view so we can set it as the render target in the output merger stage of the pipeline
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), frameIndex, rtvDescriptorSize);


// get a handle to the depth/stencil buffer
CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(dsDescriptorHeap->GetCPUDescriptorHandleForHeapStart());


// set the render target for the output merger stage (the output of the pipeline)
commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);


// Clear the render target by using the ClearRenderTargetView command
const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);


// clear the depth/stencil buffer
commandList->ClearDepthStencilView(dsDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);


// set root signature
commandList->SetGraphicsRootSignature(rootSignature); // set the root signature


// draw triangle
commandList->RSSetViewports(1, &viewport); // set the viewports
commandList->RSSetScissorRects(1, &scissorRect); // set the scissor rects
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // set the primitive topology
commandList->IASetVertexBuffers(0, 1, &vertexBufferView); // set the vertex buffer (using the vertex buffer view)
commandList->IASetIndexBuffer(&indexBufferView);




// set model's constant buffer
commandList->SetGraphicsRootConstantBufferView(0, constantBufferUploadHeaps[frameIndex]->GetGPUVirtualAddress());


// draw model
commandList->DrawIndexedInstanced(numModelIndices, 1, 0, 0, 0);




// transition the "frameIndex" render target from the render target state to the present state. If the debug layer is enabled, you will receive a
// warning if present is called on the render target when it's not in the present state
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(renderTargets[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));


hr = commandList->Close();
if (FAILED(hr))
{
Running = false;
}
}


void Render()
{
HRESULT hr;


UpdatePipeline(); // update the pipeline by sending commands to the commandqueue


// create an array of command lists (only one command list here)
ID3D12CommandList* ppCommandLists[] = { commandList };


// execute the array of command a
commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);


// this command goes in at the end of our command queue. we will know when our command queue 
// has finished because the fence value will be set to "fenceValue" from the GPU since the command
// queue is being executed on the GPU
hr = commandQueue->Signal(fence[frameIndex], fenceValue[frameIndex]);
if (FAILED(hr))
{
Running = false;
}


// present the current backbuffer
hr = swapChain->Present(0, 0);
if (FAILED(hr))
{
Running = false;
}
}
 

Thank you for your help.

Edited by alezz94

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement