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