Helper Recipes

10.Helper Recipes

[TOC]

介绍

内容

Preparing a translation matrix
Preparing a rotation matrix
Preparing a scaling matrix
Preparing a perspective projection matrix
Preparing an orthographic projection matrix
Loading texture data from a file
Loading a 3D model from an OBJ file

介绍

matrix

translation matrix

关于vulkan 坐标系x (lef/rightt), y (down/up), and z (near/far).右手坐标系

关于矩阵

1
2
3
4
5
6
7
std::array<float, 16> translation_matrix = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
x, y, z, 1.0f
};
return translation_matrix;

All elements initialize with a 0.0f value
0th, 5th, 10th, and 15th elements (main diagonal) with a 1.0f value
12th element with a value stored in the x variable
13th element with a value stored in the y variable
14th element with a value stored in the z variable

也就是列主序

rotation matrix

0th element with a x x (1.0f - c) + c
1st element with a y x (1.0f - c) - z s
2nd element with a z
x (1.0f - c) + y s
4th element with a x y (1.0f - c) + z s
5th element with a y
y (1.0f - c) + c
6th element with a z
y (1.0f - c) - x s
8th element with a x z (1.0f - c) - y s
9th element with a y
z (1.0f - c) + x s
10th element with a z z (1.0f - c) + c
The rest of the elements initialize with a 0.0f value
Except for the 15th element, which should contain a 1.0f value

Each column of such matrix defines the directions of x, y, and z axes respectively after the rotation is performed.

一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
if( normalize ) {
std::array<float, 3> normalized = Normalize( x, y, z );
x = normalized[0];
y = normalized[1];
z = normalized[2];
}
const float c = cos( Deg2Rad( angle ) );
const float _1_c = 1.0f - c;
const float s = sin( Deg2Rad( angle ) );
std::array<float, 16> rotation_matrix = {
x * x * _1_c + c,
y * x * _1_c - z * s,
z * x * _1_c + y * s,
0.0f,
x * y * _1_c + z * s,
y * y * _1_c + c,
z * y * _1_c - x * s,
0.0f,
x * z * _1_c - y * s,
y * z * _1_c + x * s,
z * z * _1_c + c,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f
};
return rotation_matrix;

Preparing a scaling matrix

  • All elements initialize with a 0.0f value
  • 0th element with a value stored in the x variable
  • 5th element with a value stored in the y variable
  • 10th element with a value stored in the z variable
  • 15th element with a 1.0f value

..

1
2
3
4
5
6
7
std::array<float, 16> scaling_matrix = {
x, 0.0f, 0.0f, 0.0f,
0.0f, y, 0.0f, 0.0f,
0.0f, 0.0f, z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
return scaling_matrix;

Preparing a perspective projection matrix

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
float aspect_ratio;//width/height
float field_of_view;//Initialize it with an angle (in radians) of a vertical field of view of a camera
float near_plane;
float far_plane;
float f = (1.0f / tan(Deg2Rad(0.5f * field_of_view)));
Matrix4x4 perspective_projection_matrix = {
f / aspect_ratio,
0.0f,
0.0f,
0.0f,
0.0f,
-f,
0.0f,
0.0f,
0.0f,
0.0f,
far_plane / (near_plane - far_plane),
-1.0f,
0.0f,
0.0f,
(near_plane * far_plane) / (near_plane - far_plane),
0.0f
};
return perspective_projection_matrix;
  • 0th element with a f / aspect_ratio
  • 5th element with a -f
  • 10th element with a far_plane / (near_plane - far_plane)
  • 11th element with a -1.0f value
  • 14th element with a (near_plane * far_plane) / (near_plane -
    far_plane)
  • The rest of the elements initialize with a 0.0f value

Preparing an orthographic projection matrix

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Matrix4x4 orthographic_projection_matrix = {
2.0f / (right_plane - left_plane),
0.0f,
0.0f,
0.0f,
0.0f,
2.0f / (bottom_plane - top_plane),
0.0f,
0.0f,
0.0f,
0.0f,
1.0f / (near_plane - far_plane),
0.0f,
-(right_plane + left_plane) / (right_plane - left_plane),
-(bottom_plane + top_plane) / (bottom_plane - top_plane),
near_plane / (near_plane - far_plane),
1.0f
};
return orthographic_projection_matrix;

Loading texture data

stb

1
2
3
4
5
6
7
8
9
10
11
12
13
int width = 0;
int height = 0;
int num_components = 0;
std::unique_ptr<unsigned char, void(*)(void*)> stbi_data( stbi_load(
filename, &width, &height, &num_components, num_requested_components ),
stbi_image_free );
if( (!stbi_data) ||
(0 >= width) ||
(0 >= height) ||
(0 >= num_components) ) {
std::cout << "Could not read image!" << std::endl;
return false;
}
1
2
3
4
5
6
std::vector<unsigned char> image_data;
int data_size = width * height * (0 < num_requested_components ?
num_requested_components : num_components);
image_data.resize( data_size );
std::memcpy( image_data.data(), stbi_data.get(), data_size );
return true;

3D model obj file

https://github.com/syoyo/tinyobjloader.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include ...
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"


struct Mesh {
std::vector<float> Data;
struct Part {
uint32_t VertexOffset;
uint32_t VertexCount;
};
std::vector<Part> Parts;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
tinyobj::attrib_t attribs;
std::vectortinyobj::shape_t shapes;
std::vectortinyobj::material_t materials;
std::string error;
bool result = tinyobj::LoadObj( &attribs, &shapes, &materials, &error,
filename.c_str() );
if( !result ) {
std::cout << "Could not open '" << filename << "' file.";
if( 0 < error.size() ) {
std::cout << " " << error;
}
std::cout << std::endl;
return false;
}



Mesh mesh = {};
uint32_t offset = 0;
for( auto & shape : shapes ) {
uint32_t part_offset = offset;
for( auto & index : shape.mesh.indices ) {
mesh.Data.emplace_back( attribs.vertices[3 * index.vertex_index + 0] );
mesh.Data.emplace_back( attribs.vertices[3 * index.vertex_index + 1] );
mesh.Data.emplace_back( attribs.vertices[3 * index.vertex_index + 2] );
++offset;
if( (load_normals) &&
(attribs.normals.size() > 0) ) {
mesh.Data.emplace_back( attribs.normals[3index.normal_index+0]);
mesh.Data.emplace_back( attribs.normals[3index.normal_index+1]);
mesh.Data.emplace_back( attribs.normals[3*index.normal_index+2]);

}
if( (load_texcoords) &&
(attribs.texcoords.size() > 0)) {
mesh.Data.emplace_back( attribs.texcoords[2 * index.texcoord_index +
0] );
mesh.Data.emplace_back( attribs.texcoords[2 * index.texcoord_index +
1] );
}
}
uint32_t part_vertex_count = offset - part_offset;
if( 0 < part_vertex_count ) {
mesh.Parts.push_back( { part_offset, part_vertex_count } );
}
}