Drawing a mesh created in Blender with Direct3D12
I decided to try drawing an arbitrary mesh in Direct3D12, so I first created the mesh data.
I use Maya in my work, but this time, I will create the data in Blender. Since this is my first time, I created the rocket mesh while reading this book on Kindle Unlimited.
I think this book is simple and easy to understand.
Next, I figured out how to bring the Blender data toC++. This time, the two types of data needed will be vertex data and index data. (Materials will come later.)
If we were to export the Blender data, we could use fbx, usd, and glTF formats. Each also provides a python API so you can get the data you need. However, each was more tedious than I expected when I tried to dump the vertex data in python. Is there a more user-friendly format?
So, I tried to output the data directly using Blender’s PythonAPI, just for study.
import bpy
import os
import json
# Output file name with full path
output_file = "mesh_data.json"
def append_vertex_list(vertex_list, vertex):
# If the same vertex already exists, return its index
if vertex in vertex_list:
return vertex_list.index(vertex)
# Add a new index
vertex_list.append(vertex)
return len(vertex_list) - 1
json_data = {}
# Loop over all objects in the scene
for obj in bpy.context.scene.objects:
# Targets only mesh objects
if obj.type == "MESH":
vertex_list = []
triangle_list = []
for poly in obj.data.polygons:
local_triangle_list = []
for i in range(2, len(poly.vertices)):
local_triangle_list.append((poly.vertices[0], poly.vertices[i - 1], poly.vertices[i]))
for tr in local_triangle_list:
for i in range(3):
vertex = {}
vertex["position"] = tuple(obj.data.vertices[tr[i]].co)
vertex["normal"] = tuple(obj.data.vertices[tr[i]].normal)
index = append_vertex_list(vertex_list, vertex)
triangle_list.append(index)
json_data[obj.name] = {"vertices": vertex_list, "indices": triangle_list}
with open(output_file, "w") as f:
json.dump(json_data, f, indent=4)
The output was in json format, so it was simple to write.
Outputting an 8-vertex cube produces data like this
{
"Cube": {
"vertices": [
{
"position": [
1.0,
1.0,
1.0
],
"normal": [
0.5773502588272095,
0.5773502588272095,
0.5773502588272095
]
},
{
"position": [
-1.0,
1.0,
1.0
],
"normal": [
-0.5773502588272095,
0.5773502588272095,
0.5773502588272095
]
},
{
"position": [
-1.0,
-1.0,
1.0
],
"normal": [
-0.5773502588272095,
-0.5773502588272095,
0.5773502588272095
]
},
{
"position": [
1.0,
-1.0,
1.0
],
"normal": [
0.5773502588272095,
-0.5773502588272095,
0.5773502588272095
]
},
{
"position": [
1.0,
-1.0,
-1.0
],
"normal": [
0.5773502588272095,
-0.5773502588272095,
-0.5773502588272095
]
},
{
"position": [
-1.0,
-1.0,
-1.0
],
"normal": [
-0.5773502588272095,
-0.5773502588272095,
-0.5773502588272095
]
},
{
"position": [
-1.0,
1.0,
-1.0
],
"normal": [
-0.5773502588272095,
0.5773502588272095,
-0.5773502588272095
]
},
{
"position": [
1.0,
1.0,
-1.0
],
"normal": [
0.5773502588272095,
0.5773502588272095,
-0.5773502588272095
]
}
],
"indices": [
0,
1,
2,
0,
2,
3,
4,
3,
2,
4,
2,
5,
5,
2,
1,
5,
1,
6,
6,
7,
4,
6,
4,
5,
7,
0,
3,
7,
3,
4,
6,
1,
0,
6,
0,
7
]
}
}
Next, this data is loaded atC++. The json loading part looks like this.
#include <nlohmann/json.hpp>
static void JsonToFloat3(const nlohmann::json& j, float3& v) {
v.x = j.at(0).get<float>();
v.y = j.at(1).get<float>();
v.z = j.at(2).get<float>();
}
bool LoadMeshData(const char* filename, ID3D12Device* device)
{
std::ifstream file(filename);
if (!file.is_open()) {
std::cerr << "ファイルを開けません: " << filename << std::endl;
return false;
}
// Parsing JSON data
nlohmann::json file_json;
file >> file_json;
// Read mesh data
size_t mesh_num = std::distance(file_json.begin(), file_json.end());
m_data.reserve(mesh_num);
for (auto& [mesh_name, mesh_json] : file_json.items()) {
MeshData mesh;
// Load vertex data
for (const auto& vertex_json : mesh_json["vertices"]) {
VertexData vertex;
JsonToFloat3(vertex_json["position"], vertex.position);
JsonToFloat3(vertex_json["normal"], vertex.normal);
mesh.PushBackVertex(vertex);
}
// Read index data
auto index_list = mesh_json["indices"].get<std::vector<int>>();
mesh.SetIndexList(index_list);
// Add data
m_data.push_back(mesh);
// Buffer generation
m_data[m_data.size() - 1].CreateBuffer(device);
}
return true;
}
nlohmann.json can be installed with nuget from the VisualStudio menu.
Now, when you draw the mesh of the rocket as shown earlier, it looks like this.
The material, or rather the shader, is not appropriate, but at any rate, I was able to get as far as drawing an arbitrary mesh.
Note that the previous code does not output the transform information, so please Freeze the vertex data before using it. In the case of Blender, I think you can Freeze the object→apply→with all transforms.