1 /****************************************************************************
2  * 			scene.cc: scene_t controls the rendering of a scene
3  *      This is part of the yafray package
4  *      Copyright (C) 2006  Mathias Wein
5  *
6  *      This library is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU Lesser General Public
8  *      License as published by the Free Software Foundation; either
9  *      version 2.1 of the License, or (at your option) any later version.
10  *
11  *      This library is distributed in the hope that it will be useful,
12  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *      Lesser General Public License for more details.
15  *
16  *      You should have received a copy of the GNU Lesser General Public
17  *      License along with this library; if not, write to the Free Software
18  *      Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 #include <core_api/scene.h>
22 #include <core_api/environment.h>
23 #include <core_api/logging.h>
24 #include <core_api/object3d.h>
25 #include <core_api/material.h>
26 #include <core_api/light.h>
27 #include <core_api/integrator.h>
28 #include <core_api/imagefilm.h>
29 #include <core_api/sysinfo.h>
30 #include <yafraycore/triangle.h>
31 #include <yafraycore/ray_kdtree.h>
32 #include <iostream>
33 #include <limits>
34 #include <sstream>
35 
36 __BEGIN_YAFRAY
37 
scene_t(const renderEnvironment_t * render_environment)38 scene_t::scene_t(const renderEnvironment_t *render_environment):  volIntegrator(nullptr), camera(nullptr), imageFilm(nullptr), tree(nullptr), vtree(nullptr), background(nullptr), surfIntegrator(nullptr),	AA_samples(1), AA_passes(1), AA_threshold(0.05), nthreads(1), nthreads_photons(1), mode(1), signals(0), env(render_environment)
39 {
40 	state.changes = C_ALL;
41 	state.stack.push_front(READY);
42 	state.nextFreeID = std::numeric_limits<int>::max();
43 	state.curObj = nullptr;
44 
45 	AA_resampled_floor = 0.f;
46 	AA_sample_multiplier_factor = 1.f;
47 	AA_light_sample_multiplier_factor = 1.f;
48 	AA_indirect_sample_multiplier_factor = 1.f;
49 	AA_detect_color_noise = false;
50 	AA_dark_threshold_factor = 0.f;
51 	AA_variance_edge_size = 10;
52 	AA_variance_pixels = 0;
53 	AA_clamp_samples = 0.f;
54 	AA_clamp_indirect = 0.f;
55 }
56 
scene_t(const scene_t & s)57 scene_t::scene_t(const scene_t &s)
58 {
59 	Y_ERROR << "Scene: You may NOT use the copy constructor!" << yendl;
60 }
61 
~scene_t()62 scene_t::~scene_t()
63 {
64 	if(tree) delete tree;
65 	if(vtree) delete vtree;
66 	for(auto i = meshes.begin(); i != meshes.end(); ++i)
67 	{
68 		if(i->second.type == TRIM)
69 			delete i->second.obj;
70 		else
71 			delete i->second.mobj;
72 	}
73 }
74 
abort()75 void scene_t::abort()
76 {
77 	sig_mutex.lock();
78 	signals |= Y_SIG_ABORT;
79 	sig_mutex.unlock();
80 }
81 
getSignals() const82 int scene_t::getSignals() const
83 {
84 	int sig;
85 	sig_mutex.lock();
86 	sig = signals;
87 	sig_mutex.unlock();
88 	return sig;
89 }
90 
getAAParameters(int & samples,int & passes,int & inc_samples,float & threshold,float & resampled_floor,float & sample_multiplier_factor,float & light_sample_multiplier_factor,float & indirect_sample_multiplier_factor,bool & detect_color_noise,int & dark_detection_type,float & dark_threshold_factor,int & variance_edge_size,int & variance_pixels,float & clamp_samples,float & clamp_indirect) const91 void scene_t::getAAParameters(int &samples, int &passes, int &inc_samples, float &threshold, float &resampled_floor, float &sample_multiplier_factor, float &light_sample_multiplier_factor, float &indirect_sample_multiplier_factor, bool &detect_color_noise, int &dark_detection_type, float &dark_threshold_factor, int &variance_edge_size, int &variance_pixels, float &clamp_samples, float &clamp_indirect) const
92 {
93 	samples = AA_samples;
94 	passes = AA_passes;
95 	inc_samples = AA_inc_samples;
96 	threshold = AA_threshold;
97 	resampled_floor = AA_resampled_floor;
98 	sample_multiplier_factor = AA_sample_multiplier_factor;
99 	light_sample_multiplier_factor = AA_light_sample_multiplier_factor;
100 	indirect_sample_multiplier_factor = AA_indirect_sample_multiplier_factor;
101 	detect_color_noise = AA_detect_color_noise;
102 	dark_detection_type = AA_dark_detection_type;
103 	dark_threshold_factor = AA_dark_threshold_factor;
104 	variance_edge_size = AA_variance_edge_size;
105 	variance_pixels = AA_variance_pixels;
106 	clamp_samples = AA_clamp_samples;
107 	clamp_indirect = AA_clamp_indirect;
108 }
109 
startGeometry()110 bool scene_t::startGeometry()
111 {
112 	if(state.stack.front() != READY) return false;
113 	state.stack.push_front(GEOMETRY);
114 	return true;
115 }
116 
endGeometry()117 bool scene_t::endGeometry()
118 {
119 	if(state.stack.front() != GEOMETRY) return false;
120 	// in case objects share arrays, so they all need to be updated
121 	// after each object change, uncomment the below block again:
122 	// don't forget to update the mesh object iterators!
123 /*	for(auto i=meshes.begin();
124 		 i!=meshes.end(); ++i)
125 	{
126 		objData_t &dat = (*i).second;
127 		dat.obj->setContext(dat.points.begin(), dat.normals.begin() );
128 	}*/
129 	state.stack.pop_front();
130 	return true;
131 }
132 
startCurveMesh(objID_t id,int vertices,int obj_pass_index)133 bool scene_t::startCurveMesh(objID_t id, int vertices, int obj_pass_index)
134 {
135 	if(state.stack.front() != GEOMETRY) return false;
136 	int ptype = 0 & 0xFF;
137 
138 	objData_t &nObj = meshes[id];
139 
140 	//TODO: switch?
141 	// Allocate triangles to render the curve
142 	nObj.obj = new triangleObject_t( 2 * (vertices-1) , true, false);
143 	nObj.obj->setObjectIndex(obj_pass_index);
144 	nObj.type = ptype;
145 	state.stack.push_front(OBJECT);
146 	state.changes |= C_GEOM;
147 	state.orco=false;
148 	state.curObj = &nObj;
149 
150 	nObj.obj->points.reserve(2*vertices);
151 	return true;
152 }
153 
endCurveMesh(const material_t * mat,float strandStart,float strandEnd,float strandShape)154 bool scene_t::endCurveMesh(const material_t *mat, float strandStart, float strandEnd, float strandShape)
155 {
156 	if(state.stack.front() != OBJECT) return false;
157 
158 	// TODO: Check if we have at least 2 vertex...
159 	// TODO: math optimizations
160 
161 	// extrude vertices and create faces
162 	std::vector<point3d_t> &points = state.curObj->obj->points;
163 	float r;	//current radius
164 	int i;
165 	point3d_t o,a,b;
166 	vector3d_t N(0),u(0),v(0);
167 	int n = points.size();
168 	// Vertex extruding
169 	for (i=0;i<n;i++){
170 		o = points[i];
171 		if (strandShape < 0)
172 		{
173 			r = strandStart + pow((float)i/(n-1) ,1+strandShape) * ( strandEnd - strandStart );
174 		}
175 		else
176 		{
177 			r = strandStart + (1 - pow(((float)(n-i-1))/(n-1) ,1-strandShape)) * ( strandEnd - strandStart );
178 		}
179 		// Last point keep previous tangent plane
180 		if (i<n-1)
181 		{
182 			N = points[i+1]-points[i];
183 			N.normalize();
184 			createCS(N,u,v);
185 		}
186 		// TODO: thikness?
187 		a = o - (0.5 * r *v) - 1.5 * r / sqrt(3.f) * u;
188 		b = o - (0.5 * r *v) + 1.5 * r / sqrt(3.f) * u;
189 
190 		state.curObj->obj->points.push_back(a);
191 		state.curObj->obj->points.push_back(b);
192 	}
193 
194 	// Face fill
195 	triangle_t tri;
196 	int a1,a2,a3,b1,b2,b3;
197 	float su,sv;
198 	int iu,iv;
199 	for (i=0;i<n-1;i++){
200 		// 1D particles UV mapping
201 		su = (float)i / (n-1);
202 		sv = su + 1. / (n-1);
203 		iu = addUV(su,su);
204 		iv = addUV(sv,sv);
205 		a1 = i;
206 		a2 = 2*i+n;
207 		a3 = a2 +1;
208 		b1 = i+1;
209 		b2 = a2 +2;
210 		b3 = b2 +1;
211 		// Close bottom
212 		if (i == 0)
213 		{
214 			tri = triangle_t(a1, a3, a2, state.curObj->obj);
215 			tri.setMaterial(mat);
216 			state.curTri = state.curObj->obj->addTriangle(tri);
217 			state.curObj->obj->uv_offsets.push_back(iu);
218 			state.curObj->obj->uv_offsets.push_back(iu);
219 			state.curObj->obj->uv_offsets.push_back(iu);
220 		}
221 
222 		// Fill
223 		tri = triangle_t(a1, b2, b1, state.curObj->obj);
224 		tri.setMaterial(mat);
225 		state.curTri = state.curObj->obj->addTriangle(tri);
226 		// StrandUV
227 		state.curObj->obj->uv_offsets.push_back(iu);
228 		state.curObj->obj->uv_offsets.push_back(iv);
229 		state.curObj->obj->uv_offsets.push_back(iv);
230 
231 		tri = triangle_t(a1, a2, b2, state.curObj->obj);
232 		tri.setMaterial(mat);
233 		state.curTri = state.curObj->obj->addTriangle(tri);
234 		state.curObj->obj->uv_offsets.push_back(iu);
235 		state.curObj->obj->uv_offsets.push_back(iu);
236 		state.curObj->obj->uv_offsets.push_back(iv);
237 
238 		tri = triangle_t(a2, b3, b2, state.curObj->obj);
239 		tri.setMaterial(mat);
240 		state.curTri = state.curObj->obj->addTriangle(tri);
241 		state.curObj->obj->uv_offsets.push_back(iu);
242 		state.curObj->obj->uv_offsets.push_back(iv);
243 		state.curObj->obj->uv_offsets.push_back(iv);
244 
245 		tri = triangle_t(a2, a3, b3, state.curObj->obj);
246 		tri.setMaterial(mat);
247 		state.curTri = state.curObj->obj->addTriangle(tri);
248 		state.curObj->obj->uv_offsets.push_back(iu);
249 		state.curObj->obj->uv_offsets.push_back(iu);
250 		state.curObj->obj->uv_offsets.push_back(iv);
251 
252 		tri = triangle_t(b3, a3, a1, state.curObj->obj);
253 		tri.setMaterial(mat);
254 		state.curTri = state.curObj->obj->addTriangle(tri);
255 		state.curObj->obj->uv_offsets.push_back(iv);
256 		state.curObj->obj->uv_offsets.push_back(iu);
257 		state.curObj->obj->uv_offsets.push_back(iu);
258 
259 		tri = triangle_t(b3, a1, b1, state.curObj->obj);
260 		tri.setMaterial(mat);
261 		state.curTri = state.curObj->obj->addTriangle(tri);
262 		state.curObj->obj->uv_offsets.push_back(iv);
263 		state.curObj->obj->uv_offsets.push_back(iu);
264 		state.curObj->obj->uv_offsets.push_back(iv);
265 
266 	}
267 	// Close top
268 	tri = triangle_t(i, 2*i+n, 2*i+n+1, state.curObj->obj);
269 	tri.setMaterial(mat);
270 	state.curTri = state.curObj->obj->addTriangle(tri);
271 	state.curObj->obj->uv_offsets.push_back(iv);
272 	state.curObj->obj->uv_offsets.push_back(iv);
273 	state.curObj->obj->uv_offsets.push_back(iv);
274 
275 	state.curObj->obj->finish();
276 
277 	state.stack.pop_front();
278 	return true;
279 }
280 
startTriMesh(objID_t id,int vertices,int triangles,bool hasOrco,bool hasUV,int type,int obj_pass_index)281 bool scene_t::startTriMesh(objID_t id, int vertices, int triangles, bool hasOrco, bool hasUV, int type, int obj_pass_index)
282 {
283 	if(state.stack.front() != GEOMETRY) return false;
284 	int ptype = type & 0xFF;
285 	if(ptype != TRIM && type != VTRIM && type != MTRIM) return false;
286 
287 	objData_t &nObj = meshes[id];
288 	switch(ptype)
289 	{
290 		case TRIM:	nObj.obj = new triangleObject_t(triangles, hasUV, hasOrco);
291 					nObj.obj->setVisibility( !(type & INVISIBLEM) );
292 					nObj.obj->useAsBaseObject( (type & BASEMESH) );
293 					nObj.obj->setObjectIndex(obj_pass_index);
294 					break;
295 		case VTRIM:
296 		case MTRIM:	nObj.mobj = new meshObject_t(triangles, hasUV, hasOrco);
297 					nObj.mobj->setVisibility( !(type & INVISIBLEM) );
298 					nObj.obj->setObjectIndex(obj_pass_index);
299 					break;
300 		default: return false;
301 	}
302 	nObj.type = ptype;
303 	state.stack.push_front(OBJECT);
304 	state.changes |= C_GEOM;
305 	state.orco=hasOrco;
306 	state.curObj = &nObj;
307 
308 	return true;
309 }
310 
endTriMesh()311 bool scene_t::endTriMesh()
312 {
313 	if(state.stack.front() != OBJECT) return false;
314 
315 	if(state.curObj->type == TRIM)
316 	{
317 		if(state.curObj->obj->has_uv)
318 		{
319 			if( state.curObj->obj->uv_offsets.size() != 3*state.curObj->obj->triangles.size() )
320 			{
321 				Y_ERROR << "Scene: UV-offsets mismatch!" << yendl;
322 				return false;
323 			}
324 		}
325 
326 		//calculate geometric normals of tris
327 		state.curObj->obj->finish();
328 	}
329 	else
330 	{
331 		state.curObj->mobj->finish();
332 	}
333 
334 	state.stack.pop_front();
335 	return true;
336 }
337 
setNumThreads(int threads)338 void scene_t::setNumThreads(int threads)
339 {
340 	nthreads = threads;
341 
342 	if(nthreads == -1) //Automatic detection of number of threads supported by this system, taken from Blender. (DT)
343 	{
344 		Y_VERBOSE << "Automatic Detection of Threads: Active." << yendl;
345 		const sysInfo_t sys_info;
346 		nthreads = sys_info.getNumSystemThreads();
347 		Y_VERBOSE << "Number of Threads supported: [" << nthreads << "]." << yendl;
348 	}
349 	else
350 	{
351 		Y_VERBOSE << "Automatic Detection of Threads: Inactive." << yendl;
352 	}
353 
354 	Y_PARAMS << "Using [" << nthreads << "] Threads." << yendl;
355 
356 	std::stringstream set;
357 	set << "CPU threads=" << nthreads << std::endl;
358 
359 	yafLog.appendRenderSettings(set.str());
360 }
361 
setNumThreadsPhotons(int threads_photons)362 void scene_t::setNumThreadsPhotons(int threads_photons)
363 {
364 	nthreads_photons = threads_photons;
365 
366 	if(nthreads_photons == -1) //Automatic detection of number of threads supported by this system, taken from Blender. (DT)
367 	{
368 		Y_VERBOSE << "Automatic Detection of Threads for Photon Mapping: Active." << yendl;
369 		const sysInfo_t sys_info;
370 		nthreads_photons = sys_info.getNumSystemThreads();
371 		Y_VERBOSE << "Number of Threads supported for Photon Mapping: [" << nthreads_photons << "]." << yendl;
372 	}
373 	else
374 	{
375 		Y_VERBOSE << "Automatic Detection of Threads for Photon Mapping: Inactive." << yendl;
376 	}
377 
378 	Y_PARAMS << "Using for Photon Mapping [" << nthreads_photons << "] Threads." << yendl;
379 }
380 
381 #define prepareEdges(q, v1, v2) e1 = vertices[v1] - vertices[q]; \
382 			e2 = vertices[v2] - vertices[q];
383 
smoothMesh(objID_t id,float angle)384 bool scene_t::smoothMesh(objID_t id, float angle)
385 {
386 	if( state.stack.front() != GEOMETRY ) return false;
387 	objData_t *odat;
388 	if(id)
389 	{
390 		auto it = meshes.find(id);
391 		if(it == meshes.end() ) return false;
392 		odat = &(it->second);
393 	}
394 	else
395 	{
396 		odat = state.curObj;
397 		if(!odat) return false;
398 	}
399 
400 	if(odat->obj->normals_exported && odat->obj->points.size() == odat->obj->normals.size())
401 	{
402 		odat->obj->is_smooth = true;
403 		return true;
404 	}
405 
406 	// cannot smooth other mesh types yet...
407 	if(odat->type > 0) return false;
408 	unsigned int idx = 0;
409 	std::vector<normal_t> &normals = odat->obj->normals;
410 	std::vector<triangle_t> &triangles = odat->obj->triangles;
411 	size_t points = odat->obj->points.size();
412 	std::vector<triangle_t>::iterator tri;
413 	std::vector<point3d_t> const &vertices = odat->obj->points;
414 
415     normals.reserve(points);
416     normals.resize(points, normal_t(0,0,0));
417 
418 	if (angle>=180)
419 	{
420 		for (tri=triangles.begin(); tri!=triangles.end(); ++tri)
421 		{
422 
423 			vector3d_t n = tri->getNormal();
424 			vector3d_t e1, e2;
425 			float alpha = 0;
426 
427 			prepareEdges(tri->pa, tri->pb, tri->pc)
428             alpha = e1.sinFromVectors(e2);
429 
430             normals[tri->pa] += n * alpha;
431 
432 			prepareEdges(tri->pb, tri->pa, tri->pc)
433             alpha = e1.sinFromVectors(e2);
434 
435             normals[tri->pb] += n * alpha;
436 
437 			prepareEdges(tri->pc, tri->pa, tri->pb)
438             alpha = e1.sinFromVectors(e2);
439 
440             normals[tri->pc] += n * alpha;
441 
442             tri->setNormals(tri->pa, tri->pb, tri->pc);
443   		}
444 
445 		for (idx=0;idx<normals.size();++idx) normals[idx].normalize();
446 
447 	}
448 	else if(angle>0.1)// angle dependant smoothing
449 	{
450 		float thresh = fCos(degToRad(angle));
451 		std::vector<vector3d_t> vnormals;
452 		std::vector<int> vn_index;
453 		// create list of faces that include given vertex
454 		std::vector<std::vector<triangle_t*> > vface(points);
455 		std::vector<std::vector<float> > alphas(points);
456 		for (tri=triangles.begin(); tri!=triangles.end(); ++tri)
457 		{
458 			vector3d_t e1, e2;
459 
460 			prepareEdges(tri->pa, tri->pb, tri->pc)
461             alphas[tri->pa].push_back(e1.sinFromVectors(e2));
462             vface[tri->pa].push_back(&(*tri));
463 
464 			prepareEdges(tri->pb, tri->pa, tri->pc)
465             alphas[tri->pb].push_back(e1.sinFromVectors(e2));
466 			vface[tri->pb].push_back(&(*tri));
467 
468 			prepareEdges(tri->pc, tri->pa, tri->pb)
469             alphas[tri->pc].push_back(e1.sinFromVectors(e2));
470             vface[tri->pc].push_back(&(*tri));
471 		}
472 		for(int i=0; i<(int)vface.size(); ++i)
473 		{
474 			std::vector<triangle_t*> &tris = vface[i];
475 			int j = 0;
476 			for(auto fi=tris.begin(); fi!=tris.end(); ++fi)
477 			{
478 				triangle_t* f = *fi;
479 				bool smooth = false;
480 				// calculate vertex normal for face
481 				vector3d_t vnorm, fnorm;
482 
483 				fnorm = f->getNormal();
484 				vnorm = fnorm * alphas[i][j];
485                 int k = 0;
486 				for(auto f2=tris.begin(); f2!=tris.end(); ++f2)
487 				{
488 					if(**fi == **f2)
489 					{
490                         k++;
491                         continue;
492 					}
493 					vector3d_t f2norm = (*f2)->getNormal();
494 					if((fnorm * f2norm) > thresh)
495 					{
496 						smooth = true;
497 						vnorm += f2norm * alphas[i][k];
498 					}
499 					k++;
500 				}
501 				int n_idx = -1;
502 				if(smooth)
503 				{
504 					vnorm.normalize();
505 					//search for existing normal
506 					for(unsigned int l=0; l<vnormals.size(); ++l)
507 					{
508 						if(vnorm*vnormals[l] > 0.999)
509                         {
510                             n_idx = vn_index[l];
511                             break;
512                         }
513 					}
514 					// create new if none found
515 					if(n_idx == -1)
516 					{
517 						n_idx = normals.size();
518 						vnormals.push_back(vnorm);
519 						vn_index.push_back(n_idx);
520 						normals.push_back( normal_t(vnorm) );
521 					}
522 				}
523 				// set vertex normal to idx
524 				if	   (f->pa == i) f->na = n_idx;
525 				else if(f->pb == i) f->nb = n_idx;
526 				else if(f->pc == i) f->nc = n_idx;
527 				else
528 				{
529 					Y_ERROR << "Scene: Mesh smoothing error!" << yendl;
530 					return false;
531 				}
532 				j++;
533 			}
534 			vnormals.clear();
535 			vn_index.clear();
536 		}
537 	}
538 
539     odat->obj->is_smooth = true;
540 
541 	return true;
542 }
543 
addVertex(const point3d_t & p)544 int scene_t::addVertex(const point3d_t &p)
545 {
546 	if(state.stack.front() != OBJECT) return -1;
547 	state.curObj->obj->points.push_back(p);
548 	if(state.curObj->type == MTRIM)
549 	{
550 		std::vector<point3d_t> &points = state.curObj->mobj->points;
551 		int n = points.size();
552 		if(n%3==0)
553 		{
554 			//convert point 2 to quadratic bezier control point
555 			points[n-2] = 2.f*points[n-2] - 0.5f*(points[n-3] + points[n-1]);
556 		}
557 		return (n-1)/3;
558 	}
559 
560 	state.curObj->lastVertId = state.curObj->obj->points.size()-1;
561 
562 	return state.curObj->lastVertId;
563 }
564 
addVertex(const point3d_t & p,const point3d_t & orco)565 int scene_t::addVertex(const point3d_t &p, const point3d_t &orco)
566 {
567 	if(state.stack.front() != OBJECT) return -1;
568 
569 	switch(state.curObj->type)
570 	{
571 		case TRIM:
572 			state.curObj->obj->points.push_back(p);
573 			state.curObj->obj->points.push_back(orco);
574 			state.curObj->lastVertId = (state.curObj->obj->points.size()-1) / 2;
575 			break;
576 
577 		case VTRIM:
578 			state.curObj->mobj->points.push_back(p);
579 			state.curObj->mobj->points.push_back(orco);
580 			state.curObj->lastVertId = (state.curObj->mobj->points.size()-1) / 2;
581 			break;
582 
583 		case MTRIM:
584 			return addVertex(p);
585 	}
586 
587 	return state.curObj->lastVertId;
588 }
589 
addNormal(const normal_t & n)590 void scene_t::addNormal(const normal_t& n)
591 {
592 	if(mode != 0)
593 	{
594 		Y_WARNING << "Normal exporting is only supported for triangle mode" << yendl;
595 		return;
596 	}
597 	if(state.curObj->obj->points.size() > state.curObj->lastVertId && state.curObj->obj->points.size() > state.curObj->obj->normals.size())
598 	{
599 		if(state.curObj->obj->normals.size() < state.curObj->obj->points.size())
600 			state.curObj->obj->normals.resize(state.curObj->obj->points.size());
601 
602 		state.curObj->obj->normals[state.curObj->lastVertId] = n;
603 		state.curObj->obj->normals_exported = true;
604 	}
605 }
606 
addTriangle(int a,int b,int c,const material_t * mat)607 bool scene_t::addTriangle(int a, int b, int c, const material_t *mat)
608 {
609 	if(state.stack.front() != OBJECT) return false;
610 	if(state.curObj->type == MTRIM)
611 	{
612 		bsTriangle_t tri(3*a, 3*b, 3*c, state.curObj->mobj);
613 		tri.setMaterial(mat);
614 		state.curObj->mobj->addBsTriangle(tri);
615 	}
616 	else if(state.curObj->type == VTRIM)
617 	{
618 		if(state.orco) a*=2, b*=2, c*=2;
619 		vTriangle_t tri(a, b, c, state.curObj->mobj);
620 		tri.setMaterial(mat);
621 		state.curObj->mobj->addTriangle(tri);
622 	}
623 	else
624 	{
625 		if(state.orco) a*=2, b*=2, c*=2;
626 		triangle_t tri(a, b, c, state.curObj->obj);
627 		tri.setMaterial(mat);
628 		if(state.curObj->obj->normals_exported)
629 		{
630 			if(state.orco)
631 			{
632 				// Since the vertex indexes are duplicated with orco
633 				// we divide by 2: a / 2 == a >> 1 since is an integer division
634 				tri.na = a >> 1;
635 				tri.nb = b >> 1;
636 				tri.nc = c >> 1;
637 			}
638 			else
639 			{
640 				tri.na = a;
641 				tri.nb = b;
642 				tri.nc = c;
643 			}
644 		}
645 		state.curTri = state.curObj->obj->addTriangle(tri);
646 	}
647 	return true;
648 }
649 
addTriangle(int a,int b,int c,int uv_a,int uv_b,int uv_c,const material_t * mat)650 bool scene_t::addTriangle(int a, int b, int c, int uv_a, int uv_b, int uv_c, const material_t *mat)
651 {
652 	if(!addTriangle(a, b, c, mat)) return false;
653 
654 	if(state.curObj->type == TRIM)
655 	{
656 		state.curObj->obj->uv_offsets.push_back(uv_a);
657 		state.curObj->obj->uv_offsets.push_back(uv_b);
658 		state.curObj->obj->uv_offsets.push_back(uv_c);
659 	}
660 	else
661 	{
662 		state.curObj->mobj->uv_offsets.push_back(uv_a);
663 		state.curObj->mobj->uv_offsets.push_back(uv_b);
664 		state.curObj->mobj->uv_offsets.push_back(uv_c);
665 	}
666 
667 	return true;
668 }
669 
addUV(float u,float v)670 int scene_t::addUV(float u, float v)
671 {
672 	if(state.stack.front() != OBJECT) return false;
673 	if(state.curObj->type == TRIM)
674 	{
675 		state.curObj->obj->uv_values.push_back(uv_t(u, v));
676 		return (int)state.curObj->obj->uv_values.size()-1;
677 	}
678 	else
679 	{
680 		state.curObj->mobj->uv_values.push_back(uv_t(u, v));
681 		return (int)state.curObj->mobj->uv_values.size()-1;
682 	}
683 	return -1;
684 }
685 
addLight(light_t * l)686 bool scene_t::addLight(light_t *l)
687 {
688 	if(l != 0)
689 	{
690 		if(!l->lightEnabled()) return false; //if a light is disabled, don't add it to the list of lights
691 		lights.push_back(l);
692 		state.changes |= C_LIGHT;
693 		return true;
694 	}
695 	return false;
696 }
697 
setCamera(camera_t * cam)698 void scene_t::setCamera(camera_t *cam)
699 {
700 	camera = cam;
701 }
702 
setImageFilm(imageFilm_t * film)703 void scene_t::setImageFilm(imageFilm_t *film)
704 {
705 	imageFilm = film;
706 }
707 
setBackground(background_t * bg)708 void scene_t::setBackground(background_t *bg)
709 {
710 	background = bg;
711 }
712 
setSurfIntegrator(surfaceIntegrator_t * s)713 void scene_t::setSurfIntegrator(surfaceIntegrator_t *s)
714 {
715 	surfIntegrator = s;
716 	surfIntegrator->setScene(this);
717 	state.changes |= C_OTHER;
718 }
719 
setVolIntegrator(volumeIntegrator_t * v)720 void scene_t::setVolIntegrator(volumeIntegrator_t *v)
721 {
722 	volIntegrator = v;
723 	volIntegrator->setScene(this);
724 	state.changes |= C_OTHER;
725 }
726 
getBackground() const727 background_t* scene_t::getBackground() const
728 {
729 	return background;
730 }
731 
getMesh(objID_t id) const732 triangleObject_t* scene_t::getMesh(objID_t id) const
733 {
734 	auto i = meshes.find(id);
735 	return (i==meshes.end()) ? 0 : i->second.obj;
736 }
737 
getObject(objID_t id) const738 object3d_t* scene_t::getObject(objID_t id) const
739 {
740 	auto i = meshes.find(id);
741 	if(i != meshes.end())
742 	{
743 		if(i->second.type == TRIM) return i->second.obj;
744 		else return i->second.mobj;
745 	}
746 	else
747 	{
748 		auto oi = objects.find(id);
749 		if(oi != objects.end() ) return oi->second;
750 	}
751 	return nullptr;
752 }
753 
getSceneBound() const754 bound_t scene_t::getSceneBound() const
755 {
756 	return sceneBound;
757 }
758 
setAntialiasing(int numSamples,int numPasses,int incSamples,double threshold,float resampled_floor,float sample_multiplier_factor,float light_sample_multiplier_factor,float indirect_sample_multiplier_factor,bool detect_color_noise,int dark_detection_type,float dark_threshold_factor,int variance_edge_size,int variance_pixels,float clamp_samples,float clamp_indirect)759 void scene_t::setAntialiasing(int numSamples, int numPasses, int incSamples, double threshold, float resampled_floor, float sample_multiplier_factor, float light_sample_multiplier_factor, float indirect_sample_multiplier_factor, bool detect_color_noise, int dark_detection_type, float dark_threshold_factor, int variance_edge_size, int variance_pixels, float clamp_samples, float clamp_indirect)
760 {
761 	AA_samples = std::max(1, numSamples);
762 	AA_passes = numPasses;
763 	AA_inc_samples = (incSamples > 0) ? incSamples : AA_samples;
764 	AA_threshold = (float)threshold;
765 	AA_resampled_floor = resampled_floor;
766 	AA_sample_multiplier_factor = sample_multiplier_factor;
767 	AA_light_sample_multiplier_factor = light_sample_multiplier_factor;
768 	AA_indirect_sample_multiplier_factor = indirect_sample_multiplier_factor;
769 	AA_detect_color_noise = detect_color_noise;
770 	AA_dark_detection_type = dark_detection_type;
771 	AA_dark_threshold_factor = dark_threshold_factor;
772 	AA_variance_edge_size = variance_edge_size;
773 	AA_variance_pixels = variance_pixels;
774 	AA_clamp_samples = clamp_samples;
775 	AA_clamp_indirect = clamp_indirect;
776 }
777 
778 /*! update scene state to prepare for rendering.
779 	\return false if something vital to render the scene is missing
780 			true otherwise
781 */
update()782 bool scene_t::update()
783 {
784 	Y_VERBOSE << "Scene: Mode \"" << ((mode == 0) ? "Triangle" : "Universal" ) << "\"" << yendl;
785 	if(!camera || !imageFilm) return false;
786 	if(state.changes & C_GEOM)
787 	{
788 		if(tree) delete tree;
789 		if(vtree) delete vtree;
790 		tree = nullptr, vtree = nullptr;
791 		int nprims=0;
792 		if(mode==0)
793 		{
794 			for(auto i=meshes.begin(); i!=meshes.end(); ++i)
795 			{
796                 objData_t &dat = (*i).second;
797 
798                 if (!dat.obj->isVisible()) continue;
799                 if (dat.obj->isBaseObject()) continue;
800 
801 				if(dat.type == TRIM) nprims += dat.obj->numPrimitives();
802 			}
803 			if(nprims > 0)
804 			{
805 				const triangle_t **tris = new const triangle_t*[nprims];
806 				const triangle_t **insert = tris;
807 				for(auto i=meshes.begin(); i!=meshes.end(); ++i)
808 				{
809 					objData_t &dat = (*i).second;
810 
811 					if (!dat.obj->isVisible()) continue;
812 					if (dat.obj->isBaseObject()) continue;
813 
814 					if(dat.type == TRIM) insert += dat.obj->getPrimitives(insert);
815 				}
816 				tree = new triKdTree_t(tris, nprims, -1, 1, 0.8, 0.33 /* -1, 1.2, 0.40 */ );
817 				delete [] tris;
818 				sceneBound = tree->getBound();
819 				Y_VERBOSE << "Scene: New scene bound is:" <<
820 				"(" << sceneBound.a.x << ", " << sceneBound.a.y << ", " << sceneBound.a.z << "), (" <<
821 				sceneBound.g.x << ", " << sceneBound.g.y << ", " << sceneBound.g.z << ")" << yendl;
822 
823 				if(shadowBiasAuto) shadowBias = YAF_SHADOW_BIAS;
824 				if(rayMinDistAuto) rayMinDist = MIN_RAYDIST;
825 
826 				Y_INFO << "Scene: total scene dimensions: X=" << sceneBound.longX() << ", Y=" << sceneBound.longY() << ", Z=" << sceneBound.longZ() << ", volume=" << sceneBound.vol() << ", Shadow Bias=" << shadowBias << (shadowBiasAuto ? " (auto)":"") << ", Ray Min Dist=" << rayMinDist << (rayMinDistAuto ? " (auto)":"") << yendl;
827 			}
828 			else Y_WARNING << "Scene: Scene is empty..." << yendl;
829 		}
830 		else
831 		{
832 			for(auto i=meshes.begin(); i!=meshes.end(); ++i)
833 			{
834 				objData_t &dat = (*i).second;
835 				if(dat.type != TRIM) nprims += dat.mobj->numPrimitives();
836 			}
837 			// include all non-mesh objects; eventually make a common map...
838 			for(auto i=objects.begin(); i!=objects.end(); ++i)
839 			{
840 				nprims += i->second->numPrimitives();
841 			}
842 			if(nprims > 0)
843 			{
844 				const primitive_t **tris = new const primitive_t*[nprims];
845 				const primitive_t **insert = tris;
846 				for(auto i=meshes.begin(); i!=meshes.end(); ++i)
847 				{
848 					objData_t &dat = (*i).second;
849 					if(dat.type != TRIM) insert += dat.mobj->getPrimitives(insert);
850 				}
851 				for(auto i=objects.begin(); i!=objects.end(); ++i)
852 				{
853 					insert += i->second->getPrimitives(insert);
854 				}
855 				vtree = new kdTree_t<primitive_t>(tris, nprims, -1, 1, 0.8, 0.33 /* -1, 1.2, 0.40 */ );
856 				delete [] tris;
857 				sceneBound = vtree->getBound();
858 				Y_VERBOSE << "Scene: New scene bound is:" << yendl <<
859 				"(" << sceneBound.a.x << ", " << sceneBound.a.y << ", " << sceneBound.a.z << "), (" <<
860 				sceneBound.g.x << ", " << sceneBound.g.y << ", " << sceneBound.g.z << ")" << yendl;
861 
862 				if(shadowBiasAuto) shadowBias = YAF_SHADOW_BIAS;
863 				if(rayMinDistAuto) rayMinDist = MIN_RAYDIST;
864 
865 				Y_INFO << "Scene: total scene dimensions: X=" << sceneBound.longX() << ", Y=" << sceneBound.longY() << ", Z=" << sceneBound.longZ() << ", volume=" << sceneBound.vol() << ", Shadow Bias=" << shadowBias << (shadowBiasAuto ? " (auto)":"") << ", Ray Min Dist=" << rayMinDist << (rayMinDistAuto ? " (auto)":"") << yendl;
866 
867 			}
868 			else Y_ERROR << "Scene: Scene is empty..." << yendl;
869 		}
870 	}
871 
872 	for(unsigned int i=0; i<lights.size(); ++i) lights[i]->init(*this);
873 
874 	if(!surfIntegrator)
875 	{
876 		Y_ERROR << "Scene: No surface integrator, bailing out..." << yendl;
877 		return false;
878 	}
879 
880 	if(state.changes != C_NONE)
881 	{
882 		std::stringstream inteSettings;
883 
884 		bool success = (surfIntegrator->preprocess() && volIntegrator->preprocess());
885 
886 		if(!success) return false;
887 	}
888 
889 	state.changes = C_NONE;
890 
891 	return true;
892 }
893 
intersect(const ray_t & ray,surfacePoint_t & sp) const894 bool scene_t::intersect(const ray_t &ray, surfacePoint_t &sp) const
895 {
896 	float dis, Z;
897 	intersectData_t data;
898 	if(ray.tmax<0) dis=std::numeric_limits<float>::infinity();
899 	else dis=ray.tmax;
900 	// intersect with tree:
901 	if(mode == 0)
902 	{
903 		if(!tree) return false;
904 		triangle_t *hitt = nullptr;
905 		if( ! tree->Intersect(ray, dis, &hitt, Z, data) ){ return false; }
906 		point3d_t h=ray.from + Z*ray.dir;
907 		hitt->getSurface(sp, h, data);
908 		sp.origin = hitt;
909 		sp.data = data;
910 		sp.ray = nullptr;
911 	}
912 	else
913 	{
914 		if(!vtree) return false;
915 		primitive_t *hitprim = nullptr;
916 		if( ! vtree->Intersect(ray, dis, &hitprim, Z, data) ){ return false; }
917 		point3d_t h=ray.from + Z*ray.dir;
918 		hitprim->getSurface(sp, h, data);
919 		sp.origin = hitprim;
920 		sp.data = data;
921 		sp.ray = nullptr;
922 	}
923 	ray.tmax = Z;
924 	return true;
925 }
926 
intersect(const diffRay_t & ray,surfacePoint_t & sp) const927 bool scene_t::intersect(const diffRay_t &ray, surfacePoint_t &sp) const
928 {
929 	float dis, Z;
930 	intersectData_t data;
931 	if(ray.tmax<0) dis=std::numeric_limits<float>::infinity();
932 	else dis=ray.tmax;
933 	// intersect with tree:
934 	if(mode == 0)
935 	{
936 		if(!tree) return false;
937 		triangle_t *hitt = nullptr;
938 		if( ! tree->Intersect(ray, dis, &hitt, Z, data) ){ return false; }
939 		point3d_t h=ray.from + Z*ray.dir;
940 		hitt->getSurface(sp, h, data);
941 		sp.origin = hitt;
942 		sp.data = data;
943 		sp.ray = &ray;
944 	}
945 	else
946 	{
947 		if(!vtree) return false;
948 		primitive_t *hitprim = nullptr;
949 		if( ! vtree->Intersect(ray, dis, &hitprim, Z, data) ){ return false; }
950 		point3d_t h=ray.from + Z*ray.dir;
951 		hitprim->getSurface(sp, h, data);
952 		sp.origin = hitprim;
953 		sp.data = data;
954 		sp.ray = &ray;
955 	}
956 	ray.tmax = Z;
957 	return true;
958 }
959 
isShadowed(renderState_t & state,const ray_t & ray,float & obj_index,float & mat_index) const960 bool scene_t::isShadowed(renderState_t &state, const ray_t &ray, float &obj_index, float &mat_index) const
961 {
962 
963 	ray_t sray(ray);
964 	sray.from += sray.dir * sray.tmin;
965 	sray.time = state.time;
966 	float dis;
967 	if(ray.tmax<0)	dis=std::numeric_limits<float>::infinity();
968 	else  dis = sray.tmax - 2*sray.tmin;
969 	if(mode==0)
970 	{
971 		triangle_t *hitt = nullptr;
972 		if(!tree) return false;
973 		bool shadowed = tree->IntersectS(sray, dis, &hitt, shadowBias);
974 		if(hitt)
975 		{
976 			if(hitt->getMesh()) obj_index = hitt->getMesh()->getAbsObjectIndex();	//Object index of the object casting the shadow
977 			if(hitt->getMaterial()) mat_index = hitt->getMaterial()->getAbsMaterialIndex();	//Material index of the object casting the shadow
978 		}
979 		return shadowed;
980 	}
981 	else
982 	{
983 		primitive_t *hitt = nullptr;
984 		if(!vtree) return false;
985 		bool shadowed = vtree->IntersectS(sray, dis, &hitt, shadowBias);
986 		if(hitt)
987 		{
988 			if(hitt->getMaterial()) mat_index = hitt->getMaterial()->getAbsMaterialIndex();	//Material index of the object casting the shadow
989 		}
990 		return shadowed;
991 	}
992 }
993 
isShadowed(renderState_t & state,const ray_t & ray,int maxDepth,color_t & filt,float & obj_index,float & mat_index) const994 bool scene_t::isShadowed(renderState_t &state, const ray_t &ray, int maxDepth, color_t &filt, float &obj_index, float &mat_index) const
995 {
996 	ray_t sray(ray);
997 	sray.from += sray.dir * sray.tmin;
998 	float dis;
999 	if(ray.tmax<0)	dis=std::numeric_limits<float>::infinity();
1000 	else  dis = sray.tmax - 2*sray.tmin;
1001 	filt = color_t(1.0);
1002 	void *odat = state.userdata;
1003 	unsigned char userdata[USER_DATA_SIZE+7];
1004 	state.userdata = (void *)( ((size_t)&userdata[7])&(~7 ) ); // pad userdata to 8 bytes
1005 	bool isect=false;
1006 	if(mode==0)
1007 	{
1008 		triangle_t *hitt = nullptr;
1009 		if(tree)
1010 		{
1011 			isect = tree->IntersectTS(state, sray, maxDepth, dis, &hitt, filt, shadowBias);
1012 			if(hitt)
1013 			{
1014 				if(hitt->getMesh()) obj_index = hitt->getMesh()->getAbsObjectIndex();	//Object index of the object casting the shadow
1015 				if(hitt->getMaterial()) mat_index = hitt->getMaterial()->getAbsMaterialIndex();	//Material index of the object casting the shadow
1016 			}
1017 		}
1018 	}
1019 	else
1020 	{
1021 		primitive_t *hitt = nullptr;
1022 		if(vtree)
1023 		{
1024 			isect = vtree->IntersectTS(state, sray, maxDepth, dis, &hitt, filt, shadowBias);
1025 			if(hitt)
1026 			{
1027 				if(hitt->getMaterial()) mat_index = hitt->getMaterial()->getAbsMaterialIndex();	//Material index of the object casting the shadow
1028 			}
1029 		}
1030 	}
1031 	state.userdata = odat;
1032 	return isect;
1033 }
1034 
render()1035 bool scene_t::render()
1036 {
1037 	sig_mutex.lock();
1038 	signals = 0;
1039 	sig_mutex.unlock();
1040 
1041 	bool success = false;
1042 
1043 	const std::map<std::string,camera_t *> *camera_table = env->getCameraTable();
1044 
1045 	if(camera_table->size() == 0)
1046 	{
1047 		Y_ERROR << "No cameras/views found, exiting." << yendl;
1048 		return false;
1049 	}
1050 
1051 	for(auto cam_table_entry = camera_table->begin(); cam_table_entry != camera_table->end(); ++cam_table_entry)
1052     {
1053 		int numView = distance(camera_table->begin(), cam_table_entry);
1054 		camera_t* cam = cam_table_entry->second;
1055 		setCamera(cam);
1056 		if(!update()) return false;
1057 
1058 		success = surfIntegrator->render(numView, imageFilm);
1059 
1060 		surfIntegrator->cleanup();
1061 		imageFilm->flush(numView);
1062     }
1063 
1064 	return success;
1065 }
1066 
1067 //! does not do anything yet...maybe never will
addMaterial(material_t * m,const char * name)1068 bool scene_t::addMaterial(material_t *m, const char* name) { return false; }
1069 
getNextFreeID()1070 objID_t scene_t::getNextFreeID()
1071 {
1072 	objID_t id;
1073 	id = state.nextFreeID;
1074 
1075 	//create new entry for object, assert that no ID collision happens:
1076 	if(meshes.find(id) != meshes.end())
1077 	{
1078 		Y_ERROR << "Scene: Object ID already in use!" << yendl;
1079 		--state.nextFreeID;
1080 		return getNextFreeID();
1081 	}
1082 
1083 	--state.nextFreeID;
1084 
1085 	return id;
1086 }
1087 
addObject(object3d_t * obj,objID_t & id)1088 bool scene_t::addObject(object3d_t *obj, objID_t &id)
1089 {
1090 	id = getNextFreeID();
1091 	if( id > 0 )
1092 	{
1093 		//create new triangle object:
1094 		objects[id] = obj;
1095 		return true;
1096 	}
1097 	else
1098 	{
1099 		return false;
1100 	}
1101 }
1102 
addInstance(objID_t baseObjectId,const matrix4x4_t & objToWorld)1103 bool scene_t::addInstance(objID_t baseObjectId, const matrix4x4_t &objToWorld)
1104 {
1105 	if(mode != 0) return false;
1106 
1107 	if (meshes.find(baseObjectId) == meshes.end())
1108 	{
1109 		Y_ERROR << "Base mesh for instance doesn't exist " << baseObjectId << yendl;
1110 		return false;
1111 	}
1112 
1113 	int id = getNextFreeID();
1114 
1115 	if (id > 0)
1116 	{
1117 		objData_t &od = meshes[id];
1118 		objData_t &base = meshes[baseObjectId];
1119 
1120 		od.obj = new triangleObjectInstance_t(base.obj, objToWorld);
1121 
1122 		return true;
1123 	}
1124 	else
1125 	{
1126 		return false;
1127 	}
1128 }
1129 
getRenderPasses() const1130 const renderPasses_t* scene_t::getRenderPasses() const { return env->getRenderPasses(); }
pass_enabled(intPassTypes_t intPassType) const1131 bool scene_t::pass_enabled(intPassTypes_t intPassType) const { return env->getRenderPasses()->pass_enabled(intPassType); }
1132 
1133 
1134 __END_YAFRAY
1135