Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OptiXDisplayDevice.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2019 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010 * RCS INFORMATION:
00011 *
00012 *      $RCSfile: OptiXDisplayDevice.C,v $
00013 *      $Author: johns $      $Locker:  $               $State: Exp $
00014 *      $Revision: 1.87 $         $Date: 2024/03/01 01:35:33 $
00015 *
00016 ***************************************************************************/
00075 // low-level OptiX headers have to be included first
00076 // to prevent issues with compilation on Windows due to
00077 // header-internal min/max macro (re)definition, etc.
00078 #include "OptiXDisplayDevice.h"
00079 #include "OptiXRenderer.h"
00080 
00081 #include <math.h>
00082 #include <stdlib.h>
00083 #include <stdio.h>
00084 #include <string.h>
00085 
00086 #include "VMDApp.h"      // needed for GPU global memory management
00087 #include "QuickSurf.h"   // needed for GPU global memory management
00088 #include "VideoStream.h" // needed to query video streaming status
00089 
00090 #include "DispCmds.h"  // CYLINDER_TRAILINGCAP, etc..
00091 #include "config.h"    // needed for default image viewer
00092 #include "Hershey.h"   // needed for Hershey font rendering fctns
00093 
00094 #include "ProfileHooks.h"
00095 
00096 // The default radius for points and lines (which are displayed
00097 // as small spheres or cylinders, respectively)
00098 #define DEFAULT_RADIUS  0.0025f
00099 
00101 OptiXDisplayDevice::OptiXDisplayDevice(VMDApp *app, int interactive) : FileRenderer((interactive) ? 
00102                "TachyonLOptiXInteractive" : "TachyonLOptiXInternal", 
00103                (interactive) ? 
00104                "TachyonL-OptiX (interactive, GPU-accelerated)" : "TachyonL-OptiX (internal, in-memory, GPU-accelerated)",
00105                "vmdscene.ppm", DEF_VMDIMAGEVIEWER) {
00106  
00107   PROFILE_PUSH_RANGE((interactive) ? "OptiXDisplayDevice::OptiXDisplayDevice(INTERACTIVE)" : "OptiXDisplayDevice::OptiXDisplayDevice(BATCH)", 0);  
00108 
00109   vmdapp = app; // save VMDApp handle for GPU memory management routines
00110 
00111   reset_vars(); // initialize material cache
00112 
00113   // flag interactive or not
00114   isinteractive = interactive;
00115 
00116   // Add supported file formats
00117   formats.add_name("PPM", 0);
00118 
00119   // Default image format depends on platform
00120   curformat = 0;
00121 
00122   // Set default aa level
00123   has_aa = TRUE;
00124   aasamples = 12;
00125   aosamples = 12;
00126 
00127   ort = new OptiXRenderer(vmdapp);
00128   ort_timer = wkf_timer_create();
00129 
00130   PROFILE_POP_RANGE();
00131 }
00132         
00134 OptiXDisplayDevice::~OptiXDisplayDevice(void) {
00135   PROFILE_PUSH_RANGE("OptiXDisplayDevice::~OptiXDisplayDevice()", 0);  
00136 
00137   delete ort;
00138   wkf_timer_destroy(ort_timer);
00139 
00140   PROFILE_POP_RANGE();
00141 }
00142 
00143 
00145 unsigned int OptiXDisplayDevice::device_count(void) {
00146   return OptiXRenderer::device_count();
00147 }
00148 
00149 
00150 void OptiXDisplayDevice::add_material(void) {
00151   ort->add_material(materialIndex,
00152                     mat_ambient, mat_diffuse, mat_specular, mat_shininess,
00153                     mat_mirror, mat_opacity, mat_outline, mat_outlinewidth, 
00154                     roundf(mat_transmode)); // XXX allow shader hacking
00155 //                    mat_transmode > 0.5f);
00156 }
00157 
00158 
00160 void OptiXDisplayDevice::reset_vars(void) {
00161   reset_cylinder_buffer();
00162   reset_sphere_buffer();
00163   reset_triangle_buffer();
00164 }
00165 
00166 
00167 void OptiXDisplayDevice::send_cylinder_buffer() {
00168   if (cylinder_vert_buffer.num() > 0) {
00169     // send the cylinders...
00170     ort->cylinder_array_color(cylinder_xform, cylinder_radius_scalefactor,
00171                               cylinder_vert_buffer.num()/6,
00172                               &cylinder_vert_buffer[0],
00173                               &cylinder_radii_buffer[0],
00174                               &cylinder_color_buffer[0],
00175                               cylinder_matindex);
00176 
00177     // send the cylinder end caps, if any
00178     if (cylcap_vert_buffer.num() > 0) {
00179       ort->ring_array_color(*cylinder_xform, cylinder_radius_scalefactor,
00180                               cylcap_vert_buffer.num()/3,
00181                               &cylcap_vert_buffer[0],
00182                               &cylcap_norm_buffer[0],
00183                               &cylcap_radii_buffer[0],
00184                               &cylcap_color_buffer[0],
00185                               cylinder_matindex);
00186     }
00187 
00188     delete cylinder_xform;
00189   }
00190   reset_cylinder_buffer();
00191 }
00192 
00193 
00194 // draw a cylinder
00195 void OptiXDisplayDevice::cylinder(float *a, float *b, float r, int filled) {
00196   // if we have a change in transformation matrix, color, or material state,
00197   // we have to emit all accumulated cylinders to OptiX and begin a new batch
00198   if (
00199 #if 1
00200       // Rather than submitting all of the array elements in a single very large
00201       // OptiX buffer, we break up very large arrays into multiple smaller 
00202       // OptiX buffers, to better facilitate NVLink-based distributed memory 
00203       // ray tracing across multiple GPUs.
00204       cylinder_vert_buffer.num() >= 15000000 || 
00205 #endif
00206       (cylinder_xform != NULL && ((cylinder_matindex != materialIndex) || (memcmp(cylinder_xform->mat, transMat.top().mat, sizeof(cylinder_xform->mat)))))) {
00207     send_cylinder_buffer(); // render the accumulated cylinder buffer...
00208   }
00209 
00210   // record all transformation/material/color state on first cylinder call
00211   if (cylinder_xform == NULL) {
00212     // record material, color, and transformation state
00213     cylinder_matindex = materialIndex;
00214     cylinder_xform = new Matrix4(transMat.top());
00215     cylinder_radius_scalefactor = scale_factor();
00216     add_material(); // cause OptiX to cache the current material
00217   }
00218 
00219   // record vertex data
00220   cylinder_vert_buffer.append2x3(&a[0], &b[0]);
00221   cylinder_radii_buffer.append(r);
00222   cylinder_color_buffer.append3(&matData[colorIndex][0]);
00223 
00224   // Cylinder caps?
00225   if (filled) {
00226     float norm[3];
00227     norm[0] = b[0] - a[0];
00228     norm[1] = b[1] - a[1];
00229     norm[2] = b[2] - a[2];
00230 
00231     float div = 1.0f / sqrtf(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
00232     norm[0] *= div;
00233     norm[1] *= div;
00234     norm[2] *= div;
00235 
00236     if (filled & CYLINDER_TRAILINGCAP) {
00237       cylcap_vert_buffer.append3(&a[0]);
00238       cylcap_norm_buffer.append3(&norm[0]);
00239       cylcap_radii_buffer.append2(0.0f, r);
00240       cylcap_color_buffer.append3(&matData[colorIndex][0]);
00241     }
00242 
00243     if (filled & CYLINDER_LEADINGCAP) {
00244       cylcap_vert_buffer.append3(&b[0]);
00245       norm[0] *= -1;
00246       norm[1] *= -1;
00247       norm[2] *= -1;
00248       cylcap_norm_buffer.append3(&norm[0]);
00249       cylcap_radii_buffer.append2(0.0f, r);
00250       cylcap_color_buffer.append3(&matData[colorIndex][0]);
00251     }
00252   }
00253 }
00254 
00255 
00256 void OptiXDisplayDevice::send_sphere_buffer() {
00257   if (sphere_vert_buffer.num() > 0) {
00258     // send the spheres...
00259     ort->sphere_array_color(*sphere_xform, sphere_radius_scalefactor,
00260                             sphere_vert_buffer.num()/3,
00261                             &sphere_vert_buffer[0],
00262                             &sphere_radii_buffer[0],
00263                             &sphere_color_buffer[0],
00264                             sphere_matindex);
00265 
00266     delete sphere_xform;
00267   }
00268   reset_sphere_buffer();
00269 }
00270 
00271 
00272 // draw a single sphere
00273 void OptiXDisplayDevice::sphere(float *xyzr) {
00274 #if 0
00275   add_material();
00276 
00277   // Submit all geometry in one buffer
00278   ort->sphere_array_color(transMat.top(), scale_factor(), 1,
00279                           xyzr, xyzr+3, &matData[colorIndex][0], materialIndex);
00280 #else
00281   // if we have a change in transformation matrix, color, or material state,
00282   // we have to emit all accumulated spheres to OptiX and begin a new batch
00283   if (
00284 #if 1
00285       // Rather than submitting all of the array elements in a single very large
00286       // OptiX buffer, we break up very large arrays into multiple smaller 
00287       // OptiX buffers, to better facilitate NVLink-based distributed memory 
00288       // ray tracing across multiple GPUs.
00289       sphere_vert_buffer.num() >= 15000000 || 
00290 #endif
00291       (sphere_xform != NULL && ((sphere_matindex != materialIndex) || (memcmp(sphere_xform->mat, transMat.top().mat, sizeof(sphere_xform->mat)))))) {
00292     send_sphere_buffer(); // render the accumulated sphere buffer...
00293   }
00294 
00295   // record all transformation/material/color state on first sphere call
00296   if (sphere_xform == NULL) {
00297     // record material, color, and transformation state
00298     sphere_matindex = materialIndex;
00299     sphere_xform = new Matrix4(transMat.top());
00300     sphere_radius_scalefactor = scale_factor();
00301     add_material(); // cause OptiX to cache the current material
00302   }
00303 
00304   // record vertex data
00305   sphere_vert_buffer.append3(xyzr);
00306   sphere_radii_buffer.append(xyzr[3]);
00307   sphere_color_buffer.append3(&matData[colorIndex][0]);
00308 #endif
00309 }
00310 
00311 
00312 // draw a sphere array
00313 void OptiXDisplayDevice::sphere_array(int spnum, int spres, float *centers, 
00314                                       float *radii, float *colors) {
00315   add_material();
00316 
00317 #if 1
00318   // Rather than submitting all of the array elements in a single very large 
00319   // OptiX buffer, we break up very large arrays into multiple smaller 
00320   // OptiX buffers, to better facilitate NVLink-based distributed memory 
00321   // ray tracing across multiple GPUs.
00322   int spleft=spnum;
00323   while (spleft > 0) {
00324     int spcount=spleft;
00325     if (spcount > 6000000) {
00326       spcount=5000000;
00327     } 
00328 
00329     long offset = spnum - spleft;
00330     long offset3 = 3L * offset;
00331     ort->sphere_array_color(transMat.top(), scale_factor(), spcount, 
00332                             centers+offset3, radii+offset, colors+offset3, materialIndex);
00333     spleft-=spcount;
00334   }
00335 #else
00336   // Submit all geometry in one buffer
00337   ort->sphere_array_color(transMat.top(), scale_factor(), spnum, 
00338                           centers, radii, colors, materialIndex);
00339 #endif
00340  
00341   // set final color state after array has been drawn
00342   int ind=(spnum-1)*3;
00343   super_set_color(nearest_index(colors[ind], colors[ind+1], colors[ind+2]));
00344 }
00345 
00346 
00347 void OptiXDisplayDevice::text(float *pos, float size, float thickness,
00348                               const char *str) {
00349   float textpos[3];
00350   float textsize, textthickness;
00351   hersheyhandle hh;
00352 
00353   // transform the world coordinates
00354   (transMat.top()).multpoint3d(pos, textpos);
00355   textsize = size * 1.5f;
00356   textthickness = thickness*DEFAULT_RADIUS;
00357 
00358   ResizeArray<float> text_spheres;
00359   ResizeArray<float> text_cylinders;
00360 
00361   while (*str != '\0') {
00362     float lm, rm, x, y, ox, oy;
00363     int draw, odraw;
00364     ox=oy=x=y=0.0f;
00365     draw=odraw=0;
00366 
00367     hersheyDrawInitLetter(&hh, *str, &lm, &rm);
00368     textpos[0] -= lm * textsize;
00369 
00370     while (!hersheyDrawNextLine(&hh, &draw, &x, &y)) {
00371       float oldpt[3], newpt[3];
00372       if (draw) {
00373         newpt[0] = textpos[0] + textsize * x;
00374         newpt[1] = textpos[1] + textsize * y;
00375         newpt[2] = textpos[2];
00376 
00377         if (odraw) {
00378           // if we have both previous and next points, connect them...
00379           oldpt[0] = textpos[0] + textsize * ox;
00380           oldpt[1] = textpos[1] + textsize * oy;
00381           oldpt[2] = textpos[2];
00382 
00383           text_cylinders.append2x3(&oldpt[0], &newpt[0]);
00384           text_spheres.append3(&newpt[0]);
00385         } else {
00386           // ...otherwise, just draw the next point
00387           text_spheres.append3(&newpt[0]);
00388         }
00389       }
00390 
00391       ox=x;
00392       oy=y;
00393       odraw=draw;
00394     }
00395     textpos[0] += rm * textsize;
00396 
00397     str++;
00398   }
00399 
00400   add_material();
00401   // add spheres, which are already in world coordinates
00402   if (text_cylinders.num() > 0) {
00403     ort->cylinder_array(NULL, textthickness, matData[colorIndex],
00404                         text_cylinders.num() / 6, &text_cylinders[0],
00405                         materialIndex);
00406   }
00407   if (text_spheres.num() > 0) {
00408     ort->sphere_array(NULL, textthickness, matData[colorIndex],
00409                       text_spheres.num() / 3, &text_spheres[0], NULL, 
00410                       materialIndex);
00411   }
00412 }
00413 
00414 
00415 
00416 void OptiXDisplayDevice::send_triangle_buffer() {
00417   if (triangle_vert_buffer.num() > 0) {
00418     ort->trimesh_n3f_v3f(*triangle_xform, 
00419                          matData[triangle_cindex],
00420                          &triangle_norm_buffer[0],
00421                          &triangle_vert_buffer[0],
00422                          triangle_vert_buffer.num()/9,
00423                          triangle_matindex);
00424     delete triangle_xform;
00425   }
00426   reset_triangle_buffer();
00427 }
00428 
00429 
00430 // draw a triangle
00431 void OptiXDisplayDevice::triangle(const float *a, const float *b, const float *c, const float *n1, const float *n2, const float *n3) {
00432   // if we have a change in transformation matrix, color, or material state,
00433   // we have to emit all accumulated triangles to OptiX and begin a new batch
00434   if (triangle_xform != NULL && ((triangle_cindex != colorIndex) || (triangle_matindex != materialIndex) || (memcmp(triangle_xform->mat, transMat.top().mat, sizeof(triangle_xform->mat))))) {
00435     send_triangle_buffer(); // render the accumulated triangle buffer...
00436   } 
00437 
00438   // record all transformation/material/color state on first triangle call
00439   if (triangle_xform == NULL) {
00440     // record material, color, and transformation state
00441     triangle_cindex = colorIndex;
00442     triangle_matindex = materialIndex;
00443     triangle_xform = new Matrix4(transMat.top());
00444     add_material(); // cause OptiX to cache the current material
00445   }
00446 
00447   // record vertex data 
00448   triangle_vert_buffer.append3x3(&a[0], &b[0], &c[0]);
00449 
00450   // record normal data 
00451   triangle_norm_buffer.append3x3(&n1[0], &n2[0], &n3[0]);
00452 }
00453 
00454 
00455 // draw a tricolor
00456 void OptiXDisplayDevice::tricolor(const float *a, const float *b, const float *c,
00457                       const float *n1, const float *n2, const float *n3,
00458                       const float *c1, const float *c2, const float *c3) {
00459   add_material();
00460 
00461   float vnc[27];
00462   vec_copy(&vnc[ 0], a);
00463   vec_copy(&vnc[ 3], b);
00464   vec_copy(&vnc[ 6], c);
00465 
00466   vec_copy(&vnc[ 9], n1);
00467   vec_copy(&vnc[12], n2);
00468   vec_copy(&vnc[15], n3);
00469 
00470   vec_copy(&vnc[18], c1);
00471   vec_copy(&vnc[21], c2);
00472   vec_copy(&vnc[24], c3);
00473 
00474   ort->tricolor_list(transMat.top(), 1, vnc, materialIndex);
00475 }
00476 
00477 
00478 void OptiXDisplayDevice::trimesh_c4u_n3b_v3f(unsigned char *c, 
00479                                              signed char *n,
00480                                              float *v, int numfacets) {
00481   add_material();
00482   ort->trimesh_c4u_n3b_v3f(transMat.top(), c, n, v, numfacets, materialIndex);
00483 }
00484 
00485 
00486 void OptiXDisplayDevice::trimesh_c4u_n3f_v3f(unsigned char *c, float *n,
00487                                              float *v, int numfacets) {
00488   add_material();
00489   ort->trimesh_c4u_n3f_v3f(transMat.top(), c, n, v, numfacets, materialIndex);
00490 }
00491 
00492 
00493 void OptiXDisplayDevice::trimesh_c4n3v3(int numverts, float * cnv,
00494                                         int numfacets, int * facets) {
00495   add_material();
00496   ort->trimesh_c4n3v3(transMat.top(), numverts, cnv, numfacets, facets, 
00497                       materialIndex);
00498 }
00499 
00500 
00501 void OptiXDisplayDevice::trimesh_n3b_v3f(signed char *n, float *v, 
00502                                          int numfacets) {
00503   add_material();
00504   ort->trimesh_n3b_v3f(transMat.top(), matData[colorIndex], n, v, numfacets,  materialIndex);
00505 }
00506 
00507 
00508 void OptiXDisplayDevice::trimesh_n3f_v3f(float *n, float *v, int numfacets) {
00509   add_material();
00510   ort->trimesh_n3f_v3f(transMat.top(), matData[colorIndex], n, v, numfacets,  materialIndex);
00511 }
00512 
00513 
00514 void OptiXDisplayDevice::trimesh_n3fopt_v3f(float *n, float *v, int numfacets) {
00515   add_material();
00516   ort->trimesh_v3f(transMat.top(), matData[colorIndex], v, numfacets,  materialIndex);
00517 }
00518 
00519 
00520 void OptiXDisplayDevice::tristrip(int numverts, const float * cnv,
00521                          int numstrips, const int *vertsperstrip,
00522                          const int *facets) {
00523   add_material();
00524   ort->tristrip(transMat.top(), numverts, cnv, numstrips, vertsperstrip, 
00525                 facets, materialIndex);
00526 }
00527 
00528 
00529 void OptiXDisplayDevice::write_lights() {
00530   int i;
00531   int lightcount = 0;
00532 
00533   // clear all existing lights before (re)appending the current lights,
00534   // otherwise if the OptiX context is reused, we will crash and burn.
00535   ort->clear_all_lights();
00536 
00537   // directional lights
00538   for (i=0; i<DISP_LIGHTS; i++) {
00539     if (lightState[i].on) {
00540       ort->add_directional_light(lightState[i].pos, lightState[i].color);
00541       lightcount++;
00542     }
00543   }
00544 
00545 #if 0
00546   // advanced positional lights
00547   for (i=0; i<DISP_LIGHTS; i++) {
00548     if (advLightState[i].on) {
00549       float pos[3];
00550 
00551       // always use world coordinates for now
00552       vec_copy(pos, advLightState[i].pos);
00553 
00554       if (advLightState[i].spoton) {
00555         printf("TachyonInternal) SpotLight not implemented yet ...\n");
00556       } else {
00557         apitexture tex;
00558         memset(&tex, 0, sizeof(apitexture));
00559 
00560         tex.col.r=advLightState[i].color[0];
00561         tex.col.g=advLightState[i].color[1];
00562         tex.col.b=advLightState[i].color[2];
00563 
00564         void *l = rt_light(rtscene,
00565                            rt_texture(rtscene, &tex),
00566                            /* negate position to correct handedness... */
00567                            rt_vector(pos[0], pos[1], -pos[2]), 0.0f);
00568 
00569         /* emit light attentuation parameters if needed */
00570         if (advLightState[i].constfactor != 1.0f ||
00571             advLightState[i].linearfactor != 0.0f ||
00572             advLightState[i].quadfactor != 0.0f) {
00573           rt_light_attenuation(l,
00574                                advLightState[i].constfactor,
00575                                advLightState[i].linearfactor,
00576                                advLightState[i].quadfactor);
00577         }
00578       }
00579 
00580       lightcount++;
00581     }
00582   }
00583 #endif
00584 
00585   if (lightcount < 1) {
00586     msgWarn << "No lights defined in molecular scene!!" << sendmsg;
00587   }
00588 
00589 }
00590 
00591 void OptiXDisplayDevice::write_materials() {
00592   ort->set_bg_color(backColor);
00593 
00594   // Specify Tachyon/OptiX background sky sphere if background gradient
00595   // mode is enabled.
00596   if (backgroundmode == 1) {
00597     float bspheremag = 0.5f;
00598 
00599     // compute positive/negative magnitude of sphere gradient
00600     switch (projection()) {
00601       case DisplayDevice::ORTHOGRAPHIC:
00602         ort->set_bg_mode(OptiXRenderer::RT_BACKGROUND_TEXTURE_SKY_ORTHO_PLANE);
00603 
00604         // For orthographic views, Tachyon uses the dot product between
00605         // the incident ray origin and the sky sphere gradient "up" vector,
00606         // since all camera rays have the same direction and differ only
00607         // in their origin.
00608         bspheremag = vSize / 4.0f;
00609         break;
00610 
00611       case DisplayDevice::PERSPECTIVE:
00612       default:
00613         ort->set_bg_mode(OptiXRenderer::RT_BACKGROUND_TEXTURE_SKY_SPHERE);
00614 
00615         // For perspective views, Tachyon uses the dot product between
00616         // the incident ray and the sky sphere gradient "up" vector,
00617         // so for larger values of vSize, we have to clamp the maximum
00618         // magnitude to 1.0.
00619         bspheremag = (vSize / 2.0f) / (eyePos[2] - zDist);
00620         if (bspheremag > 1.0f)
00621           bspheremag = 1.0f;
00622         break;
00623     }
00624 
00625     ort->set_bg_color_grad_top(backgradienttopcolor);
00626     ort->set_bg_color_grad_bot(backgradientbotcolor);
00627 
00628     float updir[3] = { 0.0f, 1.0f, 0.0f };
00629     ort->set_bg_gradient(updir);
00630 
00631     ort->set_bg_gradient_topval(bspheremag);
00632     ort->set_bg_gradient_botval(-bspheremag);
00633   } else {
00634     ort->set_bg_mode(OptiXRenderer::RT_BACKGROUND_TEXTURE_SOLID);
00635   }
00636 }
00637 
00638 
00640 
00641 void OptiXDisplayDevice::write_header() {
00642   wkf_timer_start(ort_timer);
00643 
00644   // force-dump QuickSurf GPU state, to free up the maximum
00645   // amount of GPU global memory prior to generating the OptiX 
00646   // scene graph and building the OptiX AS structures on the GPU
00647   if (vmdapp) {
00648     // XXX 
00649     // This is currently a very heavy-handed approach that works well
00650     // for batch mode ray tracing or interactive ray tracing of a static
00651     // scene, but will be problematic when we begin doing interactive
00652     // ray tracing of animated trajectories.  When animating a trajectory,
00653     // we'll be bouncing back and forth between QuickSurf and OptiX, 
00654     // and each will need to maintain a significant amount of 
00655     // persistent GPU state for best performance.  
00656     vmdapp->qsurf->free_gpu_memory(); 
00657   }
00658 
00659   ort->setup_context(xSize, ySize);
00660   write_materials();
00661   write_lights();
00662 
00663   ort->set_aa_samples(aasamples); // set with current FileRenderer values
00664 
00665   // render with/without shadows
00666   if (shadows_enabled() || ao_enabled()) {
00667     if (shadows_enabled() && !ao_enabled())
00668       msgInfo << "Shadow rendering enabled." << sendmsg;
00669 
00670     ort->shadows_on(1); // shadowing mode required
00671   } else {
00672     ort->shadows_on(0); // disable shadows by default
00673   }
00674 
00675   // render with ambient occlusion, but only if shadows are also enabled
00676   if (ao_enabled()) {
00677     msgInfo << "Ambient occlusion enabled." << sendmsg;
00678     msgInfo << "Shadow rendering enabled." << sendmsg;
00679     ort->set_ao_samples(aosamples); // set with current FileRenderer values
00680   } else {
00681     ort->set_ao_samples(0); // disable AO rendering entirely
00682   }
00683 
00684   // Always set the AO parameters, that way the user can enable/disable
00685   // AO on-the-fly in the interactive renderer
00686   ort->set_ao_ambient(get_ao_ambient());
00687   ort->set_ao_direct(get_ao_direct());
00688 
00689   // render with depth of field, but only for perspective projection
00690   if (dof_enabled()) {
00691     msgInfo << "DoF focal blur enabled." << sendmsg;
00692     ort->dof_on(1); // enable DoF rendering
00693     ort->set_camera_dof_fnumber(get_dof_fnumber());
00694     ort->set_camera_dof_focal_dist(get_dof_focal_dist());
00695   } else {
00696     ort->dof_on(0); // disable DoF rendering
00697   }
00698 
00699   // set depth cueing parameters
00700   float start = get_cue_start();
00701   float end = get_cue_end();
00702   float density = get_cue_density();
00703   if (cueingEnabled) {
00704     switch (cueMode) {
00705       case CUE_LINEAR:
00706         ort->set_cue_mode(OptiXRenderer::RT_FOG_LINEAR, start, end, density);
00707         break;
00708 
00709       case CUE_EXP:
00710         ort->set_cue_mode(OptiXRenderer::RT_FOG_EXP, start, end, density);
00711         break;
00712 
00713       case CUE_EXP2:
00714         ort->set_cue_mode(OptiXRenderer::RT_FOG_EXP2, start, end, density);
00715         break;
00716 
00717       case NUM_CUE_MODES:
00718         // this should never happen
00719         break;
00720     }
00721   } else {
00722     ort->set_cue_mode(OptiXRenderer::RT_FOG_NONE, start, end, density);
00723   }
00724 }
00725 
00726 
00727 void OptiXDisplayDevice::write_trailer(void){
00728   send_cylinder_buffer(); // send any unsent accumulated cylinder buffer...
00729   send_sphere_buffer();   // send any unsent accumulated sphere buffer...
00730   send_triangle_buffer(); // send any unsent accumulated triangle buffer...
00731 
00732   switch (projection()) {
00733     case DisplayDevice::ORTHOGRAPHIC:
00734       ort->set_camera_projection(OptiXRenderer::RT_ORTHOGRAPHIC);
00735       ort->set_camera_zoom(0.5f / (1.0f / (vSize / 2.0f)));
00736       break;
00737 
00738     case DisplayDevice::PERSPECTIVE:
00739     default:
00740       ort->set_camera_projection(OptiXRenderer::RT_PERSPECTIVE);
00741       ort->set_camera_zoom(0.5f / ((eyePos[2] - zDist) / vSize));
00742   }
00743 
00744   // set stereoscopic display parameters
00745   ort->set_camera_stereo_eyesep(eyeSep);
00746   ort->set_camera_stereo_convergence_dist(eyeDist);
00747 
00748   char *verbstr = getenv("VMDOPTIXVERBOSE");
00749   if (verbstr != NULL) {
00750     if (!strupcmp(verbstr, "TIMING") || !strupcmp(verbstr, "DEBUG")) {
00751       double time_scene_graph = wkf_timer_timenow(ort_timer);
00752       printf("OptiXDisplayDevice) scene graph construction time %.2f\n",
00753              time_scene_graph);
00754     }
00755   }
00756 
00757   // enable output of alpha channel to alpha-capable file formats
00758   int writealpha = 0;
00759   if (getenv("VMDOPTIXWRITEALPHA"))
00760     writealpha=1;
00761 
00762 #if defined(VMDOPTIX_INTERACTIVE_OPENGL)
00763   if (isinteractive) {
00764     if (vmdapp->display->supports_gui()) {
00765       ort->render_to_glwin(my_filename, writealpha); // interactive progressive ray tracer
00766     } else if (vmdapp->uivs->srv_connected()) {
00767       ort->render_to_videostream(my_filename, writealpha); // interactive progressive ray tracer for remote video streaming
00768     }
00769   } else
00770 #else
00771   if (isinteractive && vmdapp->uivs->srv_connected())
00772     ort->render_to_videostream(my_filename, writealpha); // interactive progressive ray tracer for remote video streaming
00773   else
00774 #endif
00775     ort->render_to_file(my_filename, writealpha);  // render the scene in batch mode...
00776 
00777 
00778   // by default the OptiX context is re-used repeatedly,
00779   // but this can be overridden by the user
00780   if (getenv("VMDOPTIXDESTROYCONTEXT") != NULL) {
00781     // destroy the current context, in case we haven't done enough to ensure
00782     // that we're managing memory well without tearing it all down.
00783     delete ort;
00784 
00785     // make a new OptiXRenderer object so we're ready for the next run...
00786     ort = new OptiXRenderer(vmdapp);
00787   } else {
00788     // reset internal state between renders
00789     // reinitialize material cache, clean context state
00790     ort->destroy_scene();
00791   }
00792 
00793   wkf_timer_stop(ort_timer);
00794   printf("OptiXDisplayDevice) Total rendering time: %.2f sec\n", wkf_timer_time(ort_timer));
00795 
00796   reset_vars(); 
00797 }
00798 
00799 
00800 
00801 
00802 

Generated on Fri Apr 19 02:44:49 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002