summaryrefslogtreecommitdiff
path: root/tools/editor/plugins/baked_light_baker.h
blob: 58197283a2c9fb42a9316d9773093ea29efa25dc (plain)
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
#ifndef BAKED_LIGHT_BAKER_H
#define BAKED_LIGHT_BAKER_H

#include "scene/3d/baked_light_instance.h"
#include "scene/3d/light.h"
#include "scene/3d/mesh_instance.h"
#include "os/thread.h"

class BakedLightBaker {
public:

	enum {

		ATTENUATION_CURVE_LEN=256,
		OCTANT_POOL_CHUNK=1000000
	};

	//struct OctantLight {

	//	double accum[8][3];
	//};

	struct Octant {
		bool leaf;
		AABB aabb;
		uint16_t texture_x;
		uint16_t texture_y;
		int sampler_ofs;
		float normal_accum[8][3];
		double full_accum[3];
		int parent;
		union {
			struct {
				int next_leaf;
				float offset[3];
				int bake_neighbour;
				bool first_neighbour;
				double light_accum[8][3];
			};
			int children[8];
		};
	};

	struct OctantHash {

		int next;
		uint32_t hash;
		uint64_t value;

	};

	struct MeshTexture {

		Vector<uint8_t> tex;
		int tex_w,tex_h;

		_FORCE_INLINE_ void get_color(const Vector2& p_uv,Color& ret) {

			if (tex_w && tex_h) {

				int x = Math::fast_ftoi(Math::fposmod(p_uv.x,1.0)*tex_w);
				int y = Math::fast_ftoi(Math::fposmod(p_uv.y,1.0)*tex_w);
				x=CLAMP(x,0,tex_w-1);
				y=CLAMP(y,0,tex_h-1);
				const uint8_t*ptr = &tex[(y*tex_w+x)*4];
				ret.r*=ptr[0]/255.0;
				ret.g*=ptr[1]/255.0;
				ret.b*=ptr[2]/255.0;
				ret.a*=ptr[3]/255.0;
			}
		}

	};

	struct Param {

		Color color;
		MeshTexture*tex;
		_FORCE_INLINE_ Color get_color(const Vector2& p_uv) {

			Color ret=color;
			if (tex)
				tex->get_color(p_uv,ret);
			return ret;

		}

	};

	struct MeshMaterial {

		Param diffuse;
		Param specular;
		Param emission;
		
		bool is_double_sided;
		bool use_alpha;
	};

	struct Triangle {

		AABB aabb;	
		Vector3 vertices[3];
		Vector2 uvs[3];
		Vector2 bake_uvs[3];
		Vector3 normals[3];
		MeshMaterial *material;
		int baked_texture;

		_FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos) {

			Vector3 v0 = vertices[1] - vertices[0];
			Vector3 v1 = vertices[2] - vertices[0];
			Vector3 v2 = p_pos - vertices[0];

			float d00 = v0.dot( v0);
			float d01 = v0.dot( v1);
			float d11 = v1.dot( v1);
			float d20 = v2.dot( v0);
			float d21 = v2.dot( v1);
			float denom = (d00 * d11 - d01 * d01);
			if (denom==0)
				return uvs[0];
			float v = (d11 * d20 - d01 * d21) / denom;
			float w = (d00 * d21 - d01 * d20) / denom;
			float u = 1.0f - v - w;

			return uvs[0]*u + uvs[1]*v  + uvs[2]*w;
		}

		_FORCE_INLINE_ void get_uv_and_normal(const Vector3& p_pos,Vector2& r_uv,Vector3& r_normal) {

			Vector3 v0 = vertices[1] - vertices[0];
			Vector3 v1 = vertices[2] - vertices[0];
			Vector3 v2 = p_pos - vertices[0];

			float d00 = v0.dot( v0);
			float d01 = v0.dot( v1);
			float d11 = v1.dot( v1);
			float d20 = v2.dot( v0);
			float d21 = v2.dot( v1);
			float denom = (d00 * d11 - d01 * d01);
			if (denom==0) {
				r_normal=normals[0];
				r_uv=uvs[0];
				return;
			}
			float v = (d11 * d20 - d01 * d21) / denom;
			float w = (d00 * d21 - d01 * d20) / denom;
			float u = 1.0f - v - w;

			r_uv=uvs[0]*u + uvs[1]*v  + uvs[2]*w;
			r_normal=(normals[0]*u+normals[1]*v+normals[2]*w).normalized();
		}
	};


	struct BVH {

		int id;
		AABB aabb;
		Vector3 center;
		Triangle *leaf;
		BVH*children[2];
	};


	struct BVHCmpX {

		bool operator()(const BVH* p_left, const BVH* p_right) const {

			return p_left->center.x < p_right->center.x;
		}
	};

	struct BVHCmpY {

		bool operator()(const BVH* p_left, const BVH* p_right) const {

			return p_left->center.y < p_right->center.y;
		}
	};
	struct BVHCmpZ {

		bool operator()(const BVH* p_left, const BVH* p_right) const {

			return p_left->center.z < p_right->center.z;
		}
	};

	struct BakeTexture {

		Vector<uint8_t> data;
		int width,height;
	};


	struct LightData {

		VS::LightType type;

		Vector3 pos;
		Vector3 up;
		Vector3 left;
		Vector3 dir;
		Color diffuse;
		Color specular;
		float energy;
		float length;
		int rays_thrown;
		bool bake_shadow;

		float radius;
		float attenuation;
		float spot_angle;
		float darkening;
		float spot_attenuation;
		float area;

		float constant;

		bool bake_direct;

		Vector<float> attenuation_table;

	};


	Vector<LightData> lights;

	List<MeshMaterial> materials;
	List<MeshTexture> textures;

	AABB octree_aabb;
	Vector<Octant> octant_pool;
	int octant_pool_size;
	BVH*bvh;
	Vector<Triangle> triangles;
	Vector<BakeTexture> baked_textures;
	Transform base_inv;
	int leaf_list;
	int octree_depth;
	int bvh_depth;
	int cell_count;
	uint32_t *ray_stack;
	BVH **bvh_stack;
	uint32_t *octant_stack;
	uint32_t *octantptr_stack;

	struct ThreadStack {
		uint32_t *octant_stack;
		uint32_t *octantptr_stack;
		uint32_t *ray_stack;
		BVH **bvh_stack;
	};

	Map<Vector3,Vector3> endpoint_normal;
	Map<Vector3,uint64_t> endpoint_normal_bits;

	float cell_size;
	float plot_size; //multiplied by cell size
	float octree_extra_margin;

	int max_bounces;
	int64_t total_rays;
	bool use_diffuse;
	bool use_specular;
	bool use_translucency;
	bool linear_color;


	int baked_octree_texture_w;
	int baked_octree_texture_h;
	int baked_light_texture_w;
	int baked_light_texture_h;
	int lattice_size;
	float edge_damp;
	float normal_damp;
	float tint;
	float ao_radius;
	float ao_strength;

	bool paused;
	bool baking;
	bool first_bake_to_map;

	Map<Ref<Material>,MeshMaterial*> mat_map;
	Map<Ref<Texture>,MeshTexture*> tex_map;



	MeshTexture* _get_mat_tex(const Ref<Texture>& p_tex);
	void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform,int p_baked_texture=-1);
	void _parse_geometry(Node* p_node);
	BVH* _parse_bvh(BVH** p_children,int p_size,int p_depth,int& max_depth);
	void _make_bvh();
	void _make_octree();
	void _make_octree_texture();
	void _octree_insert(int p_octant, Triangle* p_triangle, int p_depth);
	_FORCE_INLINE_ void _plot_pixel_to_lightmap(int x, int y, int width, int height, uint8_t *image, const Vector3& p_pos,const Vector3& p_normal,double *p_norm_ptr,float mult,float gamma);


	void _free_bvh(BVH* p_bvh);

	void _fix_lights();

	Ref<BakedLight> baked_light;


	//void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,int p_octant=0);
	void _plot_light(ThreadStack& thread_stack,const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,const Color& p_tint_light,bool p_only_full,const Plane& p_plane);
	//void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light);

	float _throw_ray(ThreadStack& thread_stack,bool p_bake_direct,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce=false,bool p_only_dist=false, Vector<int>&p_ignore_list=Vector<int>());


	float total_light_area;

	Vector<Thread*> threads;

	bool bake_thread_exit;
	static void _bake_thread_func(void *arg);

	void _start_thread();
	void _stop_thread();
public:


	void throw_rays(ThreadStack &thread_stack, int p_amount);
	double get_normalization(int p_light_idx) const;
	double get_modifier(int p_light_idx) const;

	void bake(const Ref<BakedLight>& p_light,Node *p_base);
	bool is_baking();
	void set_pause(bool p_pause);
	bool is_paused();
	uint64_t get_rays_thrown() { return total_rays; }

	Error transfer_to_lightmaps();

	void update_octree_sampler(DVector<int> &p_sampler);
	void update_octree_images(DVector<uint8_t> &p_octree,DVector<uint8_t> &p_light);

	Ref<BakedLight> get_baked_light() { return baked_light; }

	void clear();

	BakedLightBaker();
	~BakedLightBaker();

};

#endif // BAKED_LIGHT_BAKER_H