Jump to content
  • Advertisement
Sign in to follow this  
Alessandro Pozzer

3D model is not visualized [DirectX12]

This topic is 557 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
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!