|
@@ -0,0 +1,423 @@
|
|
|
|
|
+#include "EmbreeRenderer.h"
|
|
|
|
|
+// Implementation
|
|
|
|
|
+
|
|
|
|
|
+//IGL viewing parts
|
|
|
|
|
+#include "../unproject.h"
|
|
|
|
|
+#include "../look_at.h"
|
|
|
|
|
+#include "../frustum.h"
|
|
|
|
|
+#include "../ortho.h"
|
|
|
|
|
+
|
|
|
|
|
+// color map
|
|
|
|
|
+#include "../jet.h"
|
|
|
|
|
+
|
|
|
|
|
+#include "../PI.h"
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void igl::embree::EmbreeRenderer::init_view()
|
|
|
|
|
+{
|
|
|
|
|
+ camera_base_zoom = 1.0f;
|
|
|
|
|
+ camera_zoom = 1.0f;
|
|
|
|
|
+
|
|
|
|
|
+ camera_view_angle = 45.0;
|
|
|
|
|
+ camera_dnear = 1.0;
|
|
|
|
|
+ camera_dfar = 100.0;
|
|
|
|
|
+ camera_base_translation << 0, 0, 0;
|
|
|
|
|
+ camera_translation << 0, 0, 0;
|
|
|
|
|
+ camera_eye << 0, 0, 5;
|
|
|
|
|
+ camera_center << 0, 0, 0;
|
|
|
|
|
+ camera_up << 0, 1, 0;
|
|
|
|
|
+
|
|
|
|
|
+ rot_matrix = Eigen::Matrix3f::Identity();
|
|
|
|
|
+
|
|
|
|
|
+ view = Eigen::Matrix4f::Identity();
|
|
|
|
|
+ proj = Eigen::Matrix4f::Identity();
|
|
|
|
|
+ norm = Eigen::Matrix4f::Identity();
|
|
|
|
|
+
|
|
|
|
|
+ orthographic = false;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ uC << 1,0,0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer()
|
|
|
|
|
+ :
|
|
|
|
|
+ scene(NULL),
|
|
|
|
|
+ geomID(0),
|
|
|
|
|
+ initialized(false),
|
|
|
|
|
+ device(igl::embree::EmbreeDevice::get_device())
|
|
|
|
|
+{
|
|
|
|
|
+ init_view();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE igl::embree::EmbreeRenderer::EmbreeRenderer(
|
|
|
|
|
+ const EmbreeRenderer &)
|
|
|
|
|
+ :// To make -Weffc++ happy
|
|
|
|
|
+ scene(NULL),
|
|
|
|
|
+ geomID(0),
|
|
|
|
|
+ initialized(false)
|
|
|
|
|
+{
|
|
|
|
|
+ assert(false && "Embree: Copying EmbreeRenderer is not allowed");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE igl::embree::EmbreeRenderer & igl::embree::EmbreeRenderer::operator=(
|
|
|
|
|
+ const EmbreeRenderer &)
|
|
|
|
|
+{
|
|
|
|
|
+ assert(false && "Embree: Assigning an EmbreeRenderer is not allowed");
|
|
|
|
|
+ return *this;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void igl::embree::EmbreeRenderer::init(
|
|
|
|
|
+ const PointMatrixType& V,
|
|
|
|
|
+ const FaceMatrixType& F,
|
|
|
|
|
+ bool isStatic)
|
|
|
|
|
+{
|
|
|
|
|
+ std::vector<const PointMatrixType*> Vtemp;
|
|
|
|
|
+ std::vector<const FaceMatrixType*> Ftemp;
|
|
|
|
|
+ std::vector<int> masks;
|
|
|
|
|
+ Vtemp.push_back(&V);
|
|
|
|
|
+ Ftemp.push_back(&F);
|
|
|
|
|
+ masks.push_back(0xFFFFFFFF);
|
|
|
|
|
+ init(Vtemp,Ftemp,masks,isStatic);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void igl::embree::EmbreeRenderer::init(
|
|
|
|
|
+ const std::vector<const PointMatrixType*>& V,
|
|
|
|
|
+ const std::vector<const FaceMatrixType*>& F,
|
|
|
|
|
+ const std::vector<int>& masks,
|
|
|
|
|
+ bool isStatic)
|
|
|
|
|
+{
|
|
|
|
|
+ if(initialized)
|
|
|
|
|
+ deinit();
|
|
|
|
|
+
|
|
|
|
|
+ using namespace std;
|
|
|
|
|
+
|
|
|
|
|
+ if(V.size() == 0 || F.size() == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ std::cerr << "Embree: No geometry specified!";
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
|
|
|
|
|
+
|
|
|
|
|
+ // create a scene
|
|
|
|
|
+ scene = rtcNewScene(device);
|
|
|
|
|
+ rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
|
|
|
|
|
+ rtcSetSceneBuildQuality(scene, buildQuality);
|
|
|
|
|
+
|
|
|
|
|
+ for(int g=0;g<(int)V.size();g++)
|
|
|
|
|
+ {
|
|
|
|
|
+ // create triangle mesh geometry in that scene
|
|
|
|
|
+ RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
|
|
|
|
|
+ rtcSetGeometryBuildQuality(geom_0, buildQuality);
|
|
|
|
|
+ rtcSetGeometryTimeStepCount(geom_0,1);
|
|
|
|
|
+ geomID = rtcAttachGeometry(scene,geom_0);
|
|
|
|
|
+ rtcReleaseGeometry(geom_0);
|
|
|
|
|
+
|
|
|
|
|
+ // fill vertex buffer, have to be 16 byte wide( sizeof(float)*4 )
|
|
|
|
|
+ Eigen::Map<Eigen::Matrix<float,-1,4,Eigen::RowMajor>> vertices(
|
|
|
|
|
+ (float*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows()),
|
|
|
|
|
+ V[g]->rows(),4
|
|
|
|
|
+ );
|
|
|
|
|
+ vertices.block(0,0,V[g]->rows(),3) = V[g]->cast<float>();
|
|
|
|
|
+
|
|
|
|
|
+ // fill triangle buffer
|
|
|
|
|
+ Eigen::Map<Eigen::Matrix<unsigned int,-1,3,Eigen::RowMajor>> triangles(
|
|
|
|
|
+ (unsigned int*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(unsigned int), F[g]->rows()),
|
|
|
|
|
+ F[g]->rows(),3
|
|
|
|
|
+ );
|
|
|
|
|
+ triangles = F[g]->cast<unsigned int>();
|
|
|
|
|
+ //TODO: store vertices and triangles in array for whatever reason?
|
|
|
|
|
+
|
|
|
|
|
+ rtcSetGeometryMask(geom_0, masks[g]);
|
|
|
|
|
+ rtcCommitGeometry(geom_0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ rtcCommitScene(scene);
|
|
|
|
|
+
|
|
|
|
|
+ if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
|
|
|
|
|
+ std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
|
|
|
|
|
+#ifdef IGL_VERBOSE
|
|
|
|
|
+ else
|
|
|
|
|
+ std::cerr << "Embree: geometry added." << endl;
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ initialized = true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE igl::embree::EmbreeRenderer::~EmbreeRenderer()
|
|
|
|
|
+{
|
|
|
|
|
+ if(initialized)
|
|
|
|
|
+ deinit();
|
|
|
|
|
+
|
|
|
|
|
+ igl::embree::EmbreeDevice::release_device();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void igl::embree::EmbreeRenderer::deinit()
|
|
|
|
|
+{
|
|
|
|
|
+ if(scene)
|
|
|
|
|
+ {
|
|
|
|
|
+ rtcReleaseScene(scene);
|
|
|
|
|
+
|
|
|
|
|
+ if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
|
|
|
|
|
+ {
|
|
|
|
|
+ std::cerr << "Embree: An error occurred while resetting!" << std::endl;
|
|
|
|
|
+ }
|
|
|
|
|
+#ifdef IGL_VERBOSE
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ std::cerr << "Embree: geometry removed." << std::endl;
|
|
|
|
|
+ }
|
|
|
|
|
+#endif
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE bool igl::embree::EmbreeRenderer::intersect_ray(
|
|
|
|
|
+ const Eigen::RowVector3f& origin,
|
|
|
|
|
+ const Eigen::RowVector3f& direction,
|
|
|
|
|
+ Hit& hit,
|
|
|
|
|
+ float tnear,
|
|
|
|
|
+ float tfar,
|
|
|
|
|
+ int mask) const
|
|
|
|
|
+{
|
|
|
|
|
+ RTCRayHit ray;
|
|
|
|
|
+ ray.ray.flags = 0;
|
|
|
|
|
+ create_ray(ray, origin,direction,tnear,tfar,mask);
|
|
|
|
|
+
|
|
|
|
|
+ // shot ray
|
|
|
|
|
+ {
|
|
|
|
|
+ RTCIntersectContext context;
|
|
|
|
|
+ rtcInitIntersectContext(&context);
|
|
|
|
|
+ rtcIntersect1(scene, &context, &ray);
|
|
|
|
|
+ ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
|
|
|
|
|
+ ray.hit.Ng_y = -ray.hit.Ng_y;
|
|
|
|
|
+ ray.hit.Ng_z = -ray.hit.Ng_z;
|
|
|
|
|
+ }
|
|
|
|
|
+#ifdef IGL_VERBOSE
|
|
|
|
|
+ if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
|
|
|
|
|
+ std::cerr << "Embree: An error occurred while resetting!" << std::endl;
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
|
|
|
|
|
+ {
|
|
|
|
|
+ hit.id = ray.hit.primID;
|
|
|
|
|
+ hit.gid = ray.hit.geomID;
|
|
|
|
|
+ hit.u = ray.hit.u;
|
|
|
|
|
+ hit.v = ray.hit.v;
|
|
|
|
|
+ hit.t = ray.ray.tfar;
|
|
|
|
|
+ hit.N = Vec3f(ray.hit.Ng_x, ray.hit.Ng_y, ray.hit.Ng_z);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer
|
|
|
|
|
+::create_ray(RTCRayHit& ray, const Eigen::RowVector3f& origin,
|
|
|
|
|
+ const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
|
|
|
|
|
+{
|
|
|
|
|
+ ray.ray.org_x = origin[0];
|
|
|
|
|
+ ray.ray.org_y = origin[1];
|
|
|
|
|
+ ray.ray.org_z = origin[2];
|
|
|
|
|
+ ray.ray.dir_x = direction[0];
|
|
|
|
|
+ ray.ray.dir_y = direction[1];
|
|
|
|
|
+ ray.ray.dir_z = direction[2];
|
|
|
|
|
+ ray.ray.tnear = tnear;
|
|
|
|
|
+ ray.ray.tfar = tfar;
|
|
|
|
|
+ ray.ray.id = RTC_INVALID_GEOMETRY_ID;
|
|
|
|
|
+ ray.ray.mask = mask;
|
|
|
|
|
+ ray.ray.time = 0.0f;
|
|
|
|
|
+
|
|
|
|
|
+ ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
|
|
|
|
|
+ ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
|
|
|
|
|
+ ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer
|
|
|
|
|
+::set_mesh(const Eigen::Matrix<double,Eigen::Dynamic,3> & MV,
|
|
|
|
|
+ const Eigen::Matrix<int, Eigen::Dynamic,3> & MF,
|
|
|
|
|
+ bool is_static)
|
|
|
|
|
+{
|
|
|
|
|
+ V = MV.cast<float>();
|
|
|
|
|
+ F = MF;
|
|
|
|
|
+ this->init(V,F,is_static);
|
|
|
|
|
+
|
|
|
|
|
+ auto min_point = V.colwise().minCoeff();
|
|
|
|
|
+ auto max_point = V.colwise().maxCoeff();
|
|
|
|
|
+ auto centroid = (0.5*(min_point + max_point)).eval();
|
|
|
|
|
+
|
|
|
|
|
+ camera_base_translation.setConstant(0);
|
|
|
|
|
+ camera_base_translation.head(centroid.size()) = -centroid.cast<float>();
|
|
|
|
|
+ camera_base_zoom = 2.0 / (max_point-min_point).array().abs().maxCoeff();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer
|
|
|
|
|
+::render_buffer(PixelMatrixType& R, PixelMatrixType&G, PixelMatrixType &B,PixelMatrixType &A)
|
|
|
|
|
+{
|
|
|
|
|
+ assert(R.rows()==G.rows());assert(R.rows()==B.rows());assert(R.rows()==A.rows());
|
|
|
|
|
+ assert(R.cols()==G.cols());assert(R.cols()==B.cols());assert(R.cols()==A.cols());
|
|
|
|
|
+
|
|
|
|
|
+ Eigen::Vector4f viewport(0,0,R.rows(),R.cols());
|
|
|
|
|
+
|
|
|
|
|
+ float width = R.rows();
|
|
|
|
|
+ float height = R.cols();
|
|
|
|
|
+
|
|
|
|
|
+ // update view matrix
|
|
|
|
|
+ igl::look_at( camera_eye, camera_center, camera_up, view);
|
|
|
|
|
+
|
|
|
|
|
+ view = view
|
|
|
|
|
+ * (rot_matrix * Eigen::Scaling(camera_zoom * camera_base_zoom)
|
|
|
|
|
+ * Eigen::Translation3f(camera_translation + camera_base_translation)).matrix();
|
|
|
|
|
+
|
|
|
|
|
+ if (orthographic)
|
|
|
|
|
+ {
|
|
|
|
|
+ float length = (camera_eye - camera_center).norm();
|
|
|
|
|
+ float h = tan(camera_view_angle/360.0 * igl::PI) * (length);
|
|
|
|
|
+ igl::ortho(-h*width/height, h*width/height, -h, h, camera_dnear, camera_dfar, proj);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ float fH = tan(camera_view_angle / 360.0 * igl::PI) * camera_dnear;
|
|
|
|
|
+ float fW = fH * (double)width/(double)height;
|
|
|
|
|
+ igl::frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar, proj);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // go over all pixels in the "view"
|
|
|
|
|
+ for(int x=0;x<(int)width;++x)
|
|
|
|
|
+ {
|
|
|
|
|
+ for(int y=0;y<(int)height;++y)
|
|
|
|
|
+ {
|
|
|
|
|
+ Vec3f s,d,dir;
|
|
|
|
|
+ igl::embree::EmbreeRenderer::Hit hit;
|
|
|
|
|
+
|
|
|
|
|
+ // look into the screen
|
|
|
|
|
+ Vec3f win_s(x,y,0);
|
|
|
|
|
+ Vec3f win_d(x,y,1);
|
|
|
|
|
+ // Source, destination and direction in world
|
|
|
|
|
+ igl::unproject(win_s,this->view,this->proj,viewport,s);
|
|
|
|
|
+ igl::unproject(win_d,this->view,this->proj,viewport,d);
|
|
|
|
|
+ dir = d-s;
|
|
|
|
|
+ dir.normalize();
|
|
|
|
|
+
|
|
|
|
|
+ auto clamp=[](float x)->unsigned char {return (unsigned char)(x<0?0:x>1.0?255:x*255);};
|
|
|
|
|
+
|
|
|
|
|
+ if(this->intersect_ray(s,dir,hit))
|
|
|
|
|
+ {
|
|
|
|
|
+ if ( dir.dot(hit.N) > 0.0f)
|
|
|
|
|
+ {
|
|
|
|
|
+ // TODO: interpolate normals ?
|
|
|
|
|
+ hit.N.normalize();
|
|
|
|
|
+ // cos between ray and face normal
|
|
|
|
|
+ float face_proj=dir.dot(hit.N);
|
|
|
|
|
+
|
|
|
|
|
+ Eigen::RowVector3f c;
|
|
|
|
|
+
|
|
|
|
|
+ if(this->uniform_color)
|
|
|
|
|
+ {
|
|
|
|
|
+ // same color for the whole mesh
|
|
|
|
|
+ c=uC;
|
|
|
|
|
+ } else if(this->face_based) {
|
|
|
|
|
+ // flat color per face
|
|
|
|
|
+ c=this->C.row(hit.id);
|
|
|
|
|
+ } else { //use barycentric coordinates to interpolate colour
|
|
|
|
|
+ c=this->C.row(F(hit.id,1))*hit.u+
|
|
|
|
|
+ this->C.row(F(hit.id,2))*hit.v+
|
|
|
|
|
+ this->C.row(F(hit.id,0))*(1.0-hit.u-hit.v);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ R(x,y) = clamp(face_proj*c(0));
|
|
|
|
|
+ G(x,y) = clamp(face_proj*c(1));
|
|
|
|
|
+ B(x,y) = clamp(face_proj*c(2));
|
|
|
|
|
+ }
|
|
|
|
|
+ // give the same alpha to all points with something behind
|
|
|
|
|
+ A(x,y)=255;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ R(x,y)=0;
|
|
|
|
|
+ G(x,y)=0;
|
|
|
|
|
+ B(x,y)=0;
|
|
|
|
|
+ A(x,y)=0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer
|
|
|
|
|
+::set_colors(const Eigen::MatrixXd & C)
|
|
|
|
|
+{
|
|
|
|
|
+ if(C.rows()==V.rows()) // per vertex color
|
|
|
|
|
+ {
|
|
|
|
|
+ face_based = false;
|
|
|
|
|
+ this->C = C.cast<float>();
|
|
|
|
|
+ this->uniform_color=false;
|
|
|
|
|
+ } else if (C.rows()==F.rows()) {
|
|
|
|
|
+ face_based = true;
|
|
|
|
|
+ this->C = C.cast<float>();
|
|
|
|
|
+ this->uniform_color=false;
|
|
|
|
|
+ } else if (C.rows()==1) {
|
|
|
|
|
+ face_based = true;
|
|
|
|
|
+ this->uC = C.cast<float>();
|
|
|
|
|
+ this->uniform_color=true;
|
|
|
|
|
+ }else {
|
|
|
|
|
+ // don't know what to do
|
|
|
|
|
+ this->uniform_color=true;
|
|
|
|
|
+ assert(false); //?
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer
|
|
|
|
|
+::set_data(const Eigen::VectorXd & D, igl::ColorMapType cmap)
|
|
|
|
|
+{
|
|
|
|
|
+ const double caxis_min = D.minCoeff();
|
|
|
|
|
+ const double caxis_max = D.maxCoeff();
|
|
|
|
|
+ return set_data(D,caxis_min,caxis_max,cmap);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void igl::embree::EmbreeRenderer::set_data(
|
|
|
|
|
+ const Eigen::VectorXd & D,
|
|
|
|
|
+ double caxis_min,
|
|
|
|
|
+ double caxis_max,
|
|
|
|
|
+ igl::ColorMapType cmap)
|
|
|
|
|
+{
|
|
|
|
|
+ Eigen::MatrixXd C;
|
|
|
|
|
+ igl::colormap(cmap,D,caxis_min,caxis_max,C);
|
|
|
|
|
+ set_colors(C);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer::set_rot(const Eigen::Matrix3d &r)
|
|
|
|
|
+{
|
|
|
|
|
+ this->rot_matrix = r.cast<float>();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer::set_zoom(double zoom)
|
|
|
|
|
+{
|
|
|
|
|
+ this->camera_zoom=zoom;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer::set_translation(const Eigen::Vector3d &tr)
|
|
|
|
|
+{
|
|
|
|
|
+ this->camera_translation=tr.cast<float>();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer::set_face_based(bool _f)
|
|
|
|
|
+{
|
|
|
|
|
+ this->face_based=_f;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+IGL_INLINE void
|
|
|
|
|
+igl::embree::EmbreeRenderer::set_orthographic(bool o)
|
|
|
|
|
+{
|
|
|
|
|
+ this->orthographic=o;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#ifdef IGL_STATIC_LIBRARY
|
|
|
|
|
+#endif //IGL_STATIC_LIBRARY
|