Skip to content

Commit c8116f8

Browse files
committed
提交剩余 demo
1 parent c6bc7f7 commit c8116f8

File tree

5 files changed

+374
-0
lines changed

5 files changed

+374
-0
lines changed

Model.h

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//=====================================================================
2+
//
3+
// Model.h - 该文件改写自 tinyrender 的 model.h
4+
//
5+
// Created by skywind on 2020/08/11
6+
// Last Modified: 2020/08/11 19:22:13
7+
//
8+
//=====================================================================
9+
#ifndef _MODEL_H_
10+
#define _MODEL_H_
11+
12+
#include <fstream>
13+
#include <sstream>
14+
#include <iostream>
15+
16+
#include "RenderHelp.h"
17+
18+
19+
//---------------------------------------------------------------------
20+
// model
21+
//---------------------------------------------------------------------
22+
class Model {
23+
public:
24+
inline virtual ~Model() {
25+
if (_diffusemap) delete _diffusemap;
26+
if (_normalmap) delete _normalmap;
27+
if (_specularmap) delete _specularmap;
28+
}
29+
30+
inline Model(const char *filename) {
31+
_diffusemap = NULL;
32+
_normalmap = NULL;
33+
_specularmap = NULL;
34+
std::ifstream in;
35+
in.open(filename, std::ifstream::in);
36+
if (in.fail()) return;
37+
std::string line;
38+
while (!in.eof()) {
39+
std::getline(in, line);
40+
std::istringstream iss(line.c_str());
41+
char trash;
42+
if (line.compare(0, 2, "v ") == 0) {
43+
iss >> trash;
44+
Vec3f v;
45+
for (int i = 0; i < 3; i++) iss >> v[i];
46+
_verts.push_back(v);
47+
}
48+
else if (line.compare(0, 3, "vn ") == 0) {
49+
iss >> trash >> trash;
50+
Vec3f n;
51+
for (int i = 0; i < 3; i++) iss >> n[i];
52+
_norms.push_back(n);
53+
}
54+
else if (line.compare(0, 3, "vt ") == 0) {
55+
iss >> trash >> trash;
56+
Vec2f uv;
57+
iss >> uv[0] >> uv[1];
58+
_uv.push_back(uv);
59+
}
60+
else if (line.compare(0, 2, "f ") == 0) {
61+
std::vector<Vec3i> f;
62+
Vec3i tmp;
63+
iss >> trash;
64+
while (iss >> tmp[0] >> trash >> tmp[1] >> trash >> tmp[2]) {
65+
for (int i = 0; i < 3; i++) tmp[i]--;
66+
f.push_back(tmp);
67+
}
68+
_faces.push_back(f);
69+
}
70+
}
71+
std::cout << "# v# " << _verts.size() << " f# " << _faces.size() << "\n";
72+
_diffusemap = load_texture(filename, "_diffuse.bmp");
73+
_normalmap = load_texture(filename, "_nm.bmp");
74+
_specularmap = load_texture(filename, "_spec.bmp");
75+
}
76+
77+
public:
78+
79+
inline int nverts() const { return (int)_verts.size(); }
80+
inline int nfaces() const { return (int)_faces.size(); }
81+
82+
inline std::vector<int> face(int idx) const {
83+
std::vector<int> face;
84+
for (int i = 0; i < (int)_faces[idx].size(); i++)
85+
face.push_back(_faces[idx][i][0]);
86+
return face;
87+
}
88+
89+
inline Vec3f vert(int i) const { return _verts[i]; }
90+
inline Vec3f vert(int iface, int nthvert) { return _verts[_faces[iface][nthvert][0]]; }
91+
92+
inline Vec2f uv(int iface, int nthvert) const {
93+
return _uv[_faces[iface][nthvert][1]];
94+
}
95+
96+
inline Vec3f normal(int iface, int nthvert) const {
97+
int idx = _faces[iface][nthvert][2];
98+
return vector_normalize(_norms[idx]);
99+
}
100+
101+
inline Vec4f diffuse(Vec2f uv) const {
102+
assert(_diffusemap);
103+
return _diffusemap->Sample2D(uv);
104+
}
105+
106+
inline Vec3f normal(Vec2f uv) const {
107+
assert(_normalmap);
108+
Vec4f color = _normalmap->Sample2D(uv);
109+
for (int i = 0; i < 3; i++) color[i] = color[i] * 2.0f - 1.0f;
110+
return {color[0], color[1], color[2]};
111+
}
112+
113+
inline float Specular(Vec2f uv) {
114+
Vec4f color = _specularmap->Sample2D(uv);
115+
return color.b;
116+
}
117+
118+
protected:
119+
Bitmap *load_texture(std::string filename, const char *suffix) {
120+
std::string texfile(filename);
121+
size_t dot = texfile.find_last_of(".");
122+
if (dot == std::string::npos) return NULL;
123+
texfile = texfile.substr(0, dot) + std::string(suffix);
124+
Bitmap *texture = Bitmap::LoadFile(texfile.c_str());
125+
std::cout << "loading: " << texfile << ((texture)? " OK" : " failed") << "\n";
126+
texture->FlipVertical();
127+
return texture;
128+
}
129+
130+
protected:
131+
std::vector<Vec3f> _verts;
132+
std::vector<std::vector<Vec3i> > _faces;
133+
std::vector<Vec3f> _norms;
134+
std::vector<Vec2f> _uv;
135+
Bitmap *_diffusemap;
136+
Bitmap *_normalmap;
137+
Bitmap *_specularmap;
138+
};
139+
140+
141+
#endif
142+
143+

RenderHelp.h

+5
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,11 @@ inline T Between(T xmin, T xmax, T x) {
683683
return Min(Max(xmin, x), xmax);
684684
}
685685

686+
// 截取 [0, 1] 的范围
687+
template<typename T>
688+
inline T Saturate(T x) {
689+
return Between<T>(0, 1, x);
690+
}
686691

687692
// 类型别名
688693
typedef Vector<2, float> Vec2f;

sample_05_model.cpp

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "RenderHelp.h"
2+
#include "Model.h"
3+
4+
5+
int main(void)
6+
{
7+
RenderHelp rh(600, 800);
8+
9+
// 加载模型
10+
Model model("res/diablo3_pose.obj");
11+
12+
Vec3f eye_pos = {0, -0.5, 1.7};
13+
Vec3f eye_at = {0, 0, 0};
14+
Vec3f eye_up = {0, 1, 0};
15+
Vec3f light_dir = {1, 1, 0.85}; // 光的方向
16+
float perspective = 3.1415926f * 0.5f;
17+
18+
Mat4x4f mat_model = matrix_set_scale(1, 1, 1);
19+
Mat4x4f mat_view = matrix_set_lookat(eye_pos, eye_at, eye_up);
20+
Mat4x4f mat_proj = matrix_set_perspective(perspective, 6 / 8.0, 1.0, 500.0f);
21+
Mat4x4f mat_mvp = mat_model * mat_view * mat_proj;
22+
23+
// 用于将法向量从模型坐标系变换到世界坐标系
24+
Mat4x4f mat_model_it = matrix_invert(mat_model).Transpose();
25+
26+
// 顶点属性
27+
struct { Vec3f pos; Vec3f normal; Vec2f uv; } vs_input[3];
28+
29+
const int VARYING_UV = 0;
30+
const int VARYING_NORMAL = 1;
31+
32+
rh.SetVertexShader([&] (int index, ShaderContext& output) -> Vec4f {
33+
Vec4f pos = vs_input[index].pos.xyz1() * mat_mvp;
34+
Vec4f normal = (vs_input[index].normal.xyz1() * mat_model_it);
35+
output.varying_vec2f[VARYING_UV] = vs_input[index].uv;
36+
output.varying_vec3f[VARYING_NORMAL] = normal.xyz(); // 转化为三维
37+
return pos;
38+
});
39+
40+
rh.SetPixelShader([&] (ShaderContext& input) -> Vec4f {
41+
Vec2f uv = input.varying_vec2f[VARYING_UV];
42+
Vec3f n = input.varying_vec3f[VARYING_NORMAL];
43+
Vec3f l = vector_normalize(light_dir);
44+
Vec4f color = model.diffuse(uv); // 从模型取得纹理颜色
45+
// 点乘 n,l 获得光照强度,Saturate 可以对范围 [0,1] 裁剪
46+
float intense = Saturate(vector_dot(n, l)) + 0.1;
47+
return color * intense;
48+
});
49+
50+
// 迭代模型每一个面
51+
for (int i = 0; i < model.nfaces(); i++) {
52+
// 设置三个顶点的输入,供 VS 读取
53+
for (int j = 0; j < 3; j++) {
54+
vs_input[j].pos = model.vert(i, j);
55+
vs_input[j].uv = model.uv(i, j);
56+
vs_input[j].normal = model.normal(i, j);
57+
}
58+
// 绘制三角形
59+
rh.DrawPrimitive();
60+
}
61+
62+
rh.SaveFile("output.bmp");
63+
64+
#if defined(WIN32) || defined(_WIN32)
65+
system("mspaint output.bmp");
66+
#endif
67+
68+
return 0;
69+
}
70+
71+

sample_06_normal.cpp

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include "RenderHelp.h"
2+
#include "Model.h"
3+
4+
5+
int main(void)
6+
{
7+
RenderHelp rh(600, 800);
8+
9+
// 加载模型
10+
Model model("res/diablo3_pose.obj");
11+
12+
Vec3f eye_pos = {0, -0.5, 1.7};
13+
Vec3f eye_at = {0, 0, 0};
14+
Vec3f eye_up = {0, 1, 0};
15+
Vec3f light_dir = {1, 1, 0.85}; // 光的方向
16+
float perspective = 3.1415926f * 0.5f;
17+
18+
Mat4x4f mat_model = matrix_set_scale(1, 1, 1);
19+
Mat4x4f mat_view = matrix_set_lookat(eye_pos, eye_at, eye_up);
20+
Mat4x4f mat_proj = matrix_set_perspective(perspective, 6 / 8.0, 1.0, 500.0f);
21+
Mat4x4f mat_mvp = mat_model * mat_view * mat_proj;
22+
23+
// 用于将法向量从模型坐标系变换到世界坐标系
24+
Mat4x4f mat_model_it = matrix_invert(mat_model).Transpose();
25+
26+
// 顶点属性
27+
struct { Vec3f pos; Vec3f normal; Vec2f uv; } vs_input[3];
28+
29+
const int VARYING_UV = 0;
30+
31+
rh.SetVertexShader([&] (int index, ShaderContext& output) -> Vec4f {
32+
Vec4f pos = vs_input[index].pos.xyz1() * mat_mvp;
33+
output.varying_vec2f[VARYING_UV] = vs_input[index].uv;
34+
return pos;
35+
});
36+
37+
rh.SetPixelShader([&] (ShaderContext& input) -> Vec4f {
38+
Vec2f uv = input.varying_vec2f[VARYING_UV];
39+
// 归一化光的方向
40+
Vec3f l = vector_normalize(light_dir);
41+
// 从模型读取每个点的法向并变换到世界坐标系
42+
Vec3f n = (model.normal(uv).xyz1() * mat_model_it).xyz();
43+
// 点乘 n,l 获得光照强度,Saturate 可以对范围 [0,1] 裁剪
44+
float intense = Saturate(vector_dot(n, l) + 0.1f);
45+
Vec4f color = model.diffuse(uv);
46+
// 纹理乘以光的强度
47+
return color * intense;
48+
});
49+
50+
// 迭代模型每一个面
51+
for (int i = 0; i < model.nfaces(); i++) {
52+
// 设置三个顶点的输入,供 VS 读取
53+
for (int j = 0; j < 3; j++) {
54+
vs_input[j].pos = model.vert(i, j);
55+
vs_input[j].uv = model.uv(i, j);
56+
vs_input[j].normal = model.normal(i, j);
57+
}
58+
// 绘制三角形
59+
rh.DrawPrimitive();
60+
}
61+
62+
rh.SaveFile("output.bmp");
63+
64+
#if defined(WIN32) || defined(_WIN32)
65+
system("mspaint output.bmp");
66+
#endif
67+
68+
return 0;
69+
}
70+
71+

sample_07_specular.cpp

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#include "RenderHelp.h"
2+
#include "Model.h"
3+
4+
5+
int main(void)
6+
{
7+
RenderHelp rh(600, 800);
8+
9+
// 加载模型
10+
Model model("res/diablo3_pose.obj");
11+
12+
Vec3f eye_pos = {0, -0.5, 1.7};
13+
Vec3f eye_at = {0, 0, 0};
14+
Vec3f eye_up = {0, 1, 0};
15+
Vec3f light_dir = {1, 1, 0.85}; // 光的方向
16+
float perspective = 3.1415926f * 0.5f;
17+
18+
Mat4x4f mat_model = matrix_set_scale(1, 1, 1);
19+
Mat4x4f mat_view = matrix_set_lookat(eye_pos, eye_at, eye_up);
20+
Mat4x4f mat_proj = matrix_set_perspective(perspective, 6 / 8.0, 1.0, 500.0f);
21+
Mat4x4f mat_mvp = mat_model * mat_view * mat_proj;
22+
23+
// 用于将法向量从模型坐标系变换到世界坐标系
24+
Mat4x4f mat_model_it = matrix_invert(mat_model).Transpose();
25+
26+
// 顶点属性
27+
struct { Vec3f pos; Vec3f normal; Vec2f uv; } vs_input[3];
28+
29+
const int VARYING_UV = 0;
30+
const int VARYING_EYE = 1; // 眼睛相对顶点的位置
31+
32+
rh.SetVertexShader([&] (int index, ShaderContext& output) -> Vec4f {
33+
Vec4f pos = vs_input[index].pos.xyz1() * mat_mvp;
34+
// 将顶点位置从模型空间转换为世界坐标系
35+
Vec3f pos_world = (vs_input[index].pos.xyz1() * mat_model).xyz();
36+
// 计算模型顶点到眼睛的方向
37+
Vec3f eye_dir = eye_pos - pos_world;
38+
output.varying_vec2f[VARYING_UV] = vs_input[index].uv;
39+
output.varying_vec3f[VARYING_EYE] = eye_dir;
40+
return pos;
41+
});
42+
43+
rh.SetPixelShader([&] (ShaderContext& input) -> Vec4f {
44+
Vec2f uv = input.varying_vec2f[VARYING_UV];
45+
// 模型上当前点到眼睛的方向
46+
Vec3f eye_dir = input.varying_vec3f[VARYING_EYE];
47+
// 归一化光照方向
48+
Vec3f l = vector_normalize(light_dir);
49+
// 法向贴图取出法向并转换为世界坐标系
50+
Vec3f n = (model.normal(uv).xyz1() * mat_model_it).xyz();
51+
// 从模型中取出当前点的高光参数
52+
float s = model.Specular(uv);
53+
// 计算反射光线
54+
Vec3f r = vector_normalize(n * vector_dot(n, l) * 2.0f - l);
55+
// 计算高光
56+
float spec = Saturate(pow(vector_dot(r, eye_dir), s * 20) * 0.05);
57+
// 综合光照强度
58+
float intense = Saturate(vector_dot(n, l)) + 0.2f + spec;
59+
Vec4f color = model.diffuse(uv);
60+
return color * intense;
61+
});
62+
63+
// 迭代模型每一个面
64+
for (int i = 0; i < model.nfaces(); i++) {
65+
// 设置三个顶点的输入,供 VS 读取
66+
for (int j = 0; j < 3; j++) {
67+
vs_input[j].pos = model.vert(i, j);
68+
vs_input[j].uv = model.uv(i, j);
69+
vs_input[j].normal = model.normal(i, j);
70+
}
71+
// 绘制三角形
72+
rh.DrawPrimitive();
73+
}
74+
75+
rh.SaveFile("output.bmp");
76+
77+
#if defined(WIN32) || defined(_WIN32)
78+
system("mspaint output.bmp");
79+
#endif
80+
81+
return 0;
82+
}
83+
84+

0 commit comments

Comments
 (0)