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: OptiXRenderer.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.391 $ $Date: 2021年12月21日 06:44:17 $ 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 "OptiXRenderer.h" 00079 #include "OptiXShaders.h" 00080 00081 #include <optix.h> 00082 #include <math.h> 00083 #include <stdlib.h> 00084 #include <stdio.h> 00085 #include <string.h> 00086 #if OPTIX_VERSION >= 50200 00087 #include <cuda_runtime.h> // needed for cudaGetDeviceCount() etc 00088 #endif 00089 00090 #if defined(__linux) 00091 #include <unistd.h> // needed for symlink() in movie recorder 00092 #endif 00093 00094 #include "VMDApp.h" // needed for video streaming 00095 #include "VideoStream.h" // needed for video streaming 00096 #include "DisplayDevice.h" // needed for video streaming 00097 00098 #include "Inform.h" 00099 #include "ImageIO.h" 00100 #include "Matrix4.h" 00101 #include "utilities.h" 00102 #include "WKFUtils.h" 00103 #include "ProfileHooks.h" 00104 #if defined(VMDOPTIXRTRT) 00105 #include "DispCmds.h" // needed to process VMDDisplayList command tokens 00106 #endif 00107 00108 // Enable the use of RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS on 00109 // RTX-specific triangle mesh vertex/index buffers optimization 00110 // 00111 // XXX This is presently disabled due to observed performance 00112 // losses compared to self-managed buffer deallocation when 00113 // rendering frames in a tight loop. 00114 // #define VMDOPTIXRTXRELEASEBUFS 1 00115 00116 // Enable HMD if VMD compiled with Oculus VR SDK or OpenHMD 00117 #if defined(VMDUSEOPENHMD) 00118 #define VMDOPTIX_USE_HMD 1 00119 #endif 00120 00121 #if defined(VMDOPTIX_USE_HMD) 00122 #include "HMDMgr.h" 00123 #endif 00124 00125 // support Linux event I/O based joystick/spaceball input 00126 #if defined(VMDUSEEVENTIO) 00127 #include "eventio.h" 00128 #endif 00129 00130 // enable the interactive ray tracing capability 00131 #if defined(VMDOPTIX_INTERACTIVE_OPENGL) 00132 #if (defined(WIN32) || defined(_WIN64)) && defined(_MSC_VER) 00133 #include <windows.h> // must include windows.h prior to GL 00134 #endif 00135 00136 #include <GL/gl.h> 00137 #endif 00138 00139 // the ORT_USE_TEMPLATE_SHADERS macro enables or disables the use of 00140 // an array of template-specialized shaders for every combination of 00141 // scene-wide and material-specific shader features. 00142 #if defined(ORT_USE_TEMPLATE_SHADERS) 00143 static const char *onoffstr(int onoff) { 00144 return (onoff) ? "on" : "off"; 00145 } 00146 #endif 00147 00148 // OptiX 5.2 HW triangle APIs 00149 #define ORT_USE_HW_TRIANGLES 1 00150 00151 // check environment for verbose timing/debugging output flags 00152 static OptiXRenderer::Verbosity get_verbose_flag(int inform=0) { 00153 OptiXRenderer::Verbosity verbose = OptiXRenderer::RT_VERB_MIN; 00154 char *verbstr = getenv("VMDOPTIXVERBOSE"); 00155 if (verbstr != NULL) { 00156 // printf("OptiXRenderer) verbosity config request: '%s'\n", verbstr); 00157 if (!strupcmp(verbstr, "MIN")) { 00158 verbose = OptiXRenderer::RT_VERB_MIN; 00159 if (inform) 00160 printf("OptiXRenderer) verbose setting: minimum\n"); 00161 } else if (!strupcmp(verbstr, "TIMING")) { 00162 verbose = OptiXRenderer::RT_VERB_TIMING; 00163 if (inform) 00164 printf("OptiXRenderer) verbose setting: timing data\n"); 00165 } else if (!strupcmp(verbstr, "DEBUG")) { 00166 verbose = OptiXRenderer::RT_VERB_DEBUG; 00167 if (inform) 00168 printf("OptiXRenderer) verbose setting: full debugging data\n"); 00169 } 00170 } 00171 return verbose; 00172 } 00173 00174 00175 #if 0 00176 // Enable the use of OptiX timeout callbacks to help reduce the likelihood 00177 // of kernel timeouts when rendering on GPUs that are also used for display 00178 #define VMD_ENABLE_OPTIX_TIMEOUTS 1 00179 00180 static int vmd_timeout_init = 0; 00181 static wkf_timerhandle cbtimer; 00182 static float vmd_timeout_lastcallback = 0.0f; 00183 00184 static void vmd_timeout_reset(void) { 00185 if (vmd_timeout_init == 0) { 00186 vmd_timeout_init = 1; 00187 cbtimer = wkf_timer_create(); 00188 } 00189 wkf_timer_start(cbtimer); 00190 vmd_timeout_lastcallback = wkf_timer_timenow(cbtimer); 00191 } 00192 00193 static void vmd_timeout_time(float &deltat, float &totalt) { 00194 double now = wkf_timer_timenow(cbtimer); 00195 deltat = now - vmd_timeout_lastcallback; 00196 totalt = now; 00197 vmd_timeout_lastcallback = now; 00198 } 00199 00200 static int vmd_timeout_cb(void) { 00201 int earlyexit = 0; 00202 float deltat, totalt; 00203 00204 if (vmd_timeout_init == 0) 00205 vmd_timeout_reset(); 00206 00207 vmd_timeout_time(deltat, totalt); 00208 printf("OptiXRenderer) timeout callback: since last %f sec, total %f sec\n", 00209 deltat, totalt); 00210 return earlyexit; 00211 } 00212 00213 #endif 00214 00215 00216 // assumes current scope has Context variable named 'ctx' 00217 #define RTERR( func ) \ 00218 { \ 00219 RTresult code = func; \ 00220 if (code != RT_SUCCESS) { \ 00221 lasterror = code; /* preserve error code for subsequent tests */ \ 00222 const char* message; \ 00223 rtContextGetErrorString(ctx, code, &message); \ 00224 msgErr << "OptiXRenderer) ERROR: " << message << " (" \ 00225 << __FILE__ << ":" << __LINE__ << sendmsg; \ 00226 } \ 00227 } 00228 00229 00230 // assumes current scope has Context variable named 'ctx' 00231 // caller-provided 'code' error return value is used so that subsequent 00232 // code can use that for its own purposes. 00233 #define RTERR2( func, code ) \ 00234 { \ 00235 code = func; \ 00236 if (code != RT_SUCCESS) { \ 00237 lasterror = code; /* preserve error code for subsequent tests */ \ 00238 const char* message; \ 00239 rtContextGetErrorString(ctx, code, &message); \ 00240 msgErr << "OptiXRenderer) ERROR: " << message << " (" \ 00241 << __FILE__ << ":" << __LINE__ << sendmsg; \ 00242 } \ 00243 } 00244 00245 00246 #if defined(ORT_USERTXAPIS) 00247 00248 // 00249 // helper routines for OptiX RTX hardware triangle APIs 00250 // 00251 00252 // helper function that tests triangles for degeneracy and 00253 // computes geometric normals 00254 __forceinline__ int hwtri_test_calc_Ngeom(const float3 * __restrict__ vertices, 00255 float3 &Ngeometric) { 00256 // Compute unnormalized geometric normal 00257 float3 Ng = cross(vertices[1]-vertices[0], vertices[2]-vertices[0]); 00258 00259 // Cull any degenerate triangles 00260 float area = length(Ng); // we want non-zero parallelogram area 00261 if (area > 0.0f && !isinf(area)) { 00262 // finish normalizing the geometric vector 00263 Ngeometric = Ng * (1.0f / area); 00264 return 0; // return success 00265 } 00266 00267 return 1; // cull any triangle that fails area test 00268 } 00269 00270 00271 // helper function to allocate and map RT buffers for hardware triangles 00272 static void hwtri_alloc_bufs_v3f_n4u4_c4u(RTcontext ctx, int numfacets, 00273 RTbuffer &vbuf, float3 *&vertices, 00274 RTbuffer &nbuf, uint4 *&normals, 00275 RTbuffer &cbuf, int numcolors, 00276 uchar4 *&colors, 00277 const float *uniform_color) { 00278 // Create and fill vertex/normal buffers 00279 rtBufferCreate(ctx, RT_BUFFER_INPUT, &vbuf); 00280 rtBufferSetFormat(vbuf, RT_FORMAT_FLOAT3); 00281 rtBufferSetSize1D(vbuf, numfacets * 3); 00282 00283 rtBufferCreate(ctx, RT_BUFFER_INPUT, &nbuf); 00284 rtBufferSetFormat(nbuf, RT_FORMAT_UNSIGNED_INT4); 00285 rtBufferSetSize1D(nbuf, numfacets); 00286 00287 rtBufferCreate(ctx, RT_BUFFER_INPUT, &cbuf); 00288 rtBufferSetFormat(cbuf, RT_FORMAT_UNSIGNED_BYTE4); 00289 rtBufferSetSize1D(cbuf, numcolors); 00290 00291 rtBufferMap(vbuf, (void**) &vertices); 00292 rtBufferMap(nbuf, (void**) &normals); 00293 rtBufferMap(cbuf, (void**) &colors); 00294 00295 if ((numcolors == 1) && (uniform_color != NULL)) { 00296 colors[0].x = uniform_color[0] * 255.0f; 00297 colors[0].y = uniform_color[1] * 255.0f; 00298 colors[0].z = uniform_color[2] * 255.0f; 00299 colors[0].w = 255; 00300 } 00301 } 00302 00303 00304 // helper function to set instance state variables to flag 00305 // the availability of per-vertex normals and colors for the triangle mesh 00306 static void hwtri_set_vertex_flags(RTcontext ctx, 00307 RTgeometryinstance instance_hwtri, 00308 RTbuffer nbuf, RTbuffer cbuf, 00309 int has_vertex_normals, 00310 int has_vertex_colors) { 00311 RTresult lasterror = RT_SUCCESS; 00312 00313 // register normal buffer 00314 RTvariable nbuf_v; 00315 RTERR( rtGeometryInstanceDeclareVariable(instance_hwtri, "normalBuffer", &nbuf_v) ); 00316 RTERR( rtVariableSetObject(nbuf_v, nbuf) ); 00317 00318 // register color buffer 00319 RTvariable cbuf_v; 00320 RTERR( rtGeometryInstanceDeclareVariable(instance_hwtri, "colorBuffer", &cbuf_v) ); 00321 RTERR( rtVariableSetObject(cbuf_v, cbuf) ); 00322 00323 // Enable/disable per-vertex normals (or use geometric normal) 00324 RTvariable has_vertex_normals_v; 00325 RTERR( rtGeometryInstanceDeclareVariable(instance_hwtri, "has_vertex_normals", &has_vertex_normals_v) ); 00326 RTERR( rtVariableSet1i(has_vertex_normals_v, has_vertex_normals) ); 00327 00328 // Enable/disable per-vertex colors (or use uniform color) 00329 RTvariable has_vertex_colors_v; 00330 RTERR( rtGeometryInstanceDeclareVariable(instance_hwtri, "has_vertex_colors", &has_vertex_colors_v) ); 00331 RTERR( rtVariableSet1i(has_vertex_colors_v, has_vertex_colors) ); 00332 00333 if (lasterror != RT_SUCCESS) { 00334 printf("OptiXRenderer::hwtri_set_vertex_flags() error!\n"); 00335 } 00336 } 00337 00338 #endif 00339 00340 00341 #if defined(VMDOPTIX_INTERACTIVE_OPENGL) 00342 00343 static void print_ctx_devices(RTcontext ctx) { 00344 unsigned int devcount = 0; 00345 rtContextGetDeviceCount(ctx, &devcount); 00346 if (devcount > 0) { 00347 int *devlist = (int *) calloc(1, devcount * sizeof(int)); 00348 rtContextGetDevices(ctx, devlist); 00349 printf("OptiXRenderer) Using %d device%s:\n", 00350 devcount, (devcount == 1) ? "" : "s"); 00351 00352 unsigned int d; 00353 for (d=0; d<devcount; d++) { 00354 char devname[20]; 00355 int cudadev=-1, kto=-1; 00356 RTsize totalmem; 00357 memset(devname, 0, sizeof(devname)); 00358 00359 rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_NAME, sizeof(devname), devname); 00360 rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_EXECUTION_TIMEOUT_ENABLED, sizeof(int), &kto); 00361 rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_CUDA_DEVICE_ORDINAL, sizeof(int), &cudadev); 00362 rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_TOTAL_MEMORY, sizeof(totalmem), &totalmem); 00363 00364 printf("OptiXRenderer) [%u] %-19s CUDA[%d], %.1fGB RAM", 00365 d, devname, cudadev, totalmem / (1024.0*1024.0*1024.0)); 00366 if (kto) { 00367 printf(", KTO"); 00368 } 00369 printf("\n"); 00370 } 00371 printf("OptiXRenderer)\n"); 00372 00373 free(devlist); 00374 } 00375 } 00376 00377 #endif 00378 00379 00380 static int query_meminfo_ctx_devices(RTcontext &ctx, unsigned long &freemem, unsigned long &physmem) { 00381 freemem=0; 00382 physmem=0; 00383 RTresult lasterror = RT_SUCCESS; 00384 00385 unsigned int devcount = 0; 00386 RTERR( rtContextGetDeviceCount(ctx, &devcount) ); 00387 if (devcount > 0) { 00388 int *devlist = (int *) calloc(1, devcount * sizeof(int)); 00389 RTERR( rtContextGetDevices(ctx, devlist) ); 00390 unsigned int d; 00391 for (d=0; d<devcount; d++) { 00392 RTsize freememsz=0; 00393 RTsize physmemsz=0; 00394 int ordinal = devlist[d]; 00395 RTERR( rtContextGetAttribute(ctx, static_cast<RTcontextattribute>(RT_CONTEXT_ATTRIBUTE_AVAILABLE_DEVICE_MEMORY+ordinal), sizeof(freememsz), &freememsz) ); 00396 if (lasterror != RT_SUCCESS) { 00397 free(devlist); 00398 return -1; 00399 } 00400 00401 RTERR( rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_TOTAL_MEMORY, sizeof(physmemsz), &physmemsz) ); 00402 if (lasterror != RT_SUCCESS) { 00403 free(devlist); 00404 return -1; 00405 } 00406 00407 if (d==0) { 00408 freemem = freememsz; 00409 physmem = physmemsz; 00410 } else { 00411 if (freemem < freememsz) 00412 freemem = freememsz; 00413 00414 if (physmem < physmemsz) 00415 physmem = physmemsz; 00416 } 00417 } 00418 free(devlist); 00419 return 0; 00420 } 00421 00422 return -1; 00423 } 00424 00425 00426 int OptiXPrintRayStats(RTbuffer raystats1_buffer, RTbuffer raystats2_buffer, 00427 double rtruntime) { 00428 int rc = 0; 00429 RTcontext ctx; 00430 RTresult result; 00431 RTsize buffer_width, buffer_height; 00432 const char* error; 00433 00434 rtBufferGetContext(raystats1_buffer, &ctx); 00435 00436 // buffer must be 2-D (for now) 00437 unsigned int bufdim; 00438 if (rtBufferGetDimensionality(raystats1_buffer, &bufdim) != RT_SUCCESS) { 00439 msgErr << "OptiXPrintRayStats: Failed to get ray stats buffer dimensions!" << sendmsg; 00440 return -1; 00441 } 00442 if (bufdim != 2) { 00443 msgErr << "OptiXPrintRayStats: Output buffer is not 2-D!" << sendmsg; 00444 return -1; 00445 } 00446 00447 result = rtBufferGetSize2D(raystats1_buffer, &buffer_width, &buffer_height); 00448 if (result != RT_SUCCESS) { 00449 // Get error from context 00450 rtContextGetErrorString(ctx, result, &error); 00451 msgErr << "OptiXRenderer) Error getting dimensions of buffers: " << error << sendmsg; 00452 return -1; 00453 } 00454 00455 volatile uint4 *raystats1, *raystats2; 00456 result = rtBufferMap(raystats1_buffer, (void**) &raystats1); 00457 result = rtBufferMap(raystats2_buffer, (void**) &raystats2); 00458 if (result != RT_SUCCESS) { 00459 rtContextGetErrorString(ctx, result, &error); 00460 msgErr << "OptiXPrintRayStats: Error mapping stats buffers: " 00461 << error << sendmsg; 00462 return -1; 00463 } 00464 00465 // no stats data 00466 if (buffer_width < 1 || buffer_height < 1 || 00467 raystats1 == NULL || raystats2 == NULL) { 00468 msgErr << "OptiXPrintRayStats: No data in ray stats buffers!" << sendmsg; 00469 return -1; 00470 } 00471 00472 // collect and sum all per-pixel ray stats 00473 int i; 00474 int totalsz = buffer_width * buffer_height; 00475 unsigned long misses, transkips; 00476 unsigned long primaryrays, shadowlights, shadowao, transrays, reflrays; 00477 misses = transkips = primaryrays = shadowlights 00478 = shadowao = transrays = reflrays = 0; 00479 00480 // accumulate per-pixel ray stats into totals 00481 for (i=0; i<totalsz; i++) { 00482 primaryrays += raystats1[i].x; 00483 shadowlights += raystats1[i].y; 00484 shadowao += raystats1[i].z; 00485 misses += raystats1[i].w; 00486 transrays += raystats2[i].x; 00487 transkips += raystats2[i].y; 00488 // XXX raystats2[i].z unused at present... 00489 reflrays += raystats2[i].w; 00490 } 00491 unsigned long totalrays = primaryrays + shadowlights + shadowao 00492 + transrays + reflrays; 00493 00494 printf("OptiXRenderer)\n"); 00495 printf("OptiXRenderer) VMD/OptiX Scene Ray Tracing Statistics:\n"); 00496 printf("OptiXRenderer) ----------------------------------------\n"); 00497 printf("OptiXRenderer) Image resolution: %lu x %lu \n", 00498 buffer_width, buffer_height); 00499 printf("OptiXRenderer) ----------------------------------------\n"); 00500 printf("OptiXRenderer) Misses: %lu\n", misses); 00501 printf("OptiXRenderer) Transmission Any-Hit Skips: %lu\n", transkips); 00502 printf("OptiXRenderer) ----------------------------------------\n"); 00503 printf("OptiXRenderer) Primary Rays: %lu\n", primaryrays); 00504 printf("OptiXRenderer) Dir-Light Shadow Rays: %lu\n", shadowlights); 00505 printf("OptiXRenderer) AO Shadow Rays: %lu\n", shadowao); 00506 printf("OptiXRenderer) Transmission Rays: %lu\n", transrays); 00507 printf("OptiXRenderer) Reflection Rays: %lu\n", reflrays); 00508 printf("OptiXRenderer) ----------------------------------------\n"); 00509 printf("OptiXRenderer) Total Rays: %lu\n", totalrays); 00510 printf("OptiXRenderer) Total Rays: %g\n", totalrays * 1.0); 00511 if (rtruntime > 0.0) { 00512 printf("OptiXRenderer) Rays/sec: %g\n", totalrays / rtruntime); 00513 } 00514 printf("OptiXRenderer)\n"); 00515 00516 result = rtBufferUnmap(raystats1_buffer); 00517 result = rtBufferUnmap(raystats2_buffer); 00518 if (result != RT_SUCCESS) { 00519 rtContextGetErrorString(ctx, result, &error); 00520 msgErr << "OptiXPrintRayStats: Error unmapping ray stats buffer: " 00521 << error << sendmsg; 00522 return -1; 00523 } 00524 00525 return rc; 00526 } 00527 00528 00529 int OptiXWriteImage(const char* filename, int writealpha, 00530 RTbuffer buffer, RTformat buffer_format, 00531 RTsize buffer_width, RTsize buffer_height) { 00532 RTresult result; 00533 00534 void * imageData; 00535 result = rtBufferMap(buffer, &imageData); 00536 if (result != RT_SUCCESS) { 00537 RTcontext ctx; 00538 const char* error; 00539 rtBufferGetContext(buffer, &ctx); 00540 rtContextGetErrorString(ctx, result, &error); 00541 msgErr << "OptiXWriteImage: Error mapping image buffer: " 00542 << error << sendmsg; 00543 return -1; 00544 } 00545 00546 // no image data 00547 if (buffer_width < 1 || buffer_height < 1 || imageData == NULL) { 00548 msgErr << "OptiXWriteImage: No image data in output buffer!" << sendmsg; 00549 return -1; 00550 } 00551 00552 // write the image to a file, according to the buffer format 00553 int xs = buffer_width; 00554 int ys = buffer_height; 00555 int rc = 0; 00556 if (buffer_format == RT_FORMAT_FLOAT4) { 00557 if (writealpha) { 00558 //printf("Writing rgba4f alpha channel output image 2\n"); 00559 if (write_image_file_rgba4f(filename, (const float *) imageData, xs, ys)) 00560 rc = -1; 00561 } else { 00562 if (write_image_file_rgb4f(filename, (const float *) imageData, xs, ys)) 00563 rc = -1; 00564 } 00565 } else if (buffer_format == RT_FORMAT_UNSIGNED_BYTE4) { 00566 if (writealpha) { 00567 //printf("Writing rgba4u alpha channel output image 2\n"); 00568 if (write_image_file_rgba4u(filename, (const unsigned char *) imageData, xs, ys)) 00569 rc = -1; 00570 } else { 00571 if (write_image_file_rgb4u(filename, (const unsigned char *) imageData, xs, ys)) 00572 rc = -1; 00573 } 00574 } else { 00575 rc = -1; 00576 } 00577 00578 result = rtBufferUnmap(buffer); 00579 if (result != RT_SUCCESS) { 00580 RTcontext ctx; 00581 const char* error; 00582 rtBufferGetContext(buffer, &ctx); 00583 rtContextGetErrorString(ctx, result, &error); 00584 msgErr << "OptiXWriteImage: Error unmapping image buffer: " 00585 << error << sendmsg; 00586 return -1; 00587 } 00588 00589 return rc; 00590 } 00591 00592 00593 int OptiXWriteImage(const char* filename, int writealpha, RTbuffer buffer) { 00594 RTresult result; 00595 RTformat buffer_format; 00596 RTsize buffer_width, buffer_height; 00597 00598 // buffer must be 2-D 00599 unsigned int bufdim; 00600 if (rtBufferGetDimensionality(buffer, &bufdim) != RT_SUCCESS) { 00601 msgErr << "OptiXWriteImage: Failed to get output buffer dimensions!" << sendmsg; 00602 return -1; 00603 } 00604 00605 if (bufdim != 2) { 00606 msgErr << "OptiXWriteImage: Output buffer is not 2-D!" << sendmsg; 00607 return -1; 00608 } 00609 00610 void * imageData; 00611 result = rtBufferMap(buffer, &imageData); 00612 if (result != RT_SUCCESS) { 00613 RTcontext ctx; 00614 const char* error; 00615 rtBufferGetContext(buffer, &ctx); 00616 rtContextGetErrorString(ctx, result, &error); 00617 msgErr << "OptiXWriteImage: Error mapping image buffer: " 00618 << error << sendmsg; 00619 return -1; 00620 } 00621 00622 // no image data 00623 if (imageData == NULL) { 00624 msgErr << "OptiXWriteImage: No image data in output buffer!" << sendmsg; 00625 return -1; 00626 } 00627 00628 result = rtBufferGetSize2D(buffer, &buffer_width, &buffer_height); 00629 if (result != RT_SUCCESS) { 00630 // Get error from context 00631 RTcontext ctx; 00632 const char* error; 00633 rtBufferGetContext(buffer, &ctx); 00634 rtContextGetErrorString(ctx, result, &error); 00635 msgErr << "OptiXRenderer) Error getting dimensions of buffer: " << error << sendmsg; 00636 return -1; 00637 } 00638 00639 if (rtBufferGetFormat(buffer, &buffer_format) != RT_SUCCESS) { 00640 msgErr << "OptiXWriteImage: failed to query output buffer format!" 00641 << sendmsg; 00642 return -1; 00643 } 00644 00645 // write the image to a file, according to the buffer format 00646 int xs = buffer_width; 00647 int ys = buffer_height; 00648 int rc = 0; 00649 00650 if (buffer_format == RT_FORMAT_FLOAT4) { 00651 if (writealpha) { 00652 //printf("Writing rgba4f alpha channel output image 1\n"); 00653 if (write_image_file_rgba4f(filename, (const float *) imageData, xs, ys)) 00654 rc = -1; 00655 } else { 00656 if (write_image_file_rgb4f(filename, (const float *) imageData, xs, ys)) 00657 rc = -1; 00658 } 00659 } else if (buffer_format == RT_FORMAT_UNSIGNED_BYTE4) { 00660 if (writealpha) { 00661 //printf("Writing rgba4u alpha channel output image 1\n"); 00662 if (write_image_file_rgba4u(filename, (const unsigned char *) imageData, xs, ys)) 00663 rc = -1; 00664 } else { 00665 if (write_image_file_rgb4u(filename, (const unsigned char *) imageData, xs, ys)) 00666 rc = -1; 00667 } 00668 } else { 00669 rc = -1; 00670 } 00671 00672 result = rtBufferUnmap(buffer); 00673 if (result != RT_SUCCESS) { 00674 RTcontext ctx; 00675 const char* error; 00676 rtBufferGetContext(buffer, &ctx); 00677 rtContextGetErrorString(ctx, result, &error); 00678 msgErr << "OptiXWriteImage: Error unmapping image buffer: " 00679 << error << sendmsg; 00680 return -1; 00681 } 00682 00683 return rc; 00684 } 00685 00686 00688 OptiXRenderer::OptiXRenderer(VMDApp *vmdapp) { 00689 PROFILE_PUSH_RANGE("OptiXRenderer::OptiXRenderer()", 0); 00690 app = vmdapp; // store VMDApp ptr for video streaming 00691 ort_timer = wkf_timer_create(); // create and initialize timer 00692 wkf_timer_start(ort_timer); 00693 00694 // setup path to pre-compiled shader PTX code 00695 const char *vmddir = getenv("VMDDIR"); 00696 if (vmddir == NULL) 00697 vmddir = "."; 00698 sprintf(shaderpath, "%s/shaders/%s", vmddir, "OptiXShaders.ptx"); 00699 00700 // allow runtime override of the default shader path for testing 00701 if (getenv("VMDOPTIXSHADERPATH")) { 00702 strcpy(shaderpath, getenv("VMDOPTIXSHADERPATH")); 00703 msgInfo << "User-override of OptiX shader path: " << getenv("VMDOPTIXSHADERPATH") << sendmsg; 00704 } 00705 00706 #if defined(ORT_USERTXAPIS) 00707 rtx_enabled = 1; // RTX execution mode enabled 00708 hwtri_enabled = 1; // RTX hardware triangle APIs enabled by default 00709 #endif 00710 00711 lasterror = RT_SUCCESS; // begin with no error state set 00712 context_created = 0; // no context yet 00713 buffers_allocated = 0; // flag no buffer allocated yet 00714 buffers_progressive = 0; // buf bound using progressive API or not 00715 scene_created = 0; // scene has been created 00716 00717 // clear timers 00718 time_ctx_setup = 0.0; 00719 time_ctx_validate = 0.0; 00720 time_ctx_AS_build = 0.0; 00721 time_ray_tracing = 0.0; 00722 time_image_io = 0.0; 00723 00724 // set default scene background state 00725 scene_background_mode = RT_BACKGROUND_TEXTURE_SOLID; 00726 memset(scene_bg_color, 0, sizeof(scene_bg_color)); 00727 memset(scene_bg_grad_top, 0, sizeof(scene_bg_grad_top)); 00728 memset(scene_bg_grad_bot, 0, sizeof(scene_bg_grad_bot)); 00729 memset(scene_gradient, 0, sizeof(scene_gradient)); 00730 scene_gradient_topval = 1.0f; 00731 scene_gradient_botval = 0.0f; 00732 // XXX this has to be recomputed prior to rendering.. 00733 scene_gradient_invrange = 1.0f / (scene_gradient_topval - scene_gradient_botval); 00734 00735 // zero out the array of material usage counts for the scene 00736 memset(material_special_counts, 0, sizeof(material_special_counts)); 00737 00738 cam_zoom = 1.0f; 00739 cam_stereo_eyesep = 0.06f; 00740 cam_stereo_convergence_dist = 2.0f; 00741 00742 clipview_mode = RT_CLIP_NONE; // VR HMD fade+clipping plane/sphere 00743 clipview_start = 1.0f; // VR HMD fade+clipping radial start dist 00744 clipview_end = 0.2f; // VR HMD fade+clipping radial end dist 00745 00746 // check for VR headlight and HMD/camera view clipping plane/sphere 00747 if (getenv("VMDOPTIXCLIPVIEW")) { 00748 clipview_mode = RT_CLIP_SPHERE; 00749 msgInfo << "OptiXRenderer) Overriding default clipping mode with RT_CLIP_SPHERE" << sendmsg; 00750 } 00751 if (getenv("VMDOPTIXCLIPVIEWSTART")) { 00752 clipview_start = float(atof(getenv("VMDOPTIXCLIPVIEWSTART"))); 00753 msgInfo << "OptiXRenderer) Overriding default clipping start: " 00754 << clipview_start << sendmsg; 00755 } 00756 if (getenv("VMDOPTIXCLIPVIEWEND")) { 00757 clipview_start = float(atof(getenv("VMDOPTIXCLIPVIEWEND"))); 00758 msgInfo << "OptiXRenderer) Overriding default clipping end: " 00759 << clipview_start << sendmsg; 00760 } 00761 00762 headlight_mode = RT_HEADLIGHT_OFF; // VR HMD headlight disabled by default 00763 if (getenv("VMDOPTIXHEADLIGHT")) { 00764 headlight_mode = RT_HEADLIGHT_ON; 00765 msgInfo << "OptiXRenderer) Overriding default headlight mode with RT_HEADLIGHT_ON" << sendmsg; 00766 } 00767 00768 shadows_enabled = RT_SHADOWS_OFF; // disable shadows by default 00769 aa_samples = 0; // no AA samples by default 00770 00771 ao_samples = 0; // no AO samples by default 00772 ao_direct = 0.3f; // AO direct contribution is 30% 00773 ao_ambient = 0.7f; // AO ambient contribution is 70% 00774 ao_maxdist = RT_DEFAULT_MAX; // default is no max occlusion distance 00775 00776 dof_enabled = 0; // disable DoF by default 00777 cam_dof_focal_dist = 2.0f; 00778 cam_dof_fnumber = 64.0f; 00779 00780 fog_mode = RT_FOG_NONE; // fog/cueing disabled by default 00781 fog_start = 0.0f; 00782 fog_end = 10.0f; 00783 fog_density = 0.32f; 00784 00785 verbose = RT_VERB_MIN; // keep console quiet except for perf/debugging cases 00786 check_verbose_env(); // see if the user has overridden verbose flag 00787 00788 create_context(); 00789 destroy_scene(); // zero out object counters, prepare for rendering 00790 00791 PROFILE_POP_RANGE(); 00792 } 00793 00795 OptiXRenderer::~OptiXRenderer(void) { 00796 PROFILE_PUSH_RANGE("OptiXRenderer::~OptiXRenderer()", 0); 00797 00798 if (context_created) 00799 destroy_context(); 00800 wkf_timer_destroy(ort_timer); 00801 00802 PROFILE_POP_RANGE(); 00803 } 00804 00805 00806 void OptiXRenderer::check_verbose_env() { 00807 verbose = get_verbose_flag(1); 00808 } 00809 00810 00811 00812 // 00813 // This routine enumerates the set of GPUs that are usable by OptiX, 00814 // both in terms of their compatibility with the OptiX library we have 00815 // compiled against, and also in terms of user preferences to exclude 00816 // particular GPUs, GPUs that have displays attached, and so on. 00817 // 00818 unsigned int OptiXRenderer::device_list(int **devlist, char ***devnames) { 00819 OptiXRenderer::Verbosity dl_verbose = get_verbose_flag(); 00820 if (dl_verbose == RT_VERB_DEBUG) 00821 printf("OptiXRenderer) OptiXRenderer::device_list()\n"); 00822 00823 unsigned int count=0; 00824 RTresult devcntresult = rtDeviceGetDeviceCount(&count); 00825 if (devcntresult != RT_SUCCESS) { 00826 #if OPTIX_VERSION >= 50200 00827 if (devcntresult == RT_ERROR_OPTIX_NOT_LOADED) { 00828 int cudadevcount = 0; 00829 cudaGetDeviceCount(&cudadevcount); 00830 if (cudadevcount > 0) { 00831 printf("OptiXRenderer) ERROR: Failed to load OptiX shared library.\n"); 00832 printf("OptiXRenderer) NVIDIA driver may be too old.\n"); 00833 printf("OptiXRenderer) Check/update NVIDIA driver\n"); 00834 } 00835 } 00836 #endif 00837 00838 if (dl_verbose == RT_VERB_DEBUG) { 00839 printf("OptiXRenderer) rtDeviceGetDeviceCount() returned error %08x\n", 00840 devcntresult); 00841 printf("OptiXRenderer) No GPUs available\n"); 00842 } 00843 00844 count = 0; 00845 if (devlist != NULL) 00846 *devlist = NULL; 00847 if (devnames != NULL) 00848 *devnames = NULL; 00849 00850 return 0; 00851 } 00852 00853 if (dl_verbose == RT_VERB_DEBUG) { 00854 printf("OptiXRenderer) OptiX rtDeviceGetDeviceCount() reports\n"); 00855 printf("OptiXRenderer) that %d GPUs are available\n", count); 00856 } 00857 00858 // check to see if the user wants to limit what device(s) are used 00859 unsigned int gpumask = 0xffffffff; 00860 const char *gpumaskstr = getenv("VMDOPTIXDEVICEMASK"); 00861 if (gpumaskstr != NULL) { 00862 unsigned int tmp; 00863 if (sscanf(gpumaskstr, "%x", &tmp) == 1) { 00864 gpumask = tmp; 00865 msgInfo << "Using OptiX device mask '" 00866 << gpumaskstr << "'" << sendmsg; 00867 } else { 00868 msgInfo << "Failed to parse OptiX GPU device mask string '" 00869 << gpumaskstr << "'" << sendmsg; 00870 } 00871 } 00872 00873 if (devlist != NULL) { 00874 *devlist = NULL; 00875 if (count > 0) { 00876 *devlist = (int *) calloc(1, count * sizeof(int)); 00877 } 00878 } 00879 if (devnames != NULL) { 00880 *devnames = NULL; 00881 if (count > 0) { 00882 *devnames = (char **) calloc(1, count * sizeof(char *)); 00883 } 00884 } 00885 00886 // walk through the list of available devices and screen out 00887 // any that may cause problems with the version of OptiX we are using 00888 unsigned int i, goodcount; 00889 for (goodcount=0,i=0; i<count; i++) { 00890 // check user-defined GPU device mask for OptiX... 00891 if (!(gpumask & (1 << i))) { 00892 if (dl_verbose == RT_VERB_DEBUG) { 00893 char msgbuf[1024]; 00894 sprintf(msgbuf, " Excluded GPU[%d] due to user-specified device mask\n", i); 00895 msgInfo << msgbuf << sendmsg; 00896 } 00897 continue; 00898 } 00899 00900 // check user-requested exclusion of devices with display timeouts enabled 00901 int timeoutenabled; 00902 rtDeviceGetAttribute(i, RT_DEVICE_ATTRIBUTE_EXECUTION_TIMEOUT_ENABLED, 00903 sizeof(int), &timeoutenabled); 00904 if (timeoutenabled && getenv("VMDOPTIXNODISPLAYGPUS")) { 00905 if (dl_verbose == RT_VERB_DEBUG) { 00906 char msgbuf[1024]; 00907 sprintf(msgbuf, " Excluded GPU[%d] due to user-specified display timeout exclusion \n", i); 00908 msgInfo << msgbuf << sendmsg; 00909 } 00910 continue; 00911 } 00912 00913 // 00914 // screen for viable compute capability for this version of OptiX 00915 // 00916 // XXX this should be unnecessary with OptiX 3.6.x and later (I hope) 00917 // 00918 int compute_capability[2]; 00919 rtDeviceGetAttribute(i, RT_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY, 00920 sizeof(compute_capability), compute_capability); 00921 // printf("OptiX GPU[%d] compute capability %d\n", i, compute_capability[0]); 00922 #if OPTIX_VERSION <= 3051 00923 // exclude Maxwell and later GPUs if we're running OptiX 3.5.1 or earlier 00924 if (compute_capability[0] > 3) { 00925 if (dl_verbose == RT_VERB_DEBUG) { 00926 char msgbuf[1024]; 00927 sprintf(msgbuf, " Excluded GPU[%d] due to unsupported compute capability\n", i); 00928 msgInfo << msgbuf << sendmsg; 00929 } 00930 continue; 00931 } 00932 #endif 00933 00934 // record all usable GPUs we find... 00935 if (dl_verbose == RT_VERB_DEBUG) { 00936 char msgbuf[1024]; 00937 sprintf(msgbuf, "Found usable GPU[%i]\n", i); 00938 msgInfo << msgbuf << sendmsg; 00939 } 00940 00941 if (devlist != NULL) { 00942 if (dl_verbose == RT_VERB_DEBUG) { 00943 char msgbuf[1024]; 00944 sprintf(msgbuf, " Adding usable GPU[%i] to list[%d]\n", i, goodcount); 00945 msgInfo << msgbuf << sendmsg; 00946 } 00947 (*devlist)[goodcount] = i; 00948 } 00949 00950 if (devnames != NULL) { 00951 char *namebuf = (char *) calloc(1, 65 * sizeof(char)); 00952 rtDeviceGetAttribute(i, RT_DEVICE_ATTRIBUTE_NAME, 00953 64*sizeof(char), namebuf); 00954 if (dl_verbose == RT_VERB_DEBUG) { 00955 char msgbuf[1024]; 00956 sprintf(msgbuf, " Adding usable GPU[%i] to list[%d]: '%s'\n", i, goodcount, namebuf); 00957 msgInfo << msgbuf << sendmsg; 00958 } 00959 (*devnames)[goodcount] = namebuf; 00960 } 00961 goodcount++; 00962 } 00963 00964 return goodcount; 00965 } 00966 00967 00968 unsigned int OptiXRenderer::device_count(void) { 00969 OptiXRenderer::Verbosity dl_verbose = get_verbose_flag(); 00970 if (dl_verbose == RT_VERB_DEBUG) 00971 printf("OptiXRenderer) OptiXRenderer::device_count()\n"); 00972 00973 #if 1 00974 return device_list(NULL, NULL); 00975 #else 00976 unsigned int count=0; 00977 if (rtDeviceGetDeviceCount(&count) != RT_SUCCESS) 00978 count = 0; 00979 return count; 00980 #endif 00981 } 00982 00983 00984 unsigned int OptiXRenderer::optix_version(void) { 00985 OptiXRenderer::Verbosity dl_verbose = get_verbose_flag(); 00986 if (dl_verbose == RT_VERB_DEBUG) 00987 msgInfo << "OptiXRenderer) OptiXRenderer::optix_version()" << sendmsg; 00988 00989 unsigned int version=0; 00990 if (rtGetVersion(&version) != RT_SUCCESS) 00991 version = 0; 00992 return version; 00993 } 00994 00995 00996 int OptiXRenderer::material_shader_table_size(void) { 00997 // used for initialization info printed to console 00998 #if defined(ORT_USE_TEMPLATE_SHADERS) 00999 return ORTMTABSZ; 01000 #else 01001 return 1; 01002 #endif 01003 } 01004 01005 01006 void OptiXRenderer::create_context() { 01007 time_ctx_create = 0; 01008 if (context_created) 01009 return; 01010 01011 double starttime = wkf_timer_timenow(ort_timer); 01012 01013 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating context...\n"); 01014 01015 #if defined(ORT_USERTXAPIS) 01016 // Starting with OptiX 6.0.0, the OptiX runtime can select either an 01017 // RTX execution strategy, or a classic non-RTX execution strategy 01018 // using a new global API flag that takes effect at context creation time. 01019 // RTX mode is only supported on Maxwell and later 01020 // GPUs, earlier Kepler hardware do not support RTX mode. 01021 int rtxonoff = 1; 01022 if (getenv("VMDOPTIXNORTX") != NULL) { 01023 rtxonoff = 0; 01024 01025 // if the RTX mode isn't on, then we can't use the hardware triangle APIs. 01026 rtx_enabled = 0; 01027 hwtri_enabled = 0; 01028 } 01029 01030 // The OptiX RTX execution strategy mode has to be set very early on, 01031 // otherwise the API call will return without error, but the OptiX 01032 // runtime will ignore the state change and continue with the existing 01033 // execution strategy (e.g. the default of '0' if set too late...) 01034 if (rtGlobalSetAttribute(RT_GLOBAL_ATTRIBUTE_ENABLE_RTX, sizeof(rtxonoff), &rtxonoff) != RT_SUCCESS) { 01035 printf("OptiXRenderer) Error setting RT_GLOBAL_ATTRIBUTE_ENABLE_RTX!!!\n"); 01036 } else { 01037 if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) 01038 printf("OptiXRenderer) OptiX RTX execution mode is %s.\n", 01039 (rtxonoff) ? "on" : "off"); 01040 } 01041 #endif 01042 01043 // Create our objects and set state 01044 RTresult ctxrc; 01045 RTERR2( rtContextCreate(&ctx), ctxrc ); 01046 if (ctxrc != RT_SUCCESS) { 01047 msgErr << "OptiXRenderer) Failed to create OptiX rendering context" << sendmsg; 01048 context_created=0; 01049 return; 01050 } 01051 01052 // screen and set what GPU device(s) are used for this context 01053 // We shouldn't need the compute capability exclusions post-OptiX 3.6.x, 01054 // but this will benefit from other updates. 01055 if (getenv("VMDOPTIXDEVICEMASK") != NULL) { 01056 int *optixdevlist; 01057 int optixdevcount = device_list(&optixdevlist, NULL); 01058 if (optixdevcount > 0) { 01059 RTERR( rtContextSetDevices(ctx, optixdevcount, optixdevlist) ); 01060 } 01061 free(optixdevlist); 01062 } else if (getenv("VMDOPTIXDEVICE") != NULL) { 01063 int optixdev = atoi(getenv("VMDOPTIXDEVICE")); 01064 msgInfo << "Setting OptiX GPU device to: " << optixdev << sendmsg; 01065 RTERR( rtContextSetDevices(ctx, 1, &optixdev) ); 01066 } 01067 01068 // register ray types for both shadow and radiance rays 01069 RTERR( rtContextSetRayTypeCount(ctx, RT_RAY_TYPE_COUNT) ); 01070 01071 // flag to indicate whether we're running in progressive mode or not 01072 RTERR( rtContextDeclareVariable(ctx, "progressive_enabled", &progressive_enabled_v) ); 01073 RTERR( rtVariableSet1i(progressive_enabled_v, 0) ); 01074 01075 // declare various internal state variables 01076 RTERR( rtContextDeclareVariable(ctx, "max_depth", &max_depth_v) ); 01077 RTERR( rtContextDeclareVariable(ctx, "max_trans", &max_trans_v) ); 01078 RTERR( rtContextDeclareVariable(ctx, "radiance_ray_type", &radiance_ray_type_v) ); 01079 RTERR( rtContextDeclareVariable(ctx, "shadow_ray_type", &shadow_ray_type_v) ); 01080 RTERR( rtContextDeclareVariable(ctx, "scene_epsilon", &scene_epsilon_v) ); 01081 01082 // create light buffers/variables now, populate at render time... 01083 #if defined(VMDOPTIX_LIGHTUSEROBJS) 01084 RTERR( rtContextDeclareVariable(ctx, "dir_light_list", &dir_light_list_v) ); 01085 RTERR( rtContextDeclareVariable(ctx, "pos_light_list", &pos_light_list_v) ); 01086 #else 01087 RTERR( rtContextDeclareVariable(ctx, "dir_lights", &dir_lightbuffer_v) ); 01088 RTERR( rtBufferCreate(ctx, RT_BUFFER_INPUT, &dir_lightbuffer) ); 01089 RTERR( rtBufferSetFormat(dir_lightbuffer, RT_FORMAT_USER) ); 01090 RTERR( rtBufferSetElementSize(dir_lightbuffer, sizeof(DirectionalLight)) ); 01091 01092 RTERR( rtContextDeclareVariable(ctx, "pos_lights", &pos_lightbuffer_v) ); 01093 RTERR( rtBufferCreate(ctx, RT_BUFFER_INPUT, &pos_lightbuffer) ); 01094 RTERR( rtBufferSetFormat(pos_lightbuffer, RT_FORMAT_USER) ); 01095 RTERR( rtBufferSetElementSize(pos_lightbuffer, sizeof(PositionalLight)) ); 01096 #endif 01097 01098 // Current accumulation subframe count, used as part of generating 01099 // AA and AO random number sequences 01100 RTERR( rtContextDeclareVariable(ctx, "accumCount", &accum_count_v) ); 01101 RTERR( rtVariableSet1ui(accum_count_v, 0) ); 01102 01103 // AO direct lighting scale factors, max occlusion distance 01104 RTERR( rtContextDeclareVariable(ctx, "ao_direct", &ao_direct_v) ); 01105 RTERR( rtContextDeclareVariable(ctx, "ao_ambient", &ao_ambient_v) ); 01106 RTERR( rtContextDeclareVariable(ctx, "ao_maxdist", &ao_maxdist_v) ); 01107 01108 // shadows, antialiasing, ambient occlusion 01109 RTERR( rtContextDeclareVariable(ctx, "shadows_enabled", &shadows_enabled_v) ); 01110 RTERR( rtContextDeclareVariable(ctx, "aa_samples", &aa_samples_v) ); 01111 RTERR( rtContextDeclareVariable(ctx, "ao_samples", &ao_samples_v) ); 01112 01113 // background color / gradient 01114 RTERR( rtContextDeclareVariable(ctx, "scene_bg_color", &scene_bg_color_v) ); 01115 RTERR( rtContextDeclareVariable(ctx, "scene_bg_color_grad_top", &scene_bg_grad_top_v) ); 01116 RTERR( rtContextDeclareVariable(ctx, "scene_bg_color_grad_bot", &scene_bg_grad_bot_v) ); 01117 RTERR( rtContextDeclareVariable(ctx, "scene_gradient", &scene_gradient_v) ); 01118 RTERR( rtContextDeclareVariable(ctx, "scene_gradient_topval", &scene_gradient_topval_v) ); 01119 RTERR( rtContextDeclareVariable(ctx, "scene_gradient_botval", &scene_gradient_botval_v) ); 01120 RTERR( rtContextDeclareVariable(ctx, "scene_gradient_invrange", &scene_gradient_invrange_v) ); 01121 01122 // VR HMD variables 01123 RTERR( rtContextDeclareVariable(ctx, "clipview_mode", &clipview_mode_v) ); 01124 RTERR( rtContextDeclareVariable(ctx, "clipview_start", &clipview_start_v) ); 01125 RTERR( rtContextDeclareVariable(ctx, "clipview_end", &clipview_end_v) ); 01126 RTERR( rtContextDeclareVariable(ctx, "headlight_mode", &headlight_mode_v) ); 01127 01128 // cueing/fog variables 01129 RTERR( rtContextDeclareVariable(ctx, "fog_mode", &fog_mode_v) ); 01130 RTERR( rtContextDeclareVariable(ctx, "fog_start", &fog_start_v) ); 01131 RTERR( rtContextDeclareVariable(ctx, "fog_end", &fog_end_v) ); 01132 RTERR( rtContextDeclareVariable(ctx, "fog_density", &fog_density_v) ); 01133 01134 // variables for top level scene graph objects 01135 RTERR( rtContextDeclareVariable(ctx, "root_object", &root_object_v) ); 01136 RTERR( rtContextDeclareVariable(ctx, "root_shadower", &root_shadower_v) ); 01137 01138 // define all of the standard camera params 01139 RTERR( rtContextDeclareVariable(ctx, "cam_zoom", &cam_zoom_v) ); 01140 RTERR( rtContextDeclareVariable(ctx, "cam_pos", &cam_pos_v) ); 01141 RTERR( rtContextDeclareVariable(ctx, "cam_U", &cam_U_v) ); 01142 RTERR( rtContextDeclareVariable(ctx, "cam_V", &cam_V_v) ); 01143 RTERR( rtContextDeclareVariable(ctx, "cam_W", &cam_W_v) ); 01144 01145 // define stereoscopic camera parameters 01146 RTERR( rtContextDeclareVariable(ctx, "cam_stereo_eyesep", &cam_stereo_eyesep_v) ); 01147 RTERR( rtContextDeclareVariable(ctx, "cam_stereo_convergence_dist", &cam_stereo_convergence_dist_v) ); 01148 01149 // define camera DoF parameters 01150 RTERR( rtContextDeclareVariable(ctx, "cam_dof_focal_dist", &cam_dof_focal_dist_v) ); 01151 RTERR( rtContextDeclareVariable(ctx, "cam_dof_aperture_rad", &cam_dof_aperture_rad_v) ); 01152 01153 RTERR( rtContextDeclareVariable(ctx, "accumulation_normalization_factor", &accum_norm_v) ); 01154 01155 01156 // 01157 // allow runtime override of the default shader path for testing 01158 // this has to be done prior to all calls that load programs from 01159 // the shader PTX 01160 // 01161 if (getenv("VMDOPTIXSHADERPATH")) { 01162 strcpy(shaderpath, getenv("VMDOPTIXSHADERPATH")); 01163 if (verbose == RT_VERB_DEBUG) 01164 printf("OptiXRenderer) user-override shaderpath: '%s'\n", shaderpath); 01165 } 01166 01167 if (verbose >= RT_VERB_TIMING) { 01168 printf("OptiXRenderer) creating shader programs...\n"); 01169 fflush(stdout); 01170 } 01171 01172 // load and initialize all of the material programs 01173 init_materials(); 01174 01175 double time_materials = wkf_timer_timenow(ort_timer); 01176 if (verbose >= RT_VERB_TIMING) { 01177 printf("OptiXRenderer) "); 01178 printf("materials(%.1f) ", time_materials - starttime); 01179 fflush(stdout); 01180 } 01181 01182 #if defined(ORT_RAYSTATS) 01183 // program for clearing the raystats buffers 01184 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "clear_raystats_buffers", &clear_raystats_buffers_pgm) ); 01185 #endif 01186 01187 // program for clearing the accumulation buffer 01188 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "clear_accumulation_buffer", &clear_accumulation_buffer_pgm) ); 01189 01190 // program for copying the accumulation buffer to the framebuffer 01191 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "draw_accumulation_buffer", &draw_accumulation_buffer_pgm) ); 01192 01193 // empty placeholder program for copying the accumulation buffer 01194 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "draw_accumulation_buffer_stub", &draw_accumulation_buffer_stub_pgm) ); 01195 01196 double time_fbops = wkf_timer_timenow(ort_timer); 01197 if (verbose >= RT_VERB_TIMING) { 01198 printf("fbops(%.1f) ", time_fbops - time_materials); 01199 fflush(stdout); 01200 } 01201 01202 // register cubemap VR camera ray gen programs 01203 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01204 "vmd_camera_cubemap", &ray_gen_pgm_cubemap) ); 01205 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01206 "vmd_camera_cubemap_dof", &ray_gen_pgm_cubemap_dof) ); 01207 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01208 "vmd_camera_cubemap_stereo", &ray_gen_pgm_cubemap_stereo) ); 01209 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01210 "vmd_camera_cubemap_stereo_dof", &ray_gen_pgm_cubemap_stereo_dof) ); 01211 01212 // register planetarium dome master camera ray gen programs 01213 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01214 "vmd_camera_dome_master", &ray_gen_pgm_dome_master) ); 01215 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01216 "vmd_camera_dome_master_dof", &ray_gen_pgm_dome_master_dof) ); 01217 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01218 "vmd_camera_dome_master_stereo", &ray_gen_pgm_dome_master_stereo) ); 01219 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01220 "vmd_camera_dome_master_stereo_dof", &ray_gen_pgm_dome_master_stereo_dof) ); 01221 01222 // register 360-degree equirectantular projection of spherical camera 01223 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01224 "vmd_camera_equirectangular", &ray_gen_pgm_equirectangular) ); 01225 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01226 "vmd_camera_equirectangular_dof", &ray_gen_pgm_equirectangular_dof) ); 01227 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01228 "vmd_camera_equirectangular_stereo", &ray_gen_pgm_equirectangular_stereo) ); 01229 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01230 "vmd_camera_equirectangular_stereo_dof", &ray_gen_pgm_equirectangular_stereo_dof) ); 01231 01232 // register Oculus Rift projection 01233 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01234 "vmd_camera_oculus_rift", &ray_gen_pgm_oculus_rift) ); 01235 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01236 "vmd_camera_oculus_rift_dof", &ray_gen_pgm_oculus_rift_dof) ); 01237 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01238 "vmd_camera_oculus_rift_stereo", &ray_gen_pgm_oculus_rift_stereo) ); 01239 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01240 "vmd_camera_oculus_rift_stereo_dof", &ray_gen_pgm_oculus_rift_stereo_dof) ); 01241 01242 // register perspective camera ray gen programs 01243 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01244 "vmd_camera_perspective", &ray_gen_pgm_perspective) ); 01245 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01246 "vmd_camera_perspective_dof", &ray_gen_pgm_perspective_dof) ); 01247 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01248 "vmd_camera_perspective_stereo", &ray_gen_pgm_perspective_stereo) ); 01249 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01250 "vmd_camera_perspective_stereo_dof", &ray_gen_pgm_perspective_stereo_dof) ); 01251 01252 // register othographic camera ray gen programs 01253 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01254 "vmd_camera_orthographic", &ray_gen_pgm_orthographic) ); 01255 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01256 "vmd_camera_orthographic_dof", &ray_gen_pgm_orthographic_dof) ); 01257 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01258 "vmd_camera_orthographic_stereo", &ray_gen_pgm_orthographic_stereo) ); 01259 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, 01260 "vmd_camera_orthographic_stereo_dof", &ray_gen_pgm_orthographic_stereo_dof) ); 01261 01262 // miss programs for background (solid, gradient sphere/plane) 01263 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "miss_gradient_bg_sky_sphere", &miss_pgm_sky_sphere) ); 01264 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "miss_gradient_bg_sky_plane", &miss_pgm_sky_ortho_plane) ); 01265 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "miss_solid_bg", &miss_pgm_solid) ); 01266 01267 // exception handler program 01268 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "exception", &exception_pgm) ); 01269 01270 double time_cambgops = wkf_timer_timenow(ort_timer); 01271 if (verbose >= RT_VERB_TIMING) { 01272 printf("cambgops(%.1f) ", time_cambgops - time_fbops); 01273 fflush(stdout); 01274 } 01275 01276 // cylinder array programs 01277 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "cylinder_array_bounds", &cylinder_array_bbox_pgm) ); 01278 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "cylinder_array_intersect", &cylinder_array_isct_pgm) ); 01279 01280 // color-per-cylinder array programs 01281 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "cylinder_array_color_bounds", &cylinder_array_color_bbox_pgm) ); 01282 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "cylinder_array_color_intersect", &cylinder_array_color_isct_pgm) ); 01283 01284 // color-per-ring array programs 01285 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "ring_array_color_bounds", &ring_array_color_bbox_pgm) ); 01286 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "ring_array_color_intersect", &ring_array_color_isct_pgm) ); 01287 01288 // sphere array programs 01289 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "sphere_array_bounds", &sphere_array_bbox_pgm) ); 01290 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "sphere_array_intersect", &sphere_array_isct_pgm) ); 01291 01292 // color-per-sphere array programs 01293 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "sphere_array_color_bounds", &sphere_array_color_bbox_pgm) ); 01294 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "sphere_array_color_intersect", &sphere_array_color_isct_pgm) ); 01295 01296 // tricolor list programs 01297 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "tricolor_bounds", &tricolor_bbox_pgm) ); 01298 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "tricolor_intersect", &tricolor_isct_pgm) ); 01299 01300 // c4u_n3b_v3f 01301 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_c4u_n3b_v3f_bounds", &trimesh_c4u_n3b_v3f_bbox_pgm) ); 01302 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_c4u_n3b_v3f_intersect", &trimesh_c4u_n3b_v3f_isct_pgm) ); 01303 01304 // n3f_v3f 01305 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_n3f_v3f_bounds", &trimesh_n3f_v3f_bbox_pgm) ); 01306 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_n3f_v3f_intersect", &trimesh_n3f_v3f_isct_pgm) ); 01307 01308 // n3b_v3f 01309 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_n3b_v3f_bounds", &trimesh_n3b_v3f_bbox_pgm) ); 01310 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_n3b_v3f_intersect", &trimesh_n3b_v3f_isct_pgm) ); 01311 01312 // v3f 01313 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_v3f_bounds", &trimesh_v3f_bbox_pgm) ); 01314 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_v3f_intersect", &trimesh_v3f_isct_pgm) ); 01315 01316 double time_geompgms = wkf_timer_timenow(ort_timer); 01317 if (verbose >= RT_VERB_TIMING) { 01318 printf("geompgms(%.1f) ", time_geompgms - time_cambgops); 01319 fflush(stdout); 01320 } 01321 01322 if (verbose >= RT_VERB_TIMING) { 01323 printf("\n"); 01324 } 01325 01326 time_ctx_create = wkf_timer_timenow(ort_timer) - starttime; 01327 01328 if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) { 01329 printf("OptiXRenderer) context creation time: %.2f\n", time_ctx_create); 01330 } 01331 01332 context_created = 1; 01333 } 01334 01335 01336 void OptiXRenderer::setup_context(int w, int h) { 01337 double starttime = wkf_timer_timenow(ort_timer); 01338 time_ctx_setup = 0; 01339 01340 lasterror = RT_SUCCESS; // clear any error state 01341 width = w; 01342 height = h; 01343 01344 if (!context_created) 01345 return; 01346 01347 check_verbose_env(); // update verbose flag if changed since last run 01348 01349 // set default global ray tracing recursion depth and/or allow 01350 // runtime user override here. 01351 scene_max_depth = 20; 01352 if (getenv("VMDOPTIXMAXDEPTH")) { 01353 int maxdepth = atoi(getenv("VMDOPTIXMAXDEPTH")); 01354 if (maxdepth > 0 && maxdepth <= 30) { 01355 printf("OptiXRenderer) Setting maxdepth to %d...\n", maxdepth); 01356 scene_max_depth = maxdepth; // set context-wide property 01357 RTERR( rtVariableSet1ui(max_depth_v, scene_max_depth) ); 01358 } else { 01359 printf("OptiXRenderer) ignoring out-of-range maxdepth to %d...\n", maxdepth); 01360 } 01361 } 01362 01363 scene_max_trans = scene_max_depth; 01364 if (getenv("VMDOPTIXMAXTRANS")) { 01365 int maxtrans = atoi(getenv("VMDOPTIXMAXTRANS")); 01366 if (maxtrans > 0 && maxtrans <= 30) { 01367 printf("OptiXRenderer) Setting maxtrans to %d...\n", maxtrans); 01368 scene_max_trans = maxtrans; // set context-wide property 01369 RTERR( rtVariableSet1ui(max_trans_v, scene_max_trans) ); 01370 } else { 01371 printf("OptiXRenderer) ignoring out-of-range maxtrans to %d...\n", maxtrans); 01372 } 01373 } 01374 01375 // set maxdepth and maxtrans with new values 01376 RTERR( rtVariableSet1ui(max_depth_v, scene_max_depth) ); 01377 RTERR( rtVariableSet1ui(max_trans_v, scene_max_trans) ); 01378 01379 // assign indices to ray types 01380 RTERR( rtVariableSet1ui(radiance_ray_type_v, 0u) ); 01381 RTERR( rtVariableSet1ui(shadow_ray_type_v, 1u) ); 01382 01383 // set default scene epsilon 01384 float scene_epsilon = 5.e-5f; 01385 RTERR( rtVariableSet1f(scene_epsilon_v, scene_epsilon) ); 01386 01387 // Current accumulation subframe count, used as part of generating 01388 // AA and AO random number sequences 01389 RTERR( rtVariableSet1ui(accum_count_v, 0) ); 01390 01391 // zero out the array of material usage counts for the scene 01392 memset(material_special_counts, 0, sizeof(material_special_counts)); 01393 time_ctx_setup = wkf_timer_timenow(ort_timer) - starttime; 01394 } 01395 01396 01397 void OptiXRenderer::report_context_stats() { 01398 if (!context_created) 01399 return; 01400 01401 unsigned int ctx_varcount=0; 01402 RTERR( rtContextGetVariableCount(ctx, &ctx_varcount) ); 01403 printf("OptiXRenderer) ctx var cnt: %u\n", ctx_varcount); 01404 } 01405 01406 01407 void OptiXRenderer::destroy_scene() { 01408 double starttime = wkf_timer_timenow(ort_timer); 01409 time_ctx_destroy_scene = 0; 01410 01411 // zero out all object counters 01412 cylinder_array_cnt = 0; 01413 cylinder_array_color_cnt = 0; 01414 ring_array_color_cnt = 0; 01415 sphere_array_cnt = 0; 01416 sphere_array_color_cnt = 0; 01417 tricolor_cnt = 0; 01418 trimesh_c4u_n3b_v3f_cnt = 0; 01419 trimesh_n3b_v3f_cnt = 0; 01420 trimesh_n3f_v3f_cnt = 0; 01421 trimesh_v3f_cnt = 0; 01422 01423 if (!context_created) 01424 return; 01425 01426 if (scene_created) { 01427 int i; 01428 01429 RTERR( rtAccelerationDestroy(acceleration) ); 01430 #if defined(ORT_USERTXAPIS) 01431 // OptiX RTX hardware-accelerated triangles API 01432 RTERR( rtAccelerationDestroy(trianglesacceleration) ); 01433 #endif 01434 01435 RTERR( rtAccelerationDestroy(root_acceleration) ); 01436 RTERR( rtGroupDestroy(root_group) ); 01437 01438 RTERR( rtGeometryGroupDestroy(geometrygroup) ); 01439 #if defined(ORT_USERTXAPIS) 01440 // OptiX RTX hardware-accelerated triangles API 01441 RTERR( rtGeometryGroupDestroy(geometrytrianglesgroup) ); 01442 #endif 01443 01444 int instcount = geominstancelist.num(); 01445 for (i=0; i<instcount; i++) { 01446 RTERR( rtGeometryInstanceDestroy(geominstancelist[i]) ); 01447 } 01448 01449 int geomcount = geomlist.num(); 01450 for (i=0; i<geomcount; i++) { 01451 RTERR( rtGeometryDestroy(geomlist[i]) ); 01452 } 01453 01454 geominstancelist.clear(); 01455 geomlist.clear(); 01456 01457 #if defined(ORT_USERTXAPIS) 01458 // OptiX RTX hardware-accelerated triangles API 01459 #if (OPTIX_VERSION >= 60500) 01460 // XXX Destroying the RTX triangle instances can cause crashes, 01461 // both in the OptiX 5.2 DEV build w/ triangle API 0.3, 01462 // and also the production OptiX 6.0.0 build w/ driver 418.30. 01463 // This may be caused by an interaction between our use of 01464 // RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS in the triangle APIs 01465 // and the instance nodes. 01466 // As of OptiX 6.5.0 and driver version 440.44, this problem 01467 // seems to be corrected, and this workaround is no longer needed. 01468 int insttrianglescount = geomtrianglesinstancelist.num(); 01469 for (i=0; i<insttrianglescount; i++) { 01470 RTERR( rtGeometryInstanceDestroy(geomtrianglesinstancelist[i]) ); 01471 } 01472 #endif 01473 01474 int geomtrianglescount = geomtriangleslist.num(); 01475 for (i=0; i<geomtrianglescount; i++) { 01476 RTERR( rtGeometryTrianglesDestroy(geomtriangleslist[i]) ); 01477 } 01478 01479 geomtrianglesinstancelist.clear(); 01480 geomtriangleslist.clear(); 01481 #endif 01482 01483 int bufcount = bufferlist.num(); 01484 for (i=0; i<bufcount; i++) { 01485 RTERR( rtBufferDestroy(bufferlist[i]) ); 01486 } 01487 01488 bufferlist.clear(); 01489 } 01490 01491 materialcache.clear(); // ensure no materials live across renderings 01492 01493 double endtime = wkf_timer_timenow(ort_timer); 01494 time_ctx_destroy_scene = endtime - starttime; 01495 01496 scene_created = 0; // scene has been destroyed 01497 } 01498 01499 01500 int OptiXRenderer::set_accum_raygen_pgm(CameraProjection &proj, 01501 int stereo_on, int dof_on) { 01502 // 01503 // XXX The ray tracing engine supports a number of camera models that 01504 // are extremely difficult to implement effectively in OpenGL, 01505 // particularly in the context of interactive rasterization. 01506 // The control over use of these camera models is currently implemented 01507 // solely through environment variables, which is undesirable, but 01508 // necessary in the very short term until we come up with a way of 01509 // exposing this in the VMD GUIs. The environment variables currently 01510 // override the incoming projection settings from VMD. 01511 // 01512 01513 01514 // VR cubemap 01515 if (getenv("VMDOPTIXCUBEMAP") != NULL) { 01516 msgInfo << "Overriding VMD camera projection mode with VR cubemap" << sendmsg; 01517 proj = RT_CUBEMAP; 01518 } 01519 01520 // planetarium dome master 01521 if (getenv("VMDOPTIXDOMEMASTER") != NULL) { 01522 msgInfo << "Overriding VMD camera projection mode with planetarium dome master" << sendmsg; 01523 proj = RT_DOME_MASTER; 01524 } 01525 01526 // 360-degree spherical projection into a rectangular (2w x 1h) image 01527 if (getenv("VMDOPTIXEQUIRECTANGULAR") != NULL) { 01528 msgInfo << "Overriding VMD camera projection mode with spherical equirectangular projection" << sendmsg; 01529 proj = RT_EQUIRECTANGULAR; 01530 } 01531 01532 // Oculus Rift w/ barrel distortion applied 01533 if (getenv("VMDOPTIXOCULUSRIFT") != NULL) { 01534 msgInfo << "Overriding VMD camera projection mode with Oculus Rift projection" << sendmsg; 01535 proj = RT_OCULUS_RIFT; 01536 } 01537 01538 // override stereo if an environment variable is set 01539 if (getenv("VMDOPTIXSTEREO") != NULL) { 01540 msgInfo << "Overriding VMD camera, enabling stereo" << sendmsg; 01541 stereo_on = 1; 01542 } 01543 01544 // set the active ray gen program based on the active projection mode 01545 switch (proj) { 01546 default: 01547 msgErr << "OptiXRenderer) Illegal projection mode! Using perspective." << sendmsg; 01548 // XXX fall through to perspective is intentional... 01549 01550 case RT_PERSPECTIVE: 01551 if (stereo_on) { 01552 if (dof_on) { 01553 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_perspective_stereo_dof) ); 01554 } else { 01555 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_perspective_stereo) ); 01556 } 01557 } else { 01558 if (dof_on) { 01559 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_perspective_dof) ); 01560 } else { 01561 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_perspective) ); 01562 } 01563 } 01564 break; 01565 01566 case RT_ORTHOGRAPHIC: 01567 if (stereo_on) { 01568 if (dof_on) { 01569 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_orthographic_stereo_dof) ); 01570 } else { 01571 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_orthographic_stereo) ); 01572 } 01573 } else { 01574 if (dof_on) { 01575 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_orthographic_dof) ); 01576 } else { 01577 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_orthographic) ); 01578 } 01579 } 01580 break; 01581 01582 case RT_CUBEMAP: 01583 if (stereo_on) { 01584 if (dof_on) { 01585 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_cubemap_stereo_dof) ); 01586 } else { 01587 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_cubemap_stereo) ); 01588 } 01589 } else { 01590 if (dof_on) { 01591 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_cubemap_dof) ); 01592 } else { 01593 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_cubemap) ); 01594 } 01595 } 01596 break; 01597 01598 case RT_DOME_MASTER: 01599 if (stereo_on) { 01600 if (dof_on) { 01601 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_dome_master_stereo_dof) ); 01602 } else { 01603 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_dome_master_stereo) ); 01604 } 01605 } else { 01606 if (dof_on) { 01607 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_dome_master_dof) ); 01608 } else { 01609 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_dome_master) ); 01610 } 01611 } 01612 break; 01613 01614 case RT_EQUIRECTANGULAR: 01615 if (stereo_on) { 01616 if (dof_on) { 01617 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_equirectangular_stereo_dof) ); 01618 } else { 01619 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_equirectangular_stereo) ); 01620 } 01621 } else { 01622 if (dof_on) { 01623 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_equirectangular_dof) ); 01624 } else { 01625 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_equirectangular) ); 01626 } 01627 } 01628 break; 01629 01630 case RT_OCULUS_RIFT: 01631 if (stereo_on) { 01632 if (dof_on) { 01633 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_oculus_rift_stereo_dof) ); 01634 } else { 01635 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_oculus_rift_stereo) ); 01636 } 01637 } else { 01638 if (dof_on) { 01639 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_oculus_rift_dof) ); 01640 } else { 01641 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_oculus_rift) ); 01642 } 01643 } 01644 break; 01645 } 01646 01647 return 0; 01648 } 01649 01650 01651 void OptiXRenderer::update_rendering_state(int interactive) { 01652 if (!context_created) 01653 return; 01654 01655 #if defined(ORT_USERTXAPIS) 01656 // Permit VMD usage of the RTX hardware triangle API to 01657 // be disabled at runtime, for debugging/comparison purposes. 01658 // This does not affect RTX execution mode, but rather VMD's 01659 // internal usage of the RTX-specific triangle APIs. 01660 if (getenv("VMDOPTIXNOHWTRIANGLES") != NULL) { 01661 hwtri_enabled = 0; 01662 } 01663 #endif 01664 01665 // update scene epsilon if necessary 01666 if (getenv("VMDOPTIXSCENEEPSILON") != NULL) { 01667 float scene_epsilon = float(atof(getenv("VMDOPTIXSCENEEPSILON"))); 01668 printf("OptiXRenderer) user override of scene epsilon: %g\n", scene_epsilon); 01669 RTERR( rtVariableSet1f(scene_epsilon_v, scene_epsilon) ); 01670 } 01671 01672 int i; 01673 wkf_timer_start(ort_timer); 01674 01675 // set interactive/progressive rendering flag 01676 RTERR( rtVariableSet1i(progressive_enabled_v, interactive) ); 01677 01678 long totaltris = tricolor_cnt + trimesh_c4u_n3b_v3f_cnt + 01679 trimesh_n3b_v3f_cnt + trimesh_n3f_v3f_cnt + trimesh_v3f_cnt; 01680 01681 if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) { 01682 printf("OptiXRenderer) cyl %ld, ring %ld, sph %ld, tri %ld, tot: %ld lt %ld\n", 01683 cylinder_array_cnt + cylinder_array_color_cnt, 01684 ring_array_color_cnt, 01685 sphere_array_cnt + sphere_array_color_cnt, 01686 totaltris, 01687 cylinder_array_cnt + cylinder_array_color_cnt + ring_array_color_cnt + sphere_array_cnt + sphere_array_color_cnt + totaltris, 01688 directional_lights.num() + positional_lights.num()); 01689 } 01690 01691 if (verbose == RT_VERB_DEBUG) { 01692 #if defined(ORT_USE_TEMPLATE_SHADERS) 01693 if (getenv("VMDOPTIXFORCEGENERALSHADER") == NULL) { 01694 printf("OptiXRenderer) using template-specialized shaders and materials:\n"); 01695 int i; 01696 for (i=0; i<ORTMTABSZ; i++) { 01697 if (material_special_counts[i] > 0) { 01698 printf("OptiXRenderer) material_special[%d] usage count: %d\n", 01699 i, material_special_counts[i]); 01700 01701 printf("OptiXRenderer) " 01702 "ClipView %s, " 01703 "Headlight %s, " 01704 "Fog %s, " 01705 "Shadows %s, " 01706 "AO %s, " 01707 "Outline %s, " 01708 "Refl %s, " 01709 "Trans %s\n", 01710 #if defined(VMDOPTIX_VCA_TABSZHACK) 01711 onoffstr(1), 01712 onoffstr(1), 01713 #else 01714 onoffstr(i & 128), 01715 onoffstr(i & 64), 01716 #endif 01717 onoffstr(i & 32), 01718 onoffstr(i & 16), 01719 onoffstr(i & 8), 01720 onoffstr(i & 4), 01721 onoffstr(i & 2), 01722 onoffstr(i & 1)); 01723 } 01724 } 01725 printf("OptiXRenderer)\n"); 01726 } else { 01727 printf("OptiXRenderer) using fully general shader and materials.\n"); 01728 } 01729 #else 01730 printf("OptiXRenderer) using fully general shader and materials.\n"); 01731 #endif 01732 } 01733 01734 RTERR( rtVariableSet3fv(scene_bg_color_v, scene_bg_color) ); 01735 RTERR( rtVariableSet3fv(scene_bg_grad_top_v, scene_bg_grad_top) ); 01736 RTERR( rtVariableSet3fv(scene_bg_grad_bot_v, scene_bg_grad_bot) ); 01737 RTERR( rtVariableSet3fv(scene_gradient_v, scene_gradient) ); 01738 RTERR( rtVariableSet1f(scene_gradient_topval_v, scene_gradient_topval) ); 01739 RTERR( rtVariableSet1f(scene_gradient_botval_v, scene_gradient_botval) ); 01740 01741 if (verbose == RT_VERB_DEBUG) { 01742 printf("OptiXRenderer) HMD/camera view clipping mode: %d start: %.2f end: %.2f\n", 01743 clipview_mode, clipview_start, clipview_end); 01744 01745 printf("OptiXRenderer) HMD/camera headlight mode: %d\n", headlight_mode); 01746 01747 printf("OptiXRenderer) scene bg mode: %d\n", scene_background_mode); 01748 01749 printf("OptiXRenderer) scene bgsolid: %.2f %.2f %.2f\n", 01750 scene_bg_color[0], scene_bg_color[1], scene_bg_color[2]); 01751 01752 printf("OptiXRenderer) scene bggradT: %.2f %.2f %.2f\n", 01753 scene_bg_grad_top[0], scene_bg_grad_top[1], scene_bg_grad_top[2]); 01754 01755 printf("OptiXRenderer) scene bggradB: %.2f %.2f %.2f\n", 01756 scene_bg_grad_bot[0], scene_bg_grad_bot[1], scene_bg_grad_bot[2]); 01757 01758 printf("OptiXRenderer) bg gradient: %f %f %f top: %f bot: %f\n", 01759 scene_gradient[0], scene_gradient[1], scene_gradient[2], 01760 scene_gradient_topval, scene_gradient_botval); 01761 } 01762 01763 // update in case the caller changed top/bottom values since last recalc 01764 scene_gradient_invrange = 1.0f / (scene_gradient_topval - scene_gradient_botval); 01765 RTERR( rtVariableSet1f(scene_gradient_invrange_v, scene_gradient_invrange) ); 01766 01767 RTERR( rtVariableSet1i(clipview_mode_v, clipview_mode) ); 01768 RTERR( rtVariableSet1f(clipview_start_v, clipview_start) ); 01769 RTERR( rtVariableSet1f(clipview_end_v, clipview_end) ); 01770 RTERR( rtVariableSet1i(headlight_mode_v, (int) headlight_mode) ); 01771 01772 RTERR( rtVariableSet1i(fog_mode_v, (int) fog_mode) ); 01773 RTERR( rtVariableSet1f(fog_start_v, fog_start) ); 01774 RTERR( rtVariableSet1f(fog_end_v, fog_end) ); 01775 RTERR( rtVariableSet1f(fog_density_v, fog_density) ); 01776 01777 if (verbose == RT_VERB_DEBUG) { 01778 printf("OptiXRenderer) adding lights: dir: %ld pos: %ld\n", 01779 directional_lights.num(), positional_lights.num()); 01780 } 01781 01782 #if defined(VMDOPTIX_LIGHTUSEROBJS) 01783 DirectionalLightList dir_lights; 01784 memset(&dir_lights, 0, sizeof(DirectionalLightList)); 01785 dir_lights.num_lights = directional_lights.num(); 01786 int dlcount = directional_lights.num(); 01787 dlcount = (dlcount > DISP_LIGHTS) ? DISP_LIGHTS : dlcount; 01788 for (i=0; i<dlcount; i++) { 01789 vec_copy((float*)(&dir_lights.dirs[i]), directional_lights[i].dir); 01790 vec_normalize((float*)&dir_lights.dirs[i]); 01791 } 01792 RTERR( rtVariableSetUserData(dir_light_list_v, sizeof(DirectionalLightList), &dir_lights) ); 01793 01794 PositionalLightList pos_lights; 01795 memset(&pos_lights, 0, sizeof(PositionalLightList)); 01796 pos_lights.num_lights = positional_lights.num(); 01797 int plcount = positional_lights.num(); 01798 plcount = (plcount > DISP_LIGHTS) ? DISP_LIGHTS : plcount; 01799 for (i=0; i<plcount; i++) { 01800 vec_copy((float*)(&pos_lights.posns[i]), positional_lights[i].pos); 01801 } 01802 RTERR( rtVariableSetUserData(pos_light_list_v, sizeof(PositionalLightList), &pos_lights) ); 01803 #else 01804 DirectionalLight *dlbuf; 01805 RTERR( rtBufferSetSize1D(dir_lightbuffer, directional_lights.num()) ); 01806 RTERR( rtBufferMap(dir_lightbuffer, (void **) &dlbuf) ); 01807 for (i=0; i<directional_lights.num(); i++) { 01808 vec_copy((float*)&dlbuf[i].dir, directional_lights[i].dir); 01809 vec_normalize((float*)&dlbuf[i].dir); 01810 } 01811 RTERR( rtBufferUnmap(dir_lightbuffer) ); 01812 RTERR( rtVariableSetObject(dir_lightbuffer_v, dir_lightbuffer) ); 01813 01814 PositionalLight *plbuf; 01815 RTERR( rtBufferSetSize1D(pos_lightbuffer, positional_lights.num()) ); 01816 RTERR( rtBufferMap(pos_lightbuffer, (void **) &plbuf) ); 01817 for (i=0; i<positional_lights.num(); i++) { 01818 vec_copy((float*)&plbuf[i].pos, positional_lights[i].pos); 01819 } 01820 RTERR( rtBufferUnmap(pos_lightbuffer) ); 01821 RTERR( rtVariableSetObject(pos_lightbuffer_v, pos_lightbuffer) ); 01822 #endif 01823 01824 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) Finalizing OptiX scene graph...\n"); 01825 01826 // create group to hold instances 01827 int instcount = geominstancelist.num(); 01828 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) instance objects: %d\n", instcount); 01829 01830 RTERR( rtGeometryGroupCreate(ctx, &geometrygroup) ); 01831 RTERR( rtGeometryGroupSetChildCount(geometrygroup, instcount) ); 01832 for (i=0; i<instcount; i++) { 01833 RTERR( rtGeometryGroupSetChild(geometrygroup, i, geominstancelist[i]) ); 01834 } 01835 01836 #if defined(ORT_USERTXAPIS) 01837 // OptiX RTX hardware-accelerated triangles API 01838 // create separate group for triangle instances 01839 int insttrianglescount = geomtrianglesinstancelist.num(); 01840 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) triangle instance objects: %d\n", insttrianglescount); 01841 01842 RTERR( rtGeometryGroupCreate(ctx, &geometrytrianglesgroup) ); 01843 RTERR( rtGeometryGroupSetChildCount(geometrytrianglesgroup, insttrianglescount) ); 01844 for (i=0; i<insttrianglescount; i++) { 01845 RTERR( rtGeometryGroupSetChild(geometrytrianglesgroup, i, geomtrianglesinstancelist[i]) ); 01846 } 01847 #endif 01848 01849 01850 // XXX we should create an acceleration object the instance shared 01851 // by multiple PBC images 01852 01853 // acceleration object for the geometrygroup 01854 RTERR( rtAccelerationCreate(ctx, &acceleration) ); 01855 01856 // Allow runtime override of acceleration builder and traverser 01857 // for performance testing/tuning 01858 const char *ort_builder = getenv("VMDOPTIXBUILDER"); 01859 const char *ort_traverser = getenv("VMDOPTIXTRAVERSER"); 01860 if (ort_builder && ort_traverser) { 01861 RTERR( rtAccelerationSetBuilder(acceleration, ort_builder) ); 01862 RTERR( rtAccelerationSetTraverser(acceleration, ort_traverser) ); 01863 if (verbose == RT_VERB_DEBUG) { 01864 printf("OptiXRenderer) user-override of AS: builder: '%s' traverser '%s'\n", 01865 ort_builder, ort_traverser); 01866 } 01867 } else if (ort_builder) { 01868 RTERR( rtAccelerationSetBuilder(acceleration, ort_builder) ); 01869 RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") ); 01870 if (verbose == RT_VERB_DEBUG) { 01871 printf("OptiXRenderer) user-override of AS builder: '%s' (def traverser '%s')\n", 01872 ort_builder, "Bvh"); 01873 } 01874 } else { 01875 #if (OPTIX_VERSION >= 3050) && (OPTIX_VERSION < 3060) || (OPTIX_VERSION == 3063) || (OPTIX_VERSION == 3080) 01876 // OptiX 3.5.0 was the first to include the new fast "Trbvh" AS builder 01877 // OptiX 3.6.3 fixed Trbvh bugs on huge models 01878 // OptiX 3.8.0 has cured all known Trbvh bugs for VMD so far 01879 RTERR( rtAccelerationSetBuilder(acceleration, "Trbvh") ); 01880 RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") ); 01881 #else 01882 // For older revs of OptiX (or those with bugs in Trbvh), 01883 // the "MedianBvh" AS builder gives the best compromise between 01884 // builder speed and ray tracing speed. 01885 // OptiX 3.6.[012] and 3.7.0 had Trbvh bugs on huge models that 01886 // could cause VMD to crash in some cases 01887 // RTERR( rtAccelerationSetBuilder(acceleration, "Sbvh") ); 01888 // RTERR( rtAccelerationSetBuilder(acceleration, "Bvh") ); 01889 RTERR( rtAccelerationSetBuilder(acceleration, "MedianBvh") ); 01890 RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") ); 01891 #endif 01892 } 01893 01894 01895 // allow user-override of the builder type (e.g. "GPU", or "CPU") when 01896 // the AS builder provides more than one choice. 01897 if (getenv("VMDOPTIXBUILDTYPE") != NULL) { 01898 const char *buildtypestr = getenv("VMDOPTIXBUILDTYPE"); 01899 const char *curbuilderstr = NULL; 01900 RTERR( rtAccelerationGetBuilder(acceleration, &curbuilderstr) ); 01901 if (!strcmp(curbuilderstr, "Trbvh")) { 01902 msgInfo << "OptiXRenderer) user-override of Trbvh AS build type: " 01903 << buildtypestr << sendmsg; 01904 RTERR( rtAccelerationSetProperty(acceleration, "build_type", buildtypestr) ); 01905 } else { 01906 msgErr << "OptiXRenderer) Can't set build type for AS builders other than Trbvh" << sendmsg; 01907 } 01908 } 01909 01910 01911 RTERR( rtGeometryGroupSetAcceleration(geometrygroup, acceleration) ); 01912 RTERR( rtAccelerationMarkDirty(acceleration) ); 01913 01914 #if defined(ORT_USERTXAPIS) 01915 // OptiX RTX hardware-accelerated triangles API 01916 // Acceleration structure for triangle geometry 01917 RTERR( rtAccelerationCreate(ctx, &trianglesacceleration) ); 01918 RTERR( rtAccelerationSetBuilder(trianglesacceleration, "Trbvh") ); 01919 RTERR( rtAccelerationSetTraverser(trianglesacceleration, "Bvh") ); 01920 RTERR( rtGeometryGroupSetAcceleration(geometrytrianglesgroup, trianglesacceleration) ); 01921 RTERR( rtAccelerationMarkDirty(trianglesacceleration) ); 01922 #endif 01923 01924 01925 // create the root node of the scene graph 01926 RTERR( rtGroupCreate(ctx, &root_group) ); 01927 #if defined(ORT_USERTXAPIS) 01928 RTERR( rtGroupSetChildCount(root_group, 2) ); 01929 RTERR( rtGroupSetChild(root_group, 0, geometrygroup) ); 01930 RTERR( rtGroupSetChild(root_group, 1, geometrytrianglesgroup) ); 01931 #else 01932 RTERR( rtGroupSetChildCount(root_group, 1) ); 01933 RTERR( rtGroupSetChild(root_group, 0, geometrygroup) ); 01934 #endif 01935 RTERR( rtVariableSetObject(root_object_v, root_group) ); 01936 RTERR( rtVariableSetObject(root_shadower_v, root_group) ); 01937 01938 // create an acceleration object for the entire scene graph 01939 RTERR( rtAccelerationCreate(ctx, &root_acceleration) ); 01940 RTERR( rtAccelerationSetBuilder(root_acceleration,"NoAccel") ); 01941 RTERR( rtAccelerationSetTraverser(root_acceleration,"NoAccel") ); 01942 RTERR( rtGroupSetAcceleration(root_group, root_acceleration) ); 01943 RTERR( rtAccelerationMarkDirty(root_acceleration) ); 01944 scene_created=1; 01945 01946 01947 // do final state variable updates before rendering begins 01948 if (verbose == RT_VERB_DEBUG) { 01949 printf("OptiXRenderer) cam zoom factor %f\n", cam_zoom); 01950 printf("OptiXRenderer) cam stereo eye separation %f\n", cam_stereo_eyesep); 01951 printf("OptiXRenderer) cam stereo convergence distance %f\n", 01952 cam_stereo_convergence_dist); 01953 printf("OptiXRenderer) cam DoF focal distance %f\n", cam_dof_focal_dist); 01954 printf("OptiXRenderer) cam DoF f/stop %f\n", cam_dof_fnumber); 01955 } 01956 01957 // define all of the standard camera params 01958 RTERR( rtVariableSet1f(cam_zoom_v, cam_zoom) ); 01959 RTERR( rtVariableSet3f( cam_pos_v, 0.0f, 0.0f, 2.0f) ); 01960 RTERR( rtVariableSet3f( cam_U_v, 1.0f, 0.0f, 0.0f) ); 01961 RTERR( rtVariableSet3f( cam_V_v, 0.0f, 1.0f, 0.0f) ); 01962 RTERR( rtVariableSet3f( cam_W_v, 0.0f, 0.0f, -1.0f) ); 01963 01964 // define stereoscopic camera parameters 01965 RTERR( rtVariableSet1f(cam_stereo_eyesep_v, cam_stereo_eyesep) ); 01966 RTERR( rtVariableSet1f(cam_stereo_convergence_dist_v, cam_stereo_convergence_dist) ); 01967 01968 // define camera DoF parameters 01969 RTERR( rtVariableSet1f(cam_dof_focal_dist_v, cam_dof_focal_dist) ); 01970 RTERR( rtVariableSet1f(cam_dof_aperture_rad_v, cam_dof_focal_dist / (2.0f * cam_zoom * cam_dof_fnumber)) ); 01971 01972 // for batch mode rendering, we prefer correctness to speed, so 01973 // we currently ignore USE_REVERSE_SHADOW_RAYS_DEFAULT except when 01974 // running interactively. When the reverse ray optimizatoin is 100% 01975 // bulletproof, we will use it for batch rendering also. 01976 RTERR( rtVariableSet1i(shadows_enabled_v, 01977 (shadows_enabled) ? RT_SHADOWS_ON : RT_SHADOWS_OFF) ); 01978 01979 RTERR( rtVariableSet1i(ao_samples_v, ao_samples) ); 01980 RTERR( rtVariableSet1f(ao_ambient_v, ao_ambient) ); 01981 RTERR( rtVariableSet1f(ao_direct_v, ao_direct) ); 01982 RTERR( rtVariableSet1f(ao_maxdist_v, ao_maxdist) ); 01983 if (getenv("VMDOPTIXAOMAXDIST")) { 01984 float tmp = float(atof(getenv("VMDOPTIXAOMAXDIST"))); 01985 if (verbose == RT_VERB_DEBUG) { 01986 printf("OptiXRenderer) setting AO maxdist: %f\n", tmp); 01987 } 01988 RTERR( rtVariableSet1f(ao_maxdist_v, tmp) ); 01989 } 01990 01991 if (verbose == RT_VERB_DEBUG) { 01992 printf("OptiXRenderer) setting sample counts: AA %d AO %d\n", aa_samples, ao_samples); 01993 printf("OptiXRenderer) setting AO factors: AOA %f AOD %f\n", ao_ambient, ao_direct); 01994 } 01995 01996 // 01997 // Handle AA samples either internally with loops internal to 01998 // each ray launch point thread, or externally by iterating over 01999 // multiple launches, adding each sample to an accumulation buffer, 02000 // or a hybrid combination of the two. The final framebuffer output 02001 // is written by launching a special accumulation buffer drawing 02002 // program that range clamps and converts the pixel data while copying 02003 // the GPU-local accumulation buffer to the final output buffer... 02004 // 02005 ext_aa_loops = 1; 02006 int totrays = (aa_samples + 1) * ((ao_samples > 0) ? ao_samples : 1); 02007 int maxrayspass = 16; 02008 if (getenv("VMDOPTIXMAXRAYSPERPASS") != NULL) { 02009 maxrayspass = atoi(getenv("VMDOPTIXMAXRAYSPERPASS")); 02010 printf("OptiXRenderer) User-override of max rays per pass: %d\n", maxrayspass); 02011 } 02012 if ((getenv("VMDOPTIXFORCEMULTIPASS") != NULL) || (totrays > maxrayspass)) { 02013 // if we have too much work for a single-pass rendering, we need to 02014 // break it up into multiple passes or we risk having kernel timeouts 02015 ext_aa_loops = 1 + aa_samples; 02016 RTERR( rtVariableSet1i(aa_samples_v, 1) ); 02017 } else { 02018 // if the scene is simple, e.g. no AO rays and AA sample count is small, 02019 // we can run it in a single pass and get better performance 02020 RTERR( rtVariableSet1i(aa_samples_v, aa_samples + 1) ); 02021 } 02022 RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(1 + aa_samples)) ); 02023 02024 if (verbose == RT_VERB_DEBUG) { 02025 if (ext_aa_loops > 1) 02026 printf("OptiXRenderer) Running OptiX multi-pass: %d loops\n", ext_aa_loops); 02027 else 02028 printf("OptiXRenderer) Running OptiX single-pass: %d total samples\n", 1+aa_samples); 02029 } 02030 02031 // set the ray generation program to the active camera code... 02032 RTERR( rtContextSetEntryPointCount(ctx, RT_RAY_GEN_COUNT) ); 02033 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, clear_accumulation_buffer_pgm) ); 02034 #if defined(ORT_RAYSTATS) 02035 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_CLEAR_RAYSTATS, clear_raystats_buffers_pgm) ); 02036 #endif 02037 02038 // set the active color accumulation ray gen program based on the 02039 // camera/projection mode, stereoscopic display mode, 02040 // and depth-of-field state 02041 set_accum_raygen_pgm(camera_projection, 0, dof_enabled); 02042 02043 // 02044 // set the ray gen program to use for the copy/finish operations 02045 // 02046 #if defined(VMDOPTIX_PROGRESSIVEAPI) 02047 if (interactive) { 02048 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_COPY_FINISH, draw_accumulation_buffer_stub_pgm) ); 02049 } else 02050 #endif 02051 { 02052 RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_COPY_FINISH, draw_accumulation_buffer_pgm) ); 02053 } 02054 02055 // Link up miss program depending on background rendering mode 02056 switch (scene_background_mode) { 02057 case RT_BACKGROUND_TEXTURE_SKY_SPHERE: 02058 RTERR( rtContextSetMissProgram(ctx, RT_RAY_TYPE_RADIANCE, miss_pgm_sky_sphere) ); 02059 break; 02060 02061 case RT_BACKGROUND_TEXTURE_SKY_ORTHO_PLANE: 02062 RTERR( rtContextSetMissProgram(ctx, RT_RAY_TYPE_RADIANCE, miss_pgm_sky_ortho_plane) ); 02063 break; 02064 02065 case RT_BACKGROUND_TEXTURE_SOLID: 02066 default: 02067 RTERR( rtContextSetMissProgram(ctx, RT_RAY_TYPE_RADIANCE, miss_pgm_solid) ); 02068 break; 02069 } 02070 02071 // enable exception handling for all defined entry points 02072 unsigned int epcnt=0; 02073 RTERR( rtContextGetEntryPointCount(ctx, &epcnt) ); 02074 unsigned int epidx; 02075 for (epidx=0; epidx<epcnt; epidx++) { 02076 RTERR( rtContextSetExceptionProgram(ctx, epidx, exception_pgm) ); 02077 } 02078 02079 // enable all exceptions for debugging if requested 02080 if (getenv("VMDOPTIXDEBUG")) { 02081 printf("OptiXRenderer) Enabling all OptiX exceptions\n"); 02082 RTERR( rtContextSetExceptionEnabled(ctx, RT_EXCEPTION_ALL, 1) ); 02083 } 02084 02085 02086 // Check/update OptiX context-wide stack size calculations 02087 // based on required recursion depth, shader complexity, etc. 02088 int stacksizeadjusted=0; 02089 02090 #if (OPTIX_VERSION >= 60000) 02091 // When running in RTX mode, OptiX >= 6.x provides an API to set 02092 // the maximum trace depth which is used to automatically compute the 02093 // required stack size. 02094 if (rtx_enabled) { 02095 // We need to tell OptiX to allow a recursion depth that includes 02096 // not only the surface hit, but also shadow feelers and any other 02097 // secondary rays that aren't being tracked explicitly by the 02098 // internal recursion depth counter implemented in the top level 02099 // ray gen and shading code. 02100 int newmaxdepth = scene_max_depth + 1; 02101 02102 // A last-ditch workaround for issues observed in the field where 02103 // the requested max trace depth somehow didn't provide sufficient 02104 // stack space in practice. This can be used for force OptiX to 02105 // use the maximum stack size allowed by the RTX runtime. 02106 if (getenv("VMDOPTIXMAXSTACKSIZE")) { 02107 printf("OptiXRenderer) Setting RTX runtime to max depth / stack size\n"); 02108 02109 // The maximum recursion depth supported by OptiX 6.0 is 31. 02110 newmaxdepth = 31; 02111 } 02112 02113 // Enforce maximum supported trace depth limit. 02114 // The maximum recursion depth supported by OptiX 6.0 is 31. 02115 if (newmaxdepth > 31) 02116 newmaxdepth = 31; 02117 02118 RTERR( rtContextSetMaxTraceDepth(ctx, newmaxdepth) ); 02119 RTERR( rtContextSetMaxCallableProgramDepth(ctx, newmaxdepth) ); 02120 02121 stacksizeadjusted = 1; 02122 } 02123 #endif 02124 02125 // When not running in RTX mode, we revert to the old OptiX [1-5.x] 02126 // stack size APIs to set the stack size required for VMD scenes 02127 // with a typical recursion depth. 02128 // XXX The rtContext[GS]etStackSize() APIs are not supported when 02129 // using the RTX execution strategy. Although they don't (yet) 02130 // return errors in that case, we protect against calling them here 02131 // except when running in a non-RTX mode. Presumably these APIs will 02132 // be deprecated in future OptiX releases. 02133 if (!stacksizeadjusted) { 02134 // increase default OptiX stack size to prevent runtime failures 02135 RTsize ssz; 02136 rtContextGetStackSize(ctx, &ssz); 02137 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) original stack size: %ld\n", ssz); 02138 02139 // a decent default stack size is 7KB 02140 long newstacksize = 7 * 1024; 02141 02142 // allow runtime user override of the OptiX stack size in 02143 // case we need to render a truly massive scene 02144 if (getenv("VMDOPTIXSTACKSIZE")) { 02145 newstacksize = atoi(getenv("VMDOPTIXSTACKSIZE")); 02146 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) user stack size override: %ld\n", newstacksize); 02147 } 02148 rtContextSetStackSize(ctx, newstacksize); 02149 rtContextGetStackSize(ctx, &ssz); 02150 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) new stack size: %ld\n", ssz); 02151 } 02152 02153 #if !defined(VMDOPTIX_PROGRESSIVEAPI) 02154 // Set print buffer size when using the old non-progressive APIs 02155 rtContextSetPrintEnabled(ctx, 1); 02156 rtContextSetPrintBufferSize(ctx, 1*1024*1024); 02157 #endif 02158 02159 #if defined(VMD_ENABLE_OPTIX_TIMEOUTS) 02160 // Add a custom OptiX timeout callback to see if we can overcome 02161 // some of the timeout issues we've had previously 02162 double timeoutlimit = 0.5; 02163 const char *tmstr = getenv("VMDOPTIXTIMEOUTLIMIT"); 02164 if (tmstr) { 02165 timeoutlimit = float(atof(tmstr)); 02166 printf("Setting OptiX timeout: %f sec\n", timeoutlimit); 02167 } 02168 02169 if (verbose == RT_VERB_DEBUG) 02170 printf("Setting OptiX timeout: %f sec\n", timeoutlimit); 02171 02172 RTERR( rtContextSetTimeoutCallback(ctx, vmd_timeout_cb, timeoutlimit) ); 02173 #endif 02174 } 02175 02176 02177 void OptiXRenderer::framebuffer_config(int fbwidth, int fbheight, 02178 int interactive) { 02179 if (!context_created) 02180 return; 02181 02182 width = fbwidth; 02183 height = fbheight; 02184 02185 #ifdef VMDOPTIX_PROGRESSIVEAPI 02186 // If VMD is using the progressive APIs, we have to check that 02187 // the requested framebuffer config matches the existing one in 02188 // terms of bindings for streaming output, otherwise we have to 02189 // destroy and re-create the framebuffer and any needed streaming 02190 // bindings. 02191 if (buffers_progressive != (interactive != 0)) { 02192 if (verbose == RT_VERB_DEBUG) { 02193 printf("OptiXRenderer) switching between progressive/non-progressive mode\n"); 02194 printf("OptiXRenderer) remaking framebuffer\n"); 02195 } 02196 framebuffer_destroy(); 02197 } 02198 #endif 02199 02200 // allocate and resize buffers to match request 02201 if (buffers_allocated) { 02202 // if the buffers already exist and match the current 02203 // progressive/non-progressive rendering mode, just resize them 02204 if (verbose == RT_VERB_DEBUG) { 02205 printf("OptiXRenderer) resizing framebuffer\n"); 02206 } 02207 framebuffer_resize(width, height); 02208 } else { 02209 // (re)allocate framebuffer and associated accumulation buffers if they 02210 // don't already exist or if they weren't bound properly for 02211 // current progressive/non-progressive rendering needs. 02212 if (verbose == RT_VERB_DEBUG) { 02213 printf("OptiXRenderer) creating framebuffer and accum. buffer\n"); 02214 } 02215 02216 // create intermediate GPU-local accumulation buffer 02217 RTERR( rtContextDeclareVariable(ctx, "accumulation_buffer", &accumulation_buffer_v) ); 02218 02219 #ifdef VMDOPTIX_PROGRESSIVEAPI 02220 if (interactive) { 02221 RTERR( rtBufferCreate(ctx, RT_BUFFER_OUTPUT, &accumulation_buffer) ); 02222 buffers_progressive = 1; 02223 } else 02224 #endif 02225 { 02226 RTERR( rtBufferCreate(ctx, RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, &accumulation_buffer) ); 02227 buffers_progressive = 0; 02228 } 02229 02230 RTERR( rtBufferSetFormat(accumulation_buffer, RT_FORMAT_FLOAT4) ); 02231 RTERR( rtBufferSetSize2D(accumulation_buffer, width, height) ); 02232 RTERR( rtVariableSetObject(accumulation_buffer_v, accumulation_buffer) ); 02233 02234 #if defined(ORT_RAYSTATS) 02235 // (re)create intermediate GPU-local ray stats buffers 02236 // the ray stat buffers get cleared when clearing the accumulation buffer 02237 RTERR( rtContextDeclareVariable(ctx, "raystats1_buffer", &raystats1_buffer_v) ); 02238 RTERR( rtBufferCreate(ctx, RT_BUFFER_OUTPUT, &raystats1_buffer) ); 02239 RTERR( rtBufferSetFormat(raystats1_buffer, RT_FORMAT_UNSIGNED_INT4) ); 02240 RTERR( rtBufferSetSize2D(raystats1_buffer, width, height) ); 02241 RTERR( rtVariableSetObject(raystats1_buffer_v, raystats1_buffer) ); 02242 02243 RTERR( rtContextDeclareVariable(ctx, "raystats2_buffer", &raystats2_buffer_v) ); 02244 RTERR( rtBufferCreate(ctx, RT_BUFFER_OUTPUT, &raystats2_buffer) ); 02245 RTERR( rtBufferSetFormat(raystats2_buffer, RT_FORMAT_UNSIGNED_INT4) ); 02246 RTERR( rtBufferSetSize2D(raystats2_buffer, width, height) ); 02247 RTERR( rtVariableSetObject(raystats2_buffer_v, raystats2_buffer) ); 02248 #endif 02249 02250 // create output framebuffer 02251 #ifdef VMDOPTIX_PROGRESSIVEAPI 02252 if (interactive) { 02253 RTERR( rtBufferCreate(ctx, RT_BUFFER_PROGRESSIVE_STREAM, &framebuffer) ); 02254 02255 // allow user-override of default 5 Mbit/s video encoding bit rate 02256 int stream_bitrate = 5000000; 02257 if (getenv("VMDOPTIXBITRATE")) 02258 stream_bitrate = atoi(getenv("VMDOPTIXBITRATE")); 02259 RTERR( rtBufferSetAttribute(framebuffer, RT_BUFFER_ATTRIBUTE_STREAM_BITRATE, sizeof(int), &stream_bitrate) ); 02260 02261 // allow user-override of default 30 FPS target frame rate 02262 int stream_fps = 30; 02263 if (getenv("VMDOPTIXFPS")) 02264 stream_fps = atoi(getenv("VMDOPTIXFPS")); 02265 RTERR( rtBufferSetAttribute(framebuffer, RT_BUFFER_ATTRIBUTE_STREAM_FPS, sizeof(int), &stream_fps) ); 02266 02267 // allow user-override of Gamma 02268 float stream_gamma = 1.0f; 02269 if (getenv("VMDOPTIXGAMMS")) 02270 stream_gamma = atoi(getenv("VMDOPTIXGAMMA")); 02271 RTERR( rtBufferSetAttribute(framebuffer, RT_BUFFER_ATTRIBUTE_STREAM_GAMMA, sizeof(float), &stream_gamma) ); 02272 } else 02273 #endif 02274 { 02275 RTERR( rtBufferCreate(ctx, RT_BUFFER_OUTPUT, &framebuffer) ); 02276 } 02277 02278 RTERR( rtBufferSetFormat(framebuffer, RT_FORMAT_UNSIGNED_BYTE4) ); 02279 RTERR( rtBufferSetSize2D(framebuffer, width, height) ); 02280 02281 #ifdef VMDOPTIX_PROGRESSIVEAPI 02282 if (interactive) { 02283 RTERR( rtBufferBindProgressiveStream( framebuffer, accumulation_buffer) ); 02284 } else 02285 #endif 02286 { 02287 RTERR( rtContextDeclareVariable(ctx, "framebuffer", &framebuffer_v) ); 02288 RTERR( rtVariableSetObject(framebuffer_v, framebuffer) ); 02289 } 02290 02291 buffers_allocated = 1; 02292 } 02293 } 02294 02295 02296 void OptiXRenderer::framebuffer_resize(int fbwidth, int fbheight) { 02297 if (!context_created) 02298 return; 02299 02300 width = fbwidth; 02301 height = fbheight; 02302 02303 if (buffers_allocated) { 02304 if (verbose == RT_VERB_DEBUG) 02305 printf("OptiXRenderer) framebuffer_resize(%d x %d)\n", width, height); 02306 02307 RTERR( rtBufferSetSize2D(framebuffer, width, height) ); 02308 RTERR( rtBufferSetSize2D(accumulation_buffer, width, height) ); 02309 #if defined(ORT_RAYSTATS) 02310 RTERR( rtBufferSetSize2D(raystats1_buffer, width, height) ); 02311 RTERR( rtBufferSetSize2D(raystats2_buffer, width, height) ); 02312 #endif 02313 } 02314 } 02315 02316 02317 void OptiXRenderer::framebuffer_map_rgb4u(unsigned char **imgrgb4u) { 02318 rtBufferMap(framebuffer, (void **) imgrgb4u); 02319 } 02320 02321 02322 void OptiXRenderer::framebuffer_unmap() { 02323 rtBufferUnmap(framebuffer); 02324 } 02325 02326 02327 void OptiXRenderer::framebuffer_destroy() { 02328 if (!context_created) 02329 return; 02330 02331 if (buffers_allocated) { 02332 #if defined(ORT_RAYSTATS) 02333 RTERR( rtContextRemoveVariable(ctx, raystats1_buffer_v) ); 02334 RTERR( rtBufferDestroy(raystats1_buffer) ); 02335 RTERR( rtContextRemoveVariable(ctx, raystats2_buffer_v) ); 02336 RTERR( rtBufferDestroy(raystats2_buffer) ); 02337 #endif 02338 RTERR( rtContextRemoveVariable(ctx, accumulation_buffer_v) ); 02339 RTERR( rtBufferDestroy(accumulation_buffer) ); 02340 #ifndef VMDOPTIX_PROGRESSIVEAPI 02341 RTERR( rtContextRemoveVariable(ctx, framebuffer_v) ); 02342 #endif 02343 RTERR( rtBufferDestroy(framebuffer) ); 02344 } 02345 buffers_allocated = 0; 02346 buffers_progressive = 0; 02347 } 02348 02349 02350 void OptiXRenderer::render_compile_and_validate(void) { 02351 if (!context_created) 02352 return; 02353 02354 // 02355 // finalize context validation, compilation, and AS generation 02356 // 02357 double startctxtime = wkf_timer_timenow(ort_timer); 02358 02359 02360 // 02361 // XXX need to add heuristics to prevent out-of-memory AS build failures on 02362 // versions of OptiX that don't allow multiple AS build attempts 02363 // 02364 // The memory usage of Trbvh is roughly (from Keith's email): 02365 // 68Byte * num_tris * 1.3 + 0.1*total GPU memory + user prim buffers. 02366 // 02367 // VMD should use this as an estimate of peak Trbvh memory demand and 02368 // force a switch from the GPU builder to a CPU builder, or if it's 02369 // still too much. Trbvh built on CPU still uses 2x the memory that 02370 // the geometry does, so there will still be cases where the only 02371 // viable route is to switch away from Trbvh entirely, e.g. use MedianBvh. 02372 #define ORT_AS_BUILD_MEM_HEURISTIC 1 02373 #if defined(ORT_AS_BUILD_MEM_HEURISTIC) 02374 if (getenv("VMDOPTIXNOMEMHEURISTIC") == NULL) { 02375 const char *curbuilderstr = NULL; 02376 RTERR( rtAccelerationGetBuilder(acceleration, &curbuilderstr) ); 02377 if (!strcmp(curbuilderstr, "Trbvh")) { 02378 long totaltris = tricolor_cnt + trimesh_c4u_n3b_v3f_cnt + 02379 trimesh_n3b_v3f_cnt + trimesh_n3f_v3f_cnt + 02380 trimesh_v3f_cnt; 02381 02382 long totalobjs = cylinder_array_cnt + cylinder_array_color_cnt + 02383 ring_array_color_cnt + 02384 sphere_array_cnt + sphere_array_color_cnt + 02385 totaltris; 02386 02387 long totaluserbufsz = 02388 cylinder_array_cnt * sizeof(vmd_cylinder) + 02389 cylinder_array_color_cnt * sizeof(vmd_cylinder_color) + 02390 ring_array_color_cnt * sizeof(vmd_ring_color) + 02391 sphere_array_cnt * sizeof(vmd_sphere) + 02392 sphere_array_color_cnt * sizeof(vmd_sphere_color) + 02393 tricolor_cnt * sizeof(vmd_tricolor) + 02394 trimesh_c4u_n3b_v3f_cnt * sizeof(vmd_trimesh_c4u_n3b_v3f) + 02395 trimesh_n3b_v3f_cnt * sizeof(vmd_trimesh_n3b_v3f) + 02396 trimesh_n3f_v3f_cnt * sizeof(vmd_trimesh_n3f_v3f) + 02397 trimesh_v3f_cnt * sizeof(vmd_trimesh_v3f); 02398 02399 // Query the current state of all GPUs in the OptiX context 02400 // to determine the smallest amount of free memory, and 02401 // the smallest amount of physical memory among all GPUs. 02402 unsigned long mingpufreemem, mingpuphysmem; 02403 if (query_meminfo_ctx_devices(ctx, mingpufreemem, mingpuphysmem)) { 02404 // If the GPU hardware query fails for some reason, we blindly 02405 // assume we've got a mostly vacant K20-like GPU with 4GB free 02406 mingpufreemem = 4L * 1024L * 1024L * 1024L; 02407 mingpuphysmem = 6L * 1024L * 1024L * 1024L; 02408 } 02409 unsigned long tenpctgpumem = mingpuphysmem / 10; 02410 02411 // 1.3 * 68 bytes == ~88 bytes 02412 unsigned long trbvhmemsz = totalobjs * 90L + tenpctgpumem; 02413 unsigned long totaltrbvhmemsz = trbvhmemsz + totaluserbufsz; 02414 unsigned long totaltrbvhmemszmb = totaltrbvhmemsz / (1024L * 1024L); 02415 02416 if (totaltrbvhmemsz > mingpufreemem) { 02417 // issue warning, and try to build the AS using a different builder 02418 msgWarn << "OptiXRenderer) Predicted Trbvh AS peak GPU memory requirement exceeds capacity" << sendmsg; 02419 msgWarn << "OptiXRenderer) Min free GPU mem: " << (mingpufreemem / (1024L * 1024L)) << "MB" << sendmsg; 02420 msgWarn << "OptiXRenderer) Predicted Trbvh AS peak mem during build: " << totaltrbvhmemszmb << "MB" << sendmsg; 02421 02422 #if 1 02423 // XXX the Trbvh CPU builder can segfault in some cases, e.g. on 02424 // a 171M triangle mesh on a machine w/ 256GB physical mem. 02425 // for now, we will only use MedianBvh as the fallback path until 02426 // this issue is resolved with greater certainty. 02427 msgWarn << "OptiXRenderer) Switching to MedianBvh AS builder..." << sendmsg; 02428 RTERR( rtAccelerationSetBuilder(acceleration, "MedianBvh") ); 02429 RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") ); 02430 #else 02431 02432 if (trbvhmemsz + totaluserbufsz > maxgpufreemem) { 02433 msgWarn << "OptiXRenderer) Switching to MedianBvh AS builder..." << sendmsg; 02434 RTERR( rtAccelerationSetBuilder(acceleration, "MedianBvh") ); 02435 RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") ); 02436 } else { 02437 msgWarn << "OptiXRenderer) Switching to Trbvh CPU-based AS builder..." << sendmsg; 02438 RTERR( rtAccelerationSetBuilder(acceleration, "Trbvh") ); 02439 RTERR( rtAccelerationSetProperty(acceleration, "build_type", "CPU") ); 02440 RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") ); 02441 } 02442 #endif 02443 02444 } 02445 } 02446 } 02447 #endif 02448 02449 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) Finalizing OptiX rendering kernels...\n"); 02450 RTERR( rtContextValidate(ctx) ); 02451 if (lasterror != RT_SUCCESS) { 02452 printf("OptiXRenderer) An error occured validating the context. Rendering is aborted.\n"); 02453 return; 02454 } 02455 02456 RTERR( rtContextCompile(ctx) ); 02457 if (lasterror != RT_SUCCESS) { 02458 printf("OptiXRenderer) An error occured compiling the context. Rendering is aborted.\n"); 02459 return; 02460 } 02461 02462 double contextinittime = wkf_timer_timenow(ort_timer); 02463 time_ctx_validate = contextinittime - startctxtime; 02464 02465 // 02466 // Force OptiX to build the acceleration structure _now_ by using 02467 // an empty launch. This is done in OptiX sample 6... 02468 // 02469 // #define ORT_RETRY_FAILED_AS_BUILD 1 02470 #if defined(ORT_RETRY_FAILED_AS_BUILD) 02471 RTresult rc; 02472 rc = rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, 0, 0); 02473 RTERR( rc ); 02474 #else 02475 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, 0, 0) ); 02476 #endif 02477 02478 #if defined(ORT_RETRY_FAILED_AS_BUILD) 02479 // XXX this never works right, I just get another error saying: 02480 // "Cannot set builder while asynchronous building is in progress" 02481 if (rc == RT_ERROR_MEMORY_ALLOCATION_FAILED) { 02482 const char *curbuilderstr = NULL; 02483 RTERR( rtAccelerationGetBuilder(acceleration, &curbuilderstr) ); 02484 printf("Current OptiX builder str: '%s'\n", curbuilderstr); 02485 if (!strcmp(curbuilderstr, "Trbvh")) { 02486 // clear previous error so we don't abort immediately... 02487 lasterror = RT_SUCCESS; 02488 02489 // issue warning, and try to rebuild the AS using a different builder 02490 printf("OptiXRenderer) Trbvh AS ran out of GPU memory, retrying with MedianBvh...\n"); 02491 RTERR( rtAccelerationSetBuilder(acceleration, "MedianBvh") ); 02492 RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") ); 02493 02494 // try re-validating and re-compiling context after changing the 02495 // AS builder to something that can survive GPU memory shortages 02496 render_compile_and_validate(); 02497 } 02498 } 02499 #endif 02500 02501 time_ctx_AS_build = wkf_timer_timenow(ort_timer) - contextinittime; 02502 if (verbose == RT_VERB_DEBUG) { 02503 printf("OptiXRenderer) launching render: %d x %d\n", width, height); 02504 } 02505 } 02506 02507 02508 #if defined(VMDOPTIX_INTERACTIVE_OPENGL) 02509 02510 static void *createoptixwindow(const char *wintitle, int width, int height) { 02511 printf("OptiXRenderer) Creating OptiX window: %d x %d...\n", width, height); 02512 02513 void *win = glwin_create(wintitle, width, height); 02514 while (glwin_handle_events(win, GLWIN_EV_POLL_NONBLOCK) != 0); 02515 02516 glDrawBuffer(GL_BACK); 02517 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 02518 glClearColor(0.0, 0.0, 0.0, 1.0); /* black */ 02519 glViewport(0, 0, width, height); 02520 glClear(GL_COLOR_BUFFER_BIT); 02521 02522 glShadeModel(GL_FLAT); 02523 glMatrixMode(GL_PROJECTION); 02524 glLoadIdentity(); 02525 glOrtho(0.0, width, height, 0.0, -1.0, 1.0); 02526 glMatrixMode(GL_MODELVIEW); 02527 glLoadIdentity(); 02528 02529 glDrawBuffer(GL_BACK); 02530 glClear(GL_COLOR_BUFFER_BIT); 02531 02532 glwin_swap_buffers(win); 02533 02534 return win; 02535 } 02536 02537 02538 static void interactive_viewer_usage(RTcontext ctx, void *win) { 02539 printf("OptiXRenderer) VMD TachyonL-OptiX Interactive Ray Tracer help:\n"); 02540 printf("OptiXRenderer) ===============================================\n"); 02541 02542 print_ctx_devices(ctx); 02543 02544 // check for Spaceball/SpaceNavigator/Magellan input devices 02545 int havespaceball = ((glwin_spaceball_available(win)) && (getenv("VMDDISABLESPACEBALLXDRV") == NULL)); 02546 printf("OptiXRenderer) Spaceball/SpaceNavigator/Magellan: %s\n", 02547 (havespaceball) ? "Available" : "Not available"); 02548 02549 // check for stereo-capable display 02550 int havestereo, havestencil; 02551 glwin_get_wininfo(win, &havestereo, &havestencil); 02552 printf("OptiXRenderer) Stereoscopic display: %s\n", 02553 (havestereo) ? "Available" : "Not available"); 02554 02555 // check for vertical retrace sync 02556 int vsync=0, rc=0; 02557 if ((rc = glwin_query_vsync(win, &vsync)) == GLWIN_SUCCESS) { 02558 printf("OptiXRenderer) Vert retrace sync: %s\n", (vsync) ? "On" : "Off"); 02559 } else { 02560 printf("OptiXRenderer) Vert retrace sync: indeterminate\n"); 02561 } 02562 02563 printf("OptiXRenderer)\n"); 02564 printf("OptiXRenderer) General controls:\n"); 02565 printf("OptiXRenderer) space: save numbered snapshot image\n"); 02566 printf("OptiXRenderer) =: reset to initial view\n"); 02567 printf("OptiXRenderer) h: print this help info\n"); 02568 printf("OptiXRenderer) p: print current rendering parameters\n"); 02569 printf("OptiXRenderer) ESC,q: quit viewer\n"); 02570 printf("OptiXRenderer)\n"); 02571 printf("OptiXRenderer) Display controls\n"); 02572 printf("OptiXRenderer) F1: override shadows on/off (off=AO off too)\n"); 02573 printf("OptiXRenderer) F2: override AO on/off\n"); 02574 printf("OptiXRenderer) F3: override DoF on/off\n"); 02575 printf("OptiXRenderer) F4: override Depth cueing on/off\n"); 02576 #if defined(VMDOPTIX_USE_HMD) 02577 printf("OptiXRenderer) F5: override HMD/camera clipping plane/sphere\n"); 02578 printf("OptiXRenderer) F6: override HMD/camera headlight\n"); 02579 printf("OPtiXRenderer) F7: toggle HMD interleaved drawing\n"); 02580 printf("OPtiXRenderer) F8: toggle HMD tex caching/update mode\n"); 02581 printf("OPtiXRenderer) F9: switch HMD lens distortion mode\n"); 02582 #endif 02583 #ifdef USE_REVERSE_SHADOW_RAYS 02584 printf("OptiXRenderer) F10: enable/disable shadow ray optimizations\n"); 02585 #endif 02586 printf("OptiXRenderer) F12: toggle full-screen display on/off\n"); 02587 printf("OptiXRenderer) 1-9,0: override samples per update auto-FPS off\n"); 02588 printf("OptiXRenderer) Up: increase DoF focal distance\n"); 02589 printf("OptiXRenderer) Down: decrease DoF focal distance\n"); 02590 printf("OptiXRenderer) Left: decrease DoF f/stop\n"); 02591 printf("OptiXRenderer) Right: increase DoF f/stop\n"); 02592 printf("OptiXRenderer) S: toggle stereoscopic display on/off (if avail)\n"); 02593 printf("OptiXRenderer) a: toggle AA/AO auto-FPS tuning on/off (on)\n"); 02594 printf("OptiXRenderer) g: toggle gradient sky xforms on/off (on)\n"); 02595 printf("OptiXRenderer) l: toggle light xforms on/off (on)\n"); 02596 printf("OptiXRenderer)\n"); 02597 printf("OptiXRenderer) Mouse controls:\n"); 02598 printf("OptiXRenderer) f: mouse depth-of-field mode\n"); 02599 printf("OptiXRenderer) r: mouse rotation mode\n"); 02600 printf("OptiXRenderer) s: mouse scaling mode\n"); 02601 printf("OptiXRenderer) t: mouse translation mode\n"); 02602 02603 int movie_recording_enabled = (getenv("VMDOPTIXLIVEMOVIECAPTURE") != NULL); 02604 if (movie_recording_enabled) { 02605 printf("OptiXRenderer)\n"); 02606 printf("OptiXRenderer) Movie recording controls:\n"); 02607 printf("OptiXRenderer) R: start/stop movie recording\n"); 02608 printf("OptiXRenderer) F: toggle movie FPS (24, 30, 60)\n"); 02609 } 02610 } 02611 02612 02613 02614 void OptiXRenderer::render_to_glwin(const char *filename, int writealpha) { 02615 int i; 02616 02617 if (!context_created) 02618 return; 02619 02620 enum RtMouseMode { RTMM_ROT=0, RTMM_TRANS=1, RTMM_SCALE=2, RTMM_DOF=3 }; 02621 enum RtMouseDown { RTMD_NONE=0, RTMD_LEFT=1, RTMD_MIDDLE=2, RTMD_RIGHT=3 }; 02622 RtMouseMode mm = RTMM_ROT; 02623 RtMouseDown mousedown = RTMD_NONE; 02624 02625 // initialize HMD free-run flag to off until HMD code enumerates the 02626 // hardware and passes all the way through initialization 02627 int hmd_freerun = 0; 02628 #if defined(VMDOPTIX_USE_HMD) 02629 void *hmd_warp = NULL; 02630 #endif 02631 int hmd_warp_drawmode=1; 02632 02633 // default HMD distortion correction coefficients assume an Oculus DK2 HMD 02634 int hmd_warp_coeff_update=0; // warp equation was changed 02635 int hmd_warp_coeff_edit=1; // which power of r to edit 02636 int hmd_warp_coeff_set=0; // sets: 0=DK2, 1=MSR, 2=User 02637 const float dk2_warp_coeff[5] = { 1.000f, 0.000f, 0.600f, 0.000f, 0.000f }; 02638 // const float msr_warp_coeff[5] = { 1.000f, 0.290f, 0.195f, 0.045f, 0.360f }; 02639 const float msr_warp_coeff[5] = { 0.950f, 0.330f, 0.195f, 0.045f, 0.360f }; 02640 float user_warp_coeff[5] = { 1.000f, 0.000f, 0.600f, 0.000f, 0.000f }; 02641 float hmd_warp_coeff[5] = { 1.000f, 0.000f, 0.600f, 0.000f, 0.000f }; 02642 02643 // obtain user-defined warp coefficients from environment variable if set 02644 if (getenv("VMDOPTIXHMDUSERWARPCOEFFS")) { 02645 printf("OptiXRenderer) user-override of default user-defined HMD warp coefficients\n"); 02646 memset(user_warp_coeff, 0, sizeof(user_warp_coeff)); 02647 int cnt=sscanf(getenv("VMDOPTIXHMDUSERWARPCOEFFS"), "%f %f %f %f %f", 02648 &user_warp_coeff[0], &user_warp_coeff[1], 02649 &user_warp_coeff[2], &user_warp_coeff[3], 02650 &user_warp_coeff[4]); 02651 if (cnt != 5) { 02652 printf("OptiXRenderer) Warning: only parsed %d coefficients!\n", cnt); 02653 } else { 02654 printf("OptiXRenderer) user-defined warp coefficients: %d\n", cnt); 02655 printf("OptiXRenderer) %.3f %.3f %.3f %.3f %.3f\n", 02656 user_warp_coeff[0], user_warp_coeff[1], 02657 user_warp_coeff[2], user_warp_coeff[3], user_warp_coeff[4]); 02658 } 02659 } 02660 02661 // don't interleave extra HMD update/draw passes between buffer updates 02662 // unless the user wants us to, as a means of improving usability of 02663 // slow machines 02664 int hmd_interleave_draws = 0; 02665 if (getenv("VMDOPTIXHMDINTERLEAVEDRAWS")) { 02666 hmd_interleave_draws = 1; 02667 printf("OptiXRenderer) HMD GL draw call interleaving enabled\n"); 02668 } 02669 02670 int hmd_tex_caching = 0; 02671 if (getenv("VMDOPTIXHMDTEXCACHING")) { 02672 hmd_tex_caching = 1; 02673 printf("OptiXRenderer) HMD texture caching enabled\n"); 02674 } 02675 02676 // flag to skip the HMD GL draw calls for timing purposes 02677 int hmd_no_draw = 0; 02678 if (getenv("VMDOPTIXHMDNODRAW")) { 02679 hmd_no_draw = 1; 02680 printf("OptiXRenderer) HMD GL draw calls disabled\n"); 02681 } 02682 02683 // allow user-override of VR HMD sphere geometric res 02684 float hmd_fov = 95; 02685 if (getenv("VMDOPTIXHMDFOV")) { 02686 hmd_fov = float(atof(getenv("VMDOPTIXHMDFOV"))); 02687 printf("OptiXRenderer) User-override of HMD FoV: %.2f\n", hmd_fov); 02688 } 02689 02690 // allow user-override of VR HMD sphere geometric res 02691 int hmd_spres = 72; // 50 seems like the useful lower-bound spres setting 02692 if (getenv("VMDOPTIXHMDSPRES")) { 02693 hmd_spres = atoi(getenv("VMDOPTIXHMDSPRES")); 02694 printf("OptiXRenderer) User-override of HMD sph res: %d\n", hmd_spres); 02695 } 02696 02697 // flags to interactively enable/disable shadows, AO, DoF 02698 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT) 02699 int gl_shadows_on=(shadows_enabled) ? RT_SHADOWS_ON_REVERSE : RT_SHADOWS_OFF; 02700 #else 02701 int gl_shadows_on=(shadows_enabled) ? RT_SHADOWS_ON : RT_SHADOWS_OFF; 02702 #endif 02703 02704 int gl_fs_on=0; // fullscreen window state 02705 int fsowsx=0, fsowsy=0; // store last win size before fullscreen 02706 int owsx=0, owsy=0; // last win size 02707 int gl_ao_on=(ao_samples > 0); 02708 int gl_dof_on, gl_dof_on_old; 02709 gl_dof_on=gl_dof_on_old=dof_enabled; 02710 int gl_fog_on=(fog_mode != RT_FOG_NONE); 02711 int gl_clip_on=(clipview_mode != RT_CLIP_NONE); 02712 int gl_headlight_on=(headlight_mode != RT_HEADLIGHT_OFF); 02713 02714 // Enable live recording of a session to a stream of image files indexed 02715 // by their display presentation time, mapped to the nearest frame index 02716 // in a fixed-frame-rate image sequence (e.g. 24, 30, or 60 FPS), 02717 // to allow subsequent encoding into a standard movie format. 02718 // XXX this feature is disabled by default at present, to prevent people 02719 // from accidentally turning it on during a live demo or the like 02720 int movie_recording_enabled = (getenv("VMDOPTIXLIVEMOVIECAPTURE") != NULL); 02721 int movie_recording_on = 0; 02722 double movie_recording_start_time = 0.0; 02723 int movie_recording_fps = 30; 02724 int movie_framecount = 0; 02725 int movie_lastframeindex = 0; 02726 const char *movie_recording_filebase = "vmdlivemovie.%05d.tga"; 02727 if (getenv("VMDOPTIXLIVEMOVIECAPTUREFILEBASE")) 02728 movie_recording_filebase = getenv("VMDOPTIXLIVEMOVIECAPTUREFILEBASE"); 02729 02730 // Enable/disable Spaceball/SpaceNavigator/Magellan input 02731 int spaceballenabled=(getenv("VMDDISABLESPACEBALLXDRV") == NULL) ? 1 : 0; 02732 int spaceballmode=0; // default mode is rotation/translation 02733 int spaceballflightmode=0; // 0=moves object, 1=camera fly 02734 if (getenv("VMDOPTIXSPACEBALLFLIGHT")) 02735 spaceballflightmode=1; 02736 02737 // total AA/AO sample count 02738 int totalsamplecount=0; 02739 02740 // counter for snapshots of live image... 02741 int snapshotcount=0; 02742 02743 // flag to enable automatic AO sample count adjustment for FPS rate control 02744 #if defined(VMDOPTIX_PROGRESSIVEAPI) 02745 #if 1 02746 int autosamplecount=0; // leave disabled for now 02747 #else 02748 int autosamplecount=1; // works partially in current revs of progressive API 02749 #endif 02750 #else 02751 int autosamplecount=1; 02752 #endif 02753 02754 // flag to enable transformation of lights and gradient sky sphere, 02755 // so that they track camera orientation as they do in the VMD OpenGL display 02756 int xformlights=1, xformgradientsphere=1; 02757 02758 // 02759 // allocate or reconfigure the framebuffer, accumulation buffer, 02760 // and output streams required for progressive rendering, either 02761 // using the new progressive APIs, or using our own code. 02762 // 02763 // Unless overridden by environment variables, we use the incoming 02764 // window size parameters from VMD to initialize the RT image dimensions. 02765 // If image size is overridden, often when using HMDs, the incoming 02766 // dims are window dims are used to size the GL window, but the image size 02767 // is set independently. 02768 int wsx=width, wsy=height; 02769 const char *imageszstr = getenv("VMDOPTIXIMAGESIZE"); 02770 if (imageszstr) { 02771 if (sscanf(imageszstr, "%d %d", &width, &height) != 2) { 02772 width=wsx; 02773 height=wsy; 02774 } 02775 } 02776 02777 framebuffer_config(width, height, 1); 02778 02779 // prepare the majority of OptiX rendering state before we go into 02780 // the interactive rendering loop 02781 update_rendering_state(1); 02782 render_compile_and_validate(); 02783 02784 // make a copy of state we're going to interactively manipulate, 02785 // so that we can recover to the original state on-demand 02786 int samples_per_pass = 1; 02787 int force_ao_1 = 0; // whether or not to force AO count per pass to 1 02788 int cur_aa_samples = aa_samples; 02789 int cur_ao_samples = ao_samples; 02790 float cam_zoom_orig = cam_zoom; 02791 float scene_gradient_orig[3] = {0.0f, 1.0f, 0.0f}; 02792 vec_copy(scene_gradient_orig, scene_gradient); 02793 02794 float cam_pos_orig[3] = {0.0f, 0.0f, 2.0f}; 02795 float cam_U_orig[3] = {1.0f, 0.0f, 0.0f}; 02796 float cam_V_orig[3] = {0.0f, 1.0f, 0.0f}; 02797 float cam_W_orig[3] = {0.0f, 0.0f, -1.0f}; 02798 float cam_pos[3], cam_U[3], cam_V[3], cam_W[3]; 02799 float hmd_U[3], hmd_V[3], hmd_W[3]; 02800 02801 vec_copy(cam_pos, cam_pos_orig); 02802 vec_copy(cam_U, cam_U_orig); 02803 vec_copy(cam_V, cam_V_orig); 02804 vec_copy(cam_W, cam_W_orig); 02805 02806 // copy light directions 02807 DirectionalLight *cur_dlights = (DirectionalLight *) calloc(1, directional_lights.num() * sizeof(DirectionalLight)); 02808 for (i=0; i<directional_lights.num(); i++) { 02809 vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir); 02810 vec_normalize((float*)&cur_dlights[i].dir); 02811 } 02812 02813 #if defined(VMDOPTIX_USE_HMD) 02814 HMDMgr *hmd = NULL; 02815 // if using HMD for display, get head tracking data 02816 if (getenv("VMDOPTIXUSEHMD") != NULL) { 02817 hmd = new HMDMgr(); 02818 if (hmd->device_count() < 1) { 02819 delete hmd; 02820 hmd = NULL; 02821 } 02822 } 02823 if (hmd) { 02824 autosamplecount=0; // disable when targeting HMDs 02825 msgInfo << "OptiXRenderer) HMD in use, disabling auto sample count adjustement," << sendmsg; 02826 msgInfo << "OptiXRenderer) optimizing for lowest rendering latency." << sendmsg; 02827 } 02828 02829 #if defined(VMDOPTIX_PROGRESSIVEAPI) 02830 hmd_freerun = (hmd != NULL && camera_projection == RT_EQUIRECTANGULAR); 02831 #endif 02832 02833 #if defined(VMDUSEEVENTIO) 02834 evio_handle eviodev = NULL; 02835 const char *eviodevname = getenv("VMDOPTIXEVIODEV"); 02836 if (hmd && eviodevname) { 02837 msgInfo << "OptiXRenderer) Attempting to open '" 02838 << eviodevname << "' for Linux event I/O input..." << sendmsg; 02839 eviodev = evio_open(eviodevname); 02840 if (eviodev) { 02841 msgInfo << "OptiXRenderer) Using Linux event I/O input:" << sendmsg; 02842 evio_print_devinfo(eviodev); 02843 } 02844 } 02845 #endif 02846 #endif 02847 02848 // create the display window 02849 const char *windowtitle; 02850 #if 1 02851 windowtitle = "VMD TachyonL-OptiX Interactive Ray Tracer"; 02852 #else 02853 // useful for demos and perf comparisons 02854 if (getenv("VMDOPTIXNORTX") != NULL || rtx_enabled==0) { 02855 windowtitle = "VMD TachyonL-OptiX Interactive Ray Tracer -- Turing RTX DISABLED"; 02856 } else { 02857 windowtitle = "VMD TachyonL-OptiX Interactive Ray Tracer -- Turing RTX ENABLED"; 02858 } 02859 #endif 02860 02861 void *win = createoptixwindow(windowtitle, width, height); 02862 interactive_viewer_usage(ctx, win); 02863 02864 // check for stereo-capable display 02865 int havestereo=0, havestencil=0; 02866 int stereoon=0, stereoon_old=0; 02867 glwin_get_wininfo(win, &havestereo, &havestencil); 02868 02869 #if defined(VMDOPTIX_USE_HMD) && defined(VMDOPTIX_PROGRESSIVEAPI) 02870 if (hmd_freerun && hmd != NULL && camera_projection == RT_EQUIRECTANGULAR) { 02871 glwin_spheremap_draw_prepare(win); 02872 02873 // enable HMD optical distortion correction, unless force-disabled 02874 if (hmd != NULL && !getenv("VMDOPTIXHMDNOWARP")) 02875 hmd_warp = glwin_spheremap_create_hmd_warp(win, wsx, wsy, 21, 0, 02876 width, height, hmd_warp_coeff); 02877 02878 // if an HMD is in use, we trigger full-screen display by default 02879 if (hmd) { 02880 if (glwin_fullscreen(win, 1, 0) == 0) { 02881 gl_fs_on = 1; 02882 fsowsx = wsx; 02883 fsowsy = wsy; 02884 glwin_get_winsize(win, &wsx, &wsy); 02885 } else { 02886 printf("OptiXRenderer) Fullscreen mode not available\n"); 02887 } 02888 } 02889 } 02890 #endif 02891 02892 // Override AA/AO sample counts since we're doing progressive rendering. 02893 // Choosing an initial AO sample count of 1 will give us the peak progressive 02894 // display update rate, but we end up wasting time on re-tracing many 02895 // primary rays. The automatic FPS optimization scheme below will update 02896 // the number of samples per rendering pass and assign the best values for 02897 // AA/AO samples accordingly. 02898 cur_aa_samples = samples_per_pass; 02899 if (cur_ao_samples > 0) { 02900 cur_aa_samples = 1; 02901 cur_ao_samples = samples_per_pass; 02902 } 02903 02904 const char *statestr = "|/-\\."; 02905 int done=0, winredraw=1; 02906 int state=0, mousedownx=0, mousedowny=0; 02907 float cur_cam_zoom = cam_zoom_orig; 02908 02909 double fpsexpave=0.0; 02910 double hmdfpsexpave=0.0; 02911 double hmdgldrawtime=0.0; 02912 double mapbuftotaltime=0.0; 02913 double accumbufstarttime=wkf_timer_timenow(ort_timer); 02914 double oldtime = wkf_timer_timenow(ort_timer); 02915 #if defined(VMDOPTIX_USE_HMD) 02916 double hmdoldtime = oldtime; 02917 #endif 02918 while (!done) { 02919 int winevent=0; 02920 02921 #if 1 02922 if (app->uivs && app->uivs->srv_connected()) { 02923 if (app->uivs->srv_check_ui_event()) { 02924 int eventtype; 02925 app->uivs->srv_get_last_event_type(eventtype); 02926 switch (eventtype) { 02927 case VideoStream::VS_EV_ROTATE_BY: 02928 { int axis; 02929 float angle; 02930 app->uivs->srv_get_last_rotate_by(angle, axis); 02931 Matrix4 rm; 02932 02933 switch (axis) { 02934 case 'x': 02935 rm.rotate_axis(cam_U, -angle * VMD_PI/180.0f); 02936 break; 02937 02938 case 'y': 02939 rm.rotate_axis(cam_V, -angle * VMD_PI/180.0f); 02940 break; 02941 02942 case 'z': 02943 rm.rotate_axis(cam_W, -angle * VMD_PI/180.0f); 02944 break; 02945 } 02946 rm.multpoint3d(cam_pos, cam_pos); 02947 rm.multnorm3d(cam_U, cam_U); 02948 rm.multnorm3d(cam_V, cam_V); 02949 rm.multnorm3d(cam_W, cam_W); 02950 02951 if (xformgradientsphere) { 02952 rm.multnorm3d(scene_gradient, scene_gradient); 02953 } 02954 02955 if (xformlights) { 02956 // update light directions (comparatively costly) 02957 for (i=0; i<directional_lights.num(); i++) { 02958 rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir); 02959 } 02960 } 02961 winredraw = 1; 02962 } 02963 break; 02964 02965 case VideoStream::VS_EV_TRANSLATE_BY: 02966 { 02967 float dU[3], dV[3], dW[3]; 02968 float tx, ty, tz; 02969 app->uivs->srv_get_last_translate_by(tx, ty, tz); 02970 vec_scale(dU, -tx, cam_U); 02971 vec_scale(dV, -ty, cam_V); 02972 vec_scale(dW, -tz, cam_W); 02973 vec_add(cam_pos, cam_pos, dU); 02974 vec_add(cam_pos, cam_pos, dV); 02975 vec_add(cam_pos, cam_pos, dW); 02976 winredraw = 1; 02977 } 02978 break; 02979 02980 case VideoStream::VS_EV_SCALE_BY: 02981 { float zoominc; 02982 app->uivs->srv_get_last_scale_by(zoominc); 02983 cam_zoom *= 1.0f / zoominc; 02984 winredraw = 1; 02985 } 02986 break; 02987 02988 #if 0 02989 } else if (mm == RTMM_DOF) { 02990 cam_dof_fnumber += txdx * 20.0f; 02991 if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f; 02992 cam_dof_focal_dist += -txdy; 02993 if (cam_dof_focal_dist < 0.01f) cam_dof_focal_dist = 0.01f; 02994 winredraw = 1; 02995 } 02996 } 02997 #endif 02998 02999 case VideoStream::VS_EV_NONE: 03000 default: 03001 // should never happen... 03002 break; 03003 } 03004 } 03005 } 03006 #endif 03007 03008 03009 while ((winevent = glwin_handle_events(win, GLWIN_EV_POLL_NONBLOCK)) != 0) { 03010 int evdev, evval; 03011 char evkey; 03012 03013 glwin_get_lastevent(win, &evdev, &evval, &evkey); 03014 glwin_get_winsize(win, &wsx, &wsy); 03015 03016 if (evdev == GLWIN_EV_WINDOW_CLOSE) { 03017 printf("OptiXRenderer) display window closed, exiting...\n"); 03018 done = 1; 03019 winredraw = 0; 03020 } else if (evdev == GLWIN_EV_KBD) { 03021 switch (evkey) { 03022 case '`': autosamplecount=0; samples_per_pass=1; 03023 force_ao_1 = (!force_ao_1); winredraw=1; 03024 printf("OptiXRenderer) Toggling forced single AO sample per pass: %s\n", 03025 force_ao_1 ? "on" : "off"); 03026 break; 03027 03028 // update HMD warp distortion coefficients 03029 case '|': hmd_warp_coeff_set = (hmd_warp_coeff_set + 1) % 3; 03030 switch (hmd_warp_coeff_set) { 03031 case 0: 03032 printf("\nDistortion correction: DK2 stock lens\n"); 03033 memcpy(hmd_warp_coeff, dk2_warp_coeff, 5*sizeof(float)); 03034 break; 03035 03036 case 1: 03037 printf("\nDistortion correction: DK2 w/ MSR lens\n"); 03038 memcpy(hmd_warp_coeff, msr_warp_coeff, 5*sizeof(float)); 03039 break; 03040 03041 case 2: 03042 printf("\nDistortion correction: User defined lens\n"); 03043 memcpy(hmd_warp_coeff, user_warp_coeff, 5*sizeof(float)); 03044 break; 03045 } 03046 printf("\nHMD warp coeff: %.3f, %.3f, %.3f, %.3f, %.3f\n", 03047 hmd_warp_coeff[0], hmd_warp_coeff[1], 03048 hmd_warp_coeff[2], hmd_warp_coeff[3], 03049 hmd_warp_coeff[4]); 03050 hmd_warp_coeff_update=1; winredraw=1; break; 03051 break; 03052 03053 case '\\': hmd_warp_coeff_edit = (hmd_warp_coeff_edit + 1) % 5; 03054 printf("\nHMD edit warp coeff: r^%d\n",hmd_warp_coeff_edit); 03055 break; 03056 03057 case '[': hmd_warp_coeff[hmd_warp_coeff_edit]-=0.005; 03058 printf("\nHMD warp coeff: %.3f, %.3f, %.3f, %.3f, %.3f\n", 03059 hmd_warp_coeff[0], hmd_warp_coeff[1], 03060 hmd_warp_coeff[2], hmd_warp_coeff[3], 03061 hmd_warp_coeff[4]); 03062 memcpy(user_warp_coeff, hmd_warp_coeff, 5*sizeof(float)); 03063 hmd_warp_coeff_update=1; winredraw=1; break; 03064 03065 case ']': hmd_warp_coeff[hmd_warp_coeff_edit]+=0.005; 03066 printf("\nHMD warp coeff: %.3f, %.3f, %.3f, %.3f, %.3f\n", 03067 hmd_warp_coeff[0], hmd_warp_coeff[1], 03068 hmd_warp_coeff[2], hmd_warp_coeff[3], 03069 hmd_warp_coeff[4]); 03070 memcpy(user_warp_coeff, hmd_warp_coeff, 5*sizeof(float)); 03071 hmd_warp_coeff_update=1; winredraw=1; break; 03072 03073 // update sample counts 03074 case '1': autosamplecount=0; samples_per_pass=1; winredraw=1; break; 03075 case '2': autosamplecount=0; samples_per_pass=2; winredraw=1; break; 03076 case '3': autosamplecount=0; samples_per_pass=3; winredraw=1; break; 03077 case '4': autosamplecount=0; samples_per_pass=4; winredraw=1; break; 03078 case '5': autosamplecount=0; samples_per_pass=5; winredraw=1; break; 03079 case '6': autosamplecount=0; samples_per_pass=6; winredraw=1; break; 03080 case '7': autosamplecount=0; samples_per_pass=7; winredraw=1; break; 03081 case '8': autosamplecount=0; samples_per_pass=8; winredraw=1; break; 03082 case '9': autosamplecount=0; samples_per_pass=9; winredraw=1; break; 03083 case '0': autosamplecount=0; samples_per_pass=10; winredraw=1; break; 03084 03085 case '=': /* recover back to initial state */ 03086 vec_copy(scene_gradient, scene_gradient_orig); 03087 cam_zoom = cam_zoom_orig; 03088 vec_copy(cam_pos, cam_pos_orig); 03089 vec_copy(cam_U, cam_U_orig); 03090 vec_copy(cam_V, cam_V_orig); 03091 vec_copy(cam_W, cam_W_orig); 03092 03093 // restore original light directions 03094 for (i=0; i<directional_lights.num(); i++) { 03095 vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir); 03096 vec_normalize((float*)&cur_dlights[i].dir); 03097 } 03098 winredraw = 1; 03099 #if defined(VMDOPTIX_USE_HMD) 03100 // Handle HMD head orientation updates if we have one attached 03101 if (hmd) { 03102 hmd->reset_orientation(); 03103 printf("\nOptiXRenderer) Resetting HMD orientation\n"); 03104 } 03105 #endif 03106 break; 03107 03108 case ' ': /* spacebar saves current image with counter */ 03109 { 03110 char snapfilename[256]; 03111 sprintf(snapfilename, "vmdsnapshot.%04d.tga", snapshotcount); 03112 if (OptiXWriteImage(snapfilename, writealpha, framebuffer) != -1) { 03113 printf("OptiXRenderer) Saved snapshot to '%s' \n", 03114 snapfilename); 03115 } 03116 snapshotcount++; 03117 } 03118 break; 03119 03120 case 'a': /* toggle automatic sample count FPS tuning */ 03121 autosamplecount = !(autosamplecount); 03122 printf("\nOptiXRenderer) Automatic AO sample count FPS tuning %s\n", 03123 (autosamplecount) ? "enabled" : "disabled"); 03124 break; 03125 03126 case 'f': /* DoF mode */ 03127 mm = RTMM_DOF; 03128 printf("\nOptiXRenderer) Mouse DoF aperture and focal dist. mode\n"); 03129 break; 03130 03131 case 'g': /* toggle gradient sky sphere xforms */ 03132 xformgradientsphere = !(xformgradientsphere); 03133 printf("\nOptiXRenderer) Gradient sky sphere transformations %s\n", 03134 (xformgradientsphere) ? "enabled" : "disabled"); 03135 break; 03136 03137 case 'h': /* print help message */ 03138 printf("\n"); 03139 interactive_viewer_usage(ctx, win); 03140 03141 // we have to force a redraw after querying OptiX context 03142 // info due to the current behavior of the progressive API, 03143 // which halts upon any API call other than the simplest queries 03144 winredraw = 1; 03145 break; 03146 03147 case 'l': /* toggle lighting xforms */ 03148 xformlights = !(xformlights); 03149 printf("\nOptiXRenderer) Light transformations %s\n", 03150 (xformlights) ? "enabled" : "disabled"); 03151 break; 03152 03153 case 'p': /* print current RT settings */ 03154 printf("\nOptiXRenderer) Current Ray Tracing Parameters:\n"); 03155 printf("OptiXRenderer) -------------------------------\n"); 03156 printf("OptiXRenderer) Camera zoom: %f\n", cur_cam_zoom); 03157 printf("OptiXRenderer) Shadows: %s Ambient occlusion: %s\n", 03158 (gl_shadows_on) ? "on" : "off", 03159 (gl_ao_on) ? "on" : "off"); 03160 printf("OptiXRenderer) Antialiasing samples per-pass: %d\n", 03161 cur_aa_samples); 03162 printf("OptiXRenderer) Ambient occlusion samples per-pass: %d\n", 03163 cur_ao_samples); 03164 printf("OptiXRenderer) Depth-of-Field: %s f/num: %.1f Foc. Dist: %.2f\n", 03165 (gl_dof_on) ? "on" : "off", 03166 cam_dof_fnumber, cam_dof_focal_dist); 03167 printf("OptiXRenderer) Win size: %d x %d\n", wsx, wsy); 03168 printf("OptiXRenderer) Image size: %d x %d\n", width, height); 03169 break; 03170 03171 case 'r': /* rotate mode */ 03172 mm = RTMM_ROT; 03173 printf("\nOptiXRenderer) Mouse rotation mode\n"); 03174 break; 03175 03176 case 's': /* scaling mode */ 03177 mm = RTMM_SCALE; 03178 printf("\nOptiXRenderer) Mouse scaling mode\n"); 03179 break; 03180 03181 case 'F': /* toggle live movie recording FPS (24, 30, 60) */ 03182 if (movie_recording_enabled) { 03183 switch (movie_recording_fps) { 03184 case 24: movie_recording_fps = 30; break; 03185 case 30: movie_recording_fps = 60; break; 03186 case 60: 03187 default: movie_recording_fps = 24; break; 03188 } 03189 printf("\nOptiXRenderer) Movie recording FPS rate: %d\n", 03190 movie_recording_fps); 03191 } else { 03192 printf("\nOptiXRenderer) Movie recording not available.\n"); 03193 } 03194 break; 03195 03196 case 'R': /* toggle live movie recording mode on/off */ 03197 if (movie_recording_enabled) { 03198 movie_recording_on = !(movie_recording_on); 03199 printf("\nOptiXRenderer) Movie recording %s\n", 03200 (movie_recording_on) ? "STARTED" : "STOPPED"); 03201 if (movie_recording_on) { 03202 movie_recording_start_time = wkf_timer_timenow(ort_timer); 03203 movie_framecount = 0; 03204 movie_lastframeindex = 0; 03205 } else { 03206 printf("OptiXRenderer) Encode movie with:\n"); 03207 printf("OptiXRenderer) ffmpeg -f image2 -i vmdlivemovie.%%05d.tga -c:v libx264 -profile:v baseline -level 3.0 -pix_fmt yuv420p -b:v 15000000 output.mp4\n"); 03208 } 03209 } else { 03210 printf("\nOptiXRenderer) Movie recording not available.\n"); 03211 } 03212 break; 03213 03214 case 'S': /* toggle stereoscopic display mode */ 03215 if (havestereo) { 03216 stereoon = (!stereoon); 03217 printf("\nOptiXRenderer) Stereoscopic display %s\n", 03218 (stereoon) ? "enabled" : "disabled"); 03219 winredraw = 1; 03220 } else { 03221 printf("\nOptiXRenderer) Stereoscopic display unavailable\n"); 03222 } 03223 break; 03224 03225 case 't': /* translation mode */ 03226 mm = RTMM_TRANS; 03227 printf("\nOptiXRenderer) Mouse translation mode\n"); 03228 break; 03229 03230 case 'q': /* 'q' key */ 03231 case 'Q': /* 'Q' key */ 03232 case 0x1b: /* ESC key */ 03233 printf("\nOptiXRenderer) Exiting on user input. \n"); 03234 done=1; /* exit from interactive RT window */ 03235 break; 03236 } 03237 } else if (evdev != GLWIN_EV_NONE) { 03238 switch (evdev) { 03239 case GLWIN_EV_KBD_F1: /* turn shadows on/off */ 03240 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT) 03241 gl_shadows_on=(!gl_shadows_on) ? RT_SHADOWS_ON_REVERSE : RT_SHADOWS_OFF; 03242 #else 03243 gl_shadows_on=(!gl_shadows_on) ? RT_SHADOWS_ON : RT_SHADOWS_OFF; 03244 // gl_shadows_on = (!gl_shadows_on); 03245 #endif 03246 03247 printf("\n"); 03248 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT) 03249 printf("OptiXRenderer) Shadows %s\n", 03250 (gl_shadows_on) ? "enabled (reversal opt.)" : "disabled"); 03251 #else 03252 printf("OptiXRenderer) Shadows %s\n", 03253 (gl_shadows_on) ? "enabled" : "disabled"); 03254 #endif 03255 winredraw = 1; 03256 break; 03257 03258 case GLWIN_EV_KBD_F2: /* turn AO on/off */ 03259 gl_ao_on = (!gl_ao_on); 03260 printf("\n"); 03261 printf("OptiXRenderer) Ambient occlusion %s\n", 03262 (gl_ao_on) ? "enabled" : "disabled"); 03263 winredraw = 1; 03264 break; 03265 03266 case GLWIN_EV_KBD_F3: /* turn DoF on/off */ 03267 gl_dof_on = (!gl_dof_on); 03268 printf("\n"); 03269 printf("OptiXRenderer) Depth-of-field %s\n", 03270 (gl_dof_on) ? "enabled" : "disabled"); 03271 winredraw = 1; 03272 break; 03273 03274 case GLWIN_EV_KBD_F4: /* turn fog/depth cueing on/off */ 03275 gl_fog_on = (!gl_fog_on); 03276 printf("\n"); 03277 printf("OptiXRenderer) Depth cueing %s\n", 03278 (gl_fog_on) ? "enabled" : "disabled"); 03279 winredraw = 1; 03280 break; 03281 03282 case GLWIN_EV_KBD_F5: /* turn HMD/camera fade+clipping on/off */ 03283 gl_clip_on = (!gl_clip_on); 03284 printf("\n"); 03285 printf("OptiXRenderer) HMD/camera clipping plane/sphere %s\n", 03286 (gl_clip_on) ? "enabled" : "disabled"); 03287 winredraw = 1; 03288 break; 03289 03290 case GLWIN_EV_KBD_F6: /* turn HMD/camera headlight on/off */ 03291 gl_headlight_on = (!gl_headlight_on); 03292 printf("\n"); 03293 printf("OptiXRenderer) HMD/camera headlight %s\n", 03294 (gl_headlight_on) ? "enabled" : "disabled"); 03295 winredraw = 1; 03296 break; 03297 03298 case GLWIN_EV_KBD_F7: /* turn HMD draw interleaving on/off */ 03299 hmd_interleave_draws = (!hmd_interleave_draws); 03300 printf("\n"); 03301 printf("OptiXRenderer) HMD interleaved draws %s\n", 03302 (hmd_interleave_draws) ? "enabled" : "disabled"); 03303 break; 03304 03305 case GLWIN_EV_KBD_F8: /* turn HMD tex caching on/off */ 03306 hmd_tex_caching = (!hmd_tex_caching); 03307 printf("\n"); 03308 printf("OptiXRenderer) HMD tex caching %s\n", 03309 (hmd_tex_caching) ? "enabled" : "disabled"); 03310 break; 03311 03312 case GLWIN_EV_KBD_F9: /* switch HMD lens distortion correction mode */ 03313 hmd_warp_drawmode = (hmd_warp_drawmode+1) % 5; 03314 printf("\n"); 03315 { const char *warpmodestr="Off"; 03316 switch (hmd_warp_drawmode) { 03317 case 0: warpmodestr="Lens: Off Chroma: Off Grid: Off"; break; 03318 case 1: warpmodestr="Lens: On Chroma: On Grid: Off"; break; 03319 case 2: warpmodestr="Lens: On Chroma: On Grid: On "; break; 03320 case 3: warpmodestr="Lens: On Chroma: Off Grid: Off"; break; 03321 case 4: warpmodestr="Lens: On Chroma: Off Grid: On "; break; 03322 } 03323 printf("OptiXRenderer) HMD Corr. %s\n", warpmodestr); 03324 } 03325 break; 03326 03327 #ifdef USE_REVERSE_SHADOW_RAYS 03328 case GLWIN_EV_KBD_F10: /* toggle shadow ray reversal on/off */ 03329 if (gl_shadows_on == RT_SHADOWS_ON) 03330 gl_shadows_on = RT_SHADOWS_ON_REVERSE; 03331 else if (gl_shadows_on == RT_SHADOWS_ON_REVERSE) 03332 gl_shadows_on = RT_SHADOWS_ON; 03333 printf("\n"); 03334 printf("OptiXRenderer) Shadow ray reversal %s\n", 03335 (gl_shadows_on==RT_SHADOWS_ON_REVERSE) ? "enabled" : "disabled"); 03336 winredraw = 1; 03337 break; 03338 #endif 03339 03340 case GLWIN_EV_KBD_F12: /* toggle full-screen window on/off */ 03341 gl_fs_on = (!gl_fs_on); 03342 printf("\nOptiXRenderer) Toggling fullscreen window %s\n", 03343 (gl_fs_on) ? "on" : "off"); 03344 if (gl_fs_on) { 03345 if (glwin_fullscreen(win, gl_fs_on, 0) == 0) { 03346 fsowsx = wsx; 03347 fsowsy = wsy; 03348 glwin_get_winsize(win, &wsx, &wsy); 03349 } else { 03350 printf("OptiXRenderer) Fullscreen mode note available\n"); 03351 } 03352 } else { 03353 glwin_fullscreen(win, gl_fs_on, 0); 03354 glwin_resize(win, fsowsx, fsowsy); 03355 } 03356 winredraw = 1; 03357 break; 03358 03359 case GLWIN_EV_KBD_UP: /* change depth-of-field focal dist */ 03360 cam_dof_focal_dist *= 1.02f; 03361 printf("\nOptiXRenderer) DoF focal dist: %f\n", cam_dof_focal_dist); 03362 winredraw = 1; 03363 break; 03364 03365 case GLWIN_EV_KBD_DOWN: /* change depth-of-field focal dist */ 03366 cam_dof_focal_dist *= 0.96f; 03367 if (cam_dof_focal_dist < 0.02f) cam_dof_focal_dist = 0.02f; 03368 printf("\nOptiXRenderer) DoF focal dist: %f\n", cam_dof_focal_dist); 03369 winredraw = 1; 03370 break; 03371 03372 case GLWIN_EV_KBD_RIGHT: /* change depth-of-field f/stop number */ 03373 cam_dof_fnumber += 1.0f; 03374 printf("\nOptiXRenderer) DoF f/stop: %f\n", cam_dof_fnumber); 03375 winredraw = 1; 03376 break; 03377 03378 case GLWIN_EV_KBD_LEFT: /* change depth-of-field f/stop number */ 03379 cam_dof_fnumber -= 1.0f; 03380 if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f; 03381 printf("\nOptiXRenderer) DoF f/stop: %f\n", cam_dof_fnumber); 03382 winredraw = 1; 03383 break; 03384 03385 case GLWIN_EV_MOUSE_MOVE: 03386 if (mousedown != RTMD_NONE) { 03387 int x, y; 03388 glwin_get_mousepointer(win, &x, &y); 03389 03390 float zoommod = 2.0f*cur_cam_zoom/cam_zoom_orig; 03391 float txdx = (x - mousedownx) * zoommod / wsx; 03392 float txdy = (y - mousedowny) * zoommod / wsy; 03393 if (mm != RTMM_SCALE) { 03394 mousedownx = x; 03395 mousedowny = y; 03396 } 03397 03398 if (mm == RTMM_ROT) { 03399 Matrix4 rm; 03400 if (mousedown == RTMD_LEFT) { 03401 // when zooming in further from the initial view, we 03402 // rotate more slowly so control remains smooth 03403 rm.rotate_axis(cam_V, -txdx); 03404 rm.rotate_axis(cam_U, -txdy); 03405 } else if (mousedown == RTMD_MIDDLE || 03406 mousedown == RTMD_RIGHT) { 03407 rm.rotate_axis(cam_W, txdx); 03408 } 03409 rm.multpoint3d(cam_pos, cam_pos); 03410 rm.multnorm3d(cam_U, cam_U); 03411 rm.multnorm3d(cam_V, cam_V); 03412 rm.multnorm3d(cam_W, cam_W); 03413 03414 if (xformgradientsphere) { 03415 rm.multnorm3d(scene_gradient, scene_gradient); 03416 } 03417 03418 if (xformlights) { 03419 // update light directions (comparatively costly) 03420 for (i=0; i<directional_lights.num(); i++) { 03421 rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir); 03422 } 03423 } 03424 03425 winredraw = 1; 03426 } else if (mm == RTMM_TRANS) { 03427 if (mousedown == RTMD_LEFT) { 03428 float dU[3], dV[3]; 03429 vec_scale(dU, -txdx, cam_U); 03430 vec_scale(dV, txdy, cam_V); 03431 vec_add(cam_pos, cam_pos, dU); 03432 vec_add(cam_pos, cam_pos, dV); 03433 } else if (mousedown == RTMD_MIDDLE || 03434 mousedown == RTMD_RIGHT) { 03435 float dW[3]; 03436 vec_scale(dW, txdx, cam_W); 03437 vec_add(cam_pos, cam_pos, dW); 03438 } 03439 winredraw = 1; 03440 } else if (mm == RTMM_SCALE) { 03441 float txdx = (x - mousedownx) * 2.0 / wsx; 03442 float zoominc = 1.0f - txdx; 03443 if (zoominc < 0.01f) zoominc = 0.01f; 03444 cam_zoom = cur_cam_zoom * zoominc; 03445 winredraw = 1; 03446 } else if (mm == RTMM_DOF) { 03447 cam_dof_fnumber += txdx * 20.0f; 03448 if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f; 03449 cam_dof_focal_dist += -txdy; 03450 if (cam_dof_focal_dist < 0.01f) cam_dof_focal_dist = 0.01f; 03451 winredraw = 1; 03452 } 03453 } 03454 break; 03455 03456 case GLWIN_EV_MOUSE_LEFT: 03457 case GLWIN_EV_MOUSE_MIDDLE: 03458 case GLWIN_EV_MOUSE_RIGHT: 03459 if (evval) { 03460 glwin_get_mousepointer(win, &mousedownx, &mousedowny); 03461 cur_cam_zoom = cam_zoom; 03462 03463 if (evdev == GLWIN_EV_MOUSE_LEFT) mousedown = RTMD_LEFT; 03464 else if (evdev == GLWIN_EV_MOUSE_MIDDLE) mousedown = RTMD_MIDDLE; 03465 else if (evdev == GLWIN_EV_MOUSE_RIGHT) mousedown = RTMD_RIGHT; 03466 } else { 03467 mousedown = RTMD_NONE; 03468 } 03469 break; 03470 03471 case GLWIN_EV_MOUSE_WHEELUP: 03472 cam_zoom /= 1.1f; winredraw = 1; break; 03473 03474 case GLWIN_EV_MOUSE_WHEELDOWN: 03475 cam_zoom *= 1.1f; winredraw = 1; break; 03476 } 03477 } 03478 } 03479 03480 03481 // 03482 // Support for Spaceball/Spacenavigator/Magellan devices that use 03483 // X11 ClientMessage protocol.... 03484 // 03485 if (spaceballenabled) { 03486 // Spaceball/Spacenavigator/Magellan event state variables 03487 int tx=0, ty=0, tz=0, rx=0, ry=0, rz=0, buttons=0; 03488 if (glwin_get_spaceball(win, &rx, &ry, &rz, &tx, &ty, &tz, &buttons)) { 03489 // negate directions if we're in flight mode... 03490 if (spaceballflightmode) { 03491 rx= -rx; 03492 ry= -ry; 03493 rz= -rz; 03494 03495 tx= -tx; 03496 ty= -ty; 03497 tz= -tz; 03498 } 03499 03500 // check for button presses to reset the view 03501 if (buttons & 1) { 03502 printf("OptiXRenderer) spaceball button 1 pressed: reset view\n"); 03503 vec_copy(scene_gradient, scene_gradient_orig); 03504 cam_zoom = cam_zoom_orig; 03505 vec_copy(cam_pos, cam_pos_orig); 03506 vec_copy(cam_U, cam_U_orig); 03507 vec_copy(cam_V, cam_V_orig); 03508 vec_copy(cam_W, cam_W_orig); 03509 03510 // restore original light directions 03511 for (i=0; i<directional_lights.num(); i++) { 03512 vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir); 03513 vec_normalize((float*)&cur_dlights[i].dir); 03514 } 03515 winredraw = 1; 03516 } 03517 03518 // check for button presses to toggle spaceball mode 03519 if (buttons & 2) { 03520 spaceballmode = !(spaceballmode); 03521 printf("OptiXRenderer) spaceball mode: %s \n", 03522 (spaceballmode) ? "scaling" : "rotation/translation"); 03523 } 03524 03525 // rotation/translation mode 03526 if (spaceballmode == 0) { 03527 float zoommod = 2.0f*cam_zoom/cam_zoom_orig; 03528 float divlen = sqrtf(wsx*wsx + wsy*wsy) * 50.0f; 03529 03530 // check for rotation and handle it... 03531 if (rx != 0 || ry !=0 || rz !=0) { 03532 Matrix4 rm; 03533 rm.rotate_axis(cam_U, -rx * zoommod / divlen); 03534 rm.rotate_axis(cam_V, -ry * zoommod / divlen); 03535 rm.rotate_axis(cam_W, -rz * zoommod / divlen); 03536 03537 rm.multpoint3d(cam_pos, cam_pos); 03538 rm.multnorm3d(cam_U, cam_U); 03539 rm.multnorm3d(cam_V, cam_V); 03540 rm.multnorm3d(cam_W, cam_W); 03541 03542 if (xformgradientsphere) { 03543 rm.multnorm3d(scene_gradient, scene_gradient); 03544 } 03545 03546 if (xformlights) { 03547 // update light directions (comparatively costly) 03548 for (i=0; i<directional_lights.num(); i++) { 03549 rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir); 03550 } 03551 } 03552 winredraw = 1; 03553 } 03554 03555 // check for translation and handle it... 03556 if (tx != 0 || ty !=0 || tz !=0) { 03557 float dU[3], dV[3], dW[3]; 03558 vec_scale(dU, -tx * zoommod / divlen, cam_U); 03559 vec_scale(dV, -ty * zoommod / divlen, cam_V); 03560 vec_scale(dW, -tz * zoommod / divlen, cam_W); 03561 vec_add(cam_pos, cam_pos, dU); 03562 vec_add(cam_pos, cam_pos, dV); 03563 vec_add(cam_pos, cam_pos, dW); 03564 winredraw = 1; 03565 } 03566 } 03567 03568 // scaling mode 03569 if (spaceballmode == 1) { 03570 const float sbscale = 1.0f / (1024.0f * 8.0f); 03571 float zoominc = 1.0f - (rz * sbscale); 03572 if (zoominc < 0.01) zoominc = 0.01; 03573 cam_zoom *= zoominc; 03574 winredraw = 1; 03575 } 03576 03577 } 03578 } 03579 03580 03581 // if there is no HMD, we use the camera orientation directly 03582 vec_copy(hmd_U, cam_U); 03583 vec_copy(hmd_V, cam_V); 03584 vec_copy(hmd_W, cam_W); 03585 03586 // 03587 // Handle HMD head orientation by directly manipulating the 03588 // view orientation if we have an HMD attached and we're using 03589 // the direct-to-HMD "Oculus Rift" camera mode. For the other 03590 // equirectangular or cubemap cameras, the head pose processing 03591 // and all HMD lens aberration correction must done in the OpenGL 03592 // display code rather than in the RT code itself. When using the 03593 // direct-drive HMD camera, we only run a single rendering pass before 03594 // triggering a fresh orientation, since the head pose changes constantly. 03595 // 03596 #if defined(VMDOPTIX_USE_HMD) 03597 float hmd_U_new[3] = {1.0f, 0.0f, 0.0f}; 03598 float hmd_V_new[3] = {0.0f, 1.0f, 0.0f}; 03599 float hmd_W_new[3] = {0.0f, 0.0f, 1.0f}; 03600 #if defined(VMDUSEEVENTIO) 03601 if ((hmd && eviodev) || (hmd && camera_projection == RT_OCULUS_RIFT)) { 03602 #else 03603 if (hmd && camera_projection == RT_OCULUS_RIFT) { 03604 #endif 03605 float hmd_U_orig[3] = {1.0f, 0.0f, 0.0f}; 03606 float hmd_V_orig[3] = {0.0f, 1.0f, 0.0f}; 03607 float hmd_W_orig[3] = {0.0f, 0.0f, 1.0f}; 03608 03609 // query the HMD head pose as late as possible to reduce latency 03610 // between the sensor reads and presentation on the display 03611 hmd->update(); 03612 hmd->rot_basis_quat(hmd_U_new, hmd_V_new, hmd_W_new, 03613 hmd_U_orig, hmd_V_orig, hmd_W_orig); 03614 03615 // We use the HMD pose quaternion to transform the standard camera 03616 // orientation basis vectors to their new orientation, and then we 03617 // project those onto the current view basis vector to get the 03618 // correct final camera view vector that we pass along to OptiX 03619 float hmdtmp[3]; 03620 memset(hmdtmp, 0, sizeof(hmdtmp)); 03621 vec_scaled_add(hmdtmp, hmd_U_new[0], cam_U); 03622 vec_scaled_add(hmdtmp, hmd_U_new[1], cam_V); 03623 vec_scaled_add(hmdtmp, hmd_U_new[2], cam_W); 03624 vec_copy(hmd_U_new, hmdtmp); 03625 03626 memset(hmdtmp, 0, sizeof(hmdtmp)); 03627 vec_scaled_add(hmdtmp, hmd_V_new[0], cam_U); 03628 vec_scaled_add(hmdtmp, hmd_V_new[1], cam_V); 03629 vec_scaled_add(hmdtmp, hmd_V_new[2], cam_W); 03630 vec_copy(hmd_V_new, hmdtmp); 03631 03632 memset(hmdtmp, 0, sizeof(hmdtmp)); 03633 vec_scaled_add(hmdtmp, hmd_W_new[0], cam_U); 03634 vec_scaled_add(hmdtmp, hmd_W_new[1], cam_V); 03635 vec_scaled_add(hmdtmp, hmd_W_new[2], cam_W); 03636 vec_copy(hmd_W_new, hmdtmp); 03637 03638 #if 0 03639 float q[4]; 03640 hmd->get_rot_quat(q); 03641 printf("\nQ: %f %f %f %f\n", q[0], q[1], q[2], q[3]); 03642 printf("hmd_U: %.1f %.1f %.1f\n", hmd_U[0], hmd_U[1], hmd_U[2]); 03643 printf("hmd_V: %.1f %.1f %.1f\n", hmd_V[0], hmd_V[1], hmd_V[2]); 03644 printf("hmd_W: %.1f %.1f %.1f\n", hmd_W[0], hmd_W[1], hmd_W[2]); 03645 #endif 03646 03647 if (hmd && camera_projection == RT_OCULUS_RIFT) { 03648 vec_copy(hmd_U, hmd_U_new); 03649 vec_copy(hmd_V, hmd_V_new); 03650 vec_copy(hmd_W, hmd_W_new); 03651 03652 // when using an HMD in direct-drive mode, we have to do 03653 // a redraw on every rendering pass. 03654 winredraw = 1; 03655 } 03656 } 03657 #endif 03658 03659 03660 #if defined(VMDUSEEVENTIO) 03661 // 03662 // Handle Linux event-based input device I/O for joysticks/spaceball/etc 03663 // 03664 if (eviodev) { 03665 float ax1, ay1, ax2, ay2; 03666 int buttons; 03667 int rc=0; 03668 rc = evio_get_joystick_status(eviodev, &ax1, &ay1, &ax2, &ay2, &buttons); 03669 03670 if (buttons) { 03671 printf("Joystick: %5.2f %5.2f %5.2f %5.2f 0x%08x \n", 03672 ax1, ay1, ax2, ay2, buttons); 03673 } 03674 03675 float tx = ax1 + ax2; 03676 float ty = ay1; 03677 float tz = ay2; 03678 03679 // check for translation and handle it... 03680 if (fabsf(tx) > 0.03 || fabsf(ty) > 0.03 || fabsf(tz) > 0.03) { 03681 tx *= -500; 03682 ty *= 500; 03683 tz *= 500; 03684 03685 // Re-use the HMD head pose info obtained above to apply 03686 // head motion translations from joysticks or other controllers 03687 float zoommod = 2.0f*cam_zoom/cam_zoom_orig; 03688 float divlen = sqrtf(wsx*wsx + wsy*wsy) * 50; 03689 float dU[3], dV[3], dW[3]; 03690 vec_scale(dU, -tx * zoommod / divlen, hmd_U_new); 03691 vec_scale(dV, -ty * zoommod / divlen, hmd_V_new); 03692 vec_scale(dW, -tz * zoommod / divlen, hmd_W_new); 03693 vec_add(cam_pos, cam_pos, dU); 03694 vec_add(cam_pos, cam_pos, dV); 03695 vec_add(cam_pos, cam_pos, dW); 03696 winredraw = 1; 03697 } 03698 03699 } 03700 #endif 03701 03702 03703 // 03704 // handle window resizing, stereoscopic mode changes, 03705 // destroy and recreate affected OptiX buffers 03706 // 03707 int resize_buffers=0; 03708 03709 #if defined(VMDOPTIX_USE_HMD) 03710 // when using spheremaps, we trigger redraw ops but we do not change 03711 // the spheremap image size 03712 if (hmd_freerun) { 03713 if (wsx != owsx || wsy != owsy) 03714 winredraw=1; 03715 } 03716 else 03717 #endif 03718 { 03719 // only process image/window resizing when not drawing spheremaps 03720 if (wsx != width) { 03721 width = wsx; 03722 resize_buffers=1; 03723 } 03724 03725 if (wsy != height || (stereoon != stereoon_old)) { 03726 if (stereoon) { 03727 if (height != wsy * 2) { 03728 height = wsy * 2; 03729 resize_buffers=1; 03730 } 03731 } else { 03732 height = wsy; 03733 resize_buffers=1; 03734 } 03735 } 03736 } 03737 03738 03739 // XXX Prior to OptiX 3.8, we had to manually stop progressive 03740 // mode before changing any OptiX state. 03741 #if defined(VMDOPTIX_PROGRESSIVEAPI) && OPTIX_VERSION < 3080 03742 // 03743 // Check for all conditions that would require modifying OptiX state 03744 // and tell the VCA to stop progressive rendering before we modify 03745 // the rendering state, 03746 // 03747 if (done || winredraw || resize_buffers || 03748 (stereoon != stereoon_old) || (gl_dof_on != gl_dof_on_old)) { 03749 // need to issue stop command before editing optix objects 03750 if (vcarunning) { 03751 rtContextStopProgressive(ctx); 03752 vcarunning=0; 03753 } 03754 } 03755 #endif 03756 03757 // check if stereo mode or DoF mode changed, both cases 03758 // require changing the active color accumulation ray gen program 03759 if ((stereoon != stereoon_old) || (gl_dof_on != gl_dof_on_old)) { 03760 // when stereo mode changes, we have to regenerate the 03761 // the RNG, accumulation buffer, and framebuffer 03762 if (stereoon != stereoon_old) { 03763 resize_buffers=1; 03764 } 03765 03766 // update stereo and DoF state 03767 stereoon_old = stereoon; 03768 gl_dof_on_old = gl_dof_on; 03769 03770 // set the active color accumulation ray gen program based on the 03771 // camera/projection mode, stereoscopic display mode, 03772 // and depth-of-field state 03773 set_accum_raygen_pgm(camera_projection, stereoon, gl_dof_on); 03774 } 03775 03776 if (resize_buffers) { 03777 framebuffer_resize(width, height); 03778 03779 // when movie recording is enabled, print the window size as a guide 03780 // since the user might want to precisely control the size or 03781 // aspect ratio for a particular movie format, e.g. 1080p, 4:3, 16:9 03782 if (movie_recording_enabled) { 03783 printf("\rOptiXRenderer) Window resize: %d x %d \n", width, height); 03784 } 03785 03786 winredraw=1; 03787 } 03788 03789 int frame_ready = 1; // Default to true for the non-VCA case 03790 unsigned int subframe_count = 1; 03791 if (!done) { 03792 #if defined(VMDOPTIX_USE_HMD) 03793 // update HMD lens distortion correction mesh and/or warp coefficients 03794 if (hmd_warp && (winredraw || hmd_warp_coeff_update)) { 03795 glwin_spheremap_update_hmd_warp(win, hmd_warp, wsx, wsy, 21, 03796 width, height, hmd_warp_coeff, 03797 hmd_warp_coeff_update); 03798 hmd_warp_coeff_update=0; 03799 } 03800 #endif 03801 03802 // 03803 // If the user interacted with the window in a meaningful way, we 03804 // need to update the OptiX rendering state, recompile and re-validate 03805 // the context, and then re-render... 03806 // 03807 if (winredraw) { 03808 // update camera parameters 03809 RTERR( rtVariableSet1f( cam_zoom_v, cam_zoom) ); 03810 RTERR( rtVariableSet3fv( cam_pos_v, cam_pos) ); 03811 RTERR( rtVariableSet3fv( cam_U_v, hmd_U) ); 03812 RTERR( rtVariableSet3fv( cam_V_v, hmd_V) ); 03813 RTERR( rtVariableSet3fv( cam_W_v, hmd_W) ); 03814 RTERR( rtVariableSet3fv(scene_gradient_v, scene_gradient) ); 03815 03816 // update shadow state 03817 RTERR( rtVariableSet1i(shadows_enabled_v, gl_shadows_on) ); 03818 03819 // update depth cueing state 03820 RTERR( rtVariableSet1i(fog_mode_v, 03821 (int) (gl_fog_on) ? fog_mode : RT_FOG_NONE) ); 03822 03823 // update clipping sphere state 03824 RTERR( rtVariableSet1i(clipview_mode_v, 03825 (int) (gl_clip_on) ? clipview_mode : RT_CLIP_NONE) ); 03826 03827 // update headlight state 03828 RTERR( rtVariableSet1i(headlight_mode_v, 03829 (int) (gl_headlight_on) ? RT_HEADLIGHT_ON : RT_HEADLIGHT_OFF) ); 03830 03831 // update/recompute DoF values 03832 RTERR( rtVariableSet1f(cam_dof_focal_dist_v, cam_dof_focal_dist) ); 03833 RTERR( rtVariableSet1f(cam_dof_aperture_rad_v, cam_dof_focal_dist / (2.0f * cam_zoom * cam_dof_fnumber)) ); 03834 03835 // 03836 // Update light directions in the OptiX light buffer or user object. 03837 // Only update when xformlights is set, otherwise we take a 03838 // speed hit when using a remote VCA cluster for rendering. 03839 // 03840 // We only transform directional lights, since our positional lights 03841 // are normally affixed to the model coordinate system rather than 03842 // the camera. 03843 // 03844 if (xformlights) { 03845 #if defined(VMDOPTIX_LIGHTUSEROBJS) 03846 DirectionalLightList dlights; 03847 memset(&dlights, 0, sizeof(DirectionalLightList) ); 03848 dlights.num_lights = directional_lights.num(); 03849 int dlcount = directional_lights.num(); 03850 dlcount = (dlcount > DISP_LIGHTS) ? DISP_LIGHTS : dlcount; 03851 for (i=0; i<dlcount; i++) { 03852 //vec_copy( (float*)( &lights.dirs[i] ), cur_dlights[i].dir ); 03853 dlights.dirs[i] = cur_dlights[i].dir; 03854 } 03855 RTERR( rtVariableSetUserData(dir_light_list_v, sizeof(DirectionalLightList), &dlights) ); 03856 #else 03857 DirectionalLight *dlbuf; 03858 RTERR( rtBufferMap(dir_lightbuffer, (void **) &dlbuf) ); 03859 for (i=0; i<directional_lights.num(); i++) { 03860 vec_copy((float*)&dlbuf[i].dir, (float*)&cur_dlights[i].dir); 03861 } 03862 RTERR( rtBufferUnmap(dir_lightbuffer) ); 03863 #endif 03864 } 03865 03866 // reset accumulation buffer 03867 totalsamplecount=0; 03868 03869 // 03870 // Sample count updates and OptiX state must always remain in 03871 // sync, so if we only update sample count state during redraw events, 03872 // that's the only time we should recompute the sample counts, since 03873 // they also affect normalization factors for the accumulation buffer 03874 // in the non-VCA case. 03875 // 03876 03877 // Update sample counts to achieve target interactivity 03878 if (autosamplecount) { 03879 if (fpsexpave > 37) 03880 samples_per_pass++; 03881 else if (fpsexpave < 30) 03882 samples_per_pass--; 03883 03884 // clamp sample counts to a "safe" range 03885 if (samples_per_pass > 14) 03886 samples_per_pass=14; 03887 if (samples_per_pass < 1) 03888 samples_per_pass=1; 03889 } 03890 03891 // split samples per pass either among AA and AO, depending on 03892 // whether DoF and AO are enabled or not. 03893 if (force_ao_1) { 03894 cur_aa_samples = samples_per_pass; 03895 cur_ao_samples = 1; 03896 } else if (gl_shadows_on && gl_ao_on) { 03897 if (gl_dof_on) { 03898 if (samples_per_pass < 4) { 03899 cur_aa_samples=samples_per_pass; 03900 cur_ao_samples=1; 03901 } else { 03902 int s = (int) sqrtf(samples_per_pass); 03903 cur_aa_samples=s; 03904 cur_ao_samples=s; 03905 } 03906 } else { 03907 cur_aa_samples=1; 03908 cur_ao_samples=samples_per_pass; 03909 } 03910 } else { 03911 cur_aa_samples=samples_per_pass; 03912 cur_ao_samples=0; 03913 } 03914 03915 // update the current AA/AO sample counts since they may be changing if 03916 // FPS autotuning is enabled... 03917 RTERR( rtVariableSet1i(aa_samples_v, cur_aa_samples) ); 03918 03919 // observe latest AO enable/disable flag, and sample count 03920 if (gl_shadows_on && gl_ao_on) { 03921 RTERR( rtVariableSet1i(ao_samples_v, cur_ao_samples) ); 03922 } else { 03923 cur_ao_samples = 0; 03924 RTERR( rtVariableSet1i(ao_samples_v, 0) ); 03925 } 03926 03927 #ifdef VMDOPTIX_PROGRESSIVEAPI 03928 RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(cur_aa_samples)) ); 03929 #endif 03930 03931 // updated cached copy of previous window dimensions so we can 03932 // trigger updates on HMD spheremaps and FBOs as necessary 03933 owsx = wsx; 03934 owsy = wsy; 03935 } 03936 03937 03938 // 03939 // The non-VCA code path must handle the accumulation buffer 03940 // for itself, correctly rescaling the accumulated samples when 03941 // drawing to the output framebuffer. 03942 // 03943 // The VCA code path takes care of normalization for itself. 03944 // 03945 #ifndef VMDOPTIX_PROGRESSIVEAPI 03946 // The accumulation buffer normalization factor must be updated 03947 // to reflect the total accumulation count before the accumulation 03948 // buffer is drawn to the output framebuffer 03949 RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(cur_aa_samples + accum_count)) ); 03950 03951 // The accumulation buffer subframe index must be updated to ensure that 03952 // the RNGs for AA and AO get correctly re-seeded 03953 RTERR( rtVariableSet1ui(accum_count_v, accum_count) ); 03954 03955 // Force context compilation/validation 03956 // If no state has changed, there's no need to recompile/validate. 03957 // This call can be omitted since OptiX will do this automatically 03958 // at the next rtContextLaunchXXX() call. 03959 // render_compile_and_validate(); 03960 #endif 03961 03962 03963 // 03964 // run the renderer 03965 // 03966 frame_ready = 1; // Default to true for the non-VCA case 03967 subframe_count = 1; 03968 if (lasterror == RT_SUCCESS) { 03969 if (winredraw) { 03970 #if defined(ORT_RAYSTATS) 03971 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_RAYSTATS, width, height) ); 03972 accumbufstarttime=wkf_timer_timenow(ort_timer); 03973 #endif 03974 #ifdef VMDOPTIX_PROGRESSIVEAPI 03975 // start the VCA doing progressive rendering... 03976 RTERR( rtContextLaunchProgressive2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height, 0) ); 03977 #else 03978 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, width, height) ); 03979 #endif 03980 winredraw=0; 03981 } 03982 03983 #ifdef VMDOPTIX_PROGRESSIVEAPI 03984 // Wait for the next frame to arrive 03985 RTERR( rtBufferGetProgressiveUpdateReady(framebuffer, &frame_ready, &subframe_count, 0) ); 03986 if (frame_ready) 03987 totalsamplecount = subframe_count * samples_per_pass; 03988 #else 03989 // iterate, adding to the accumulation buffer... 03990 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height) ); 03991 subframe_count++; // increment subframe index 03992 totalsamplecount += samples_per_pass; 03993 accum_count += cur_aa_samples; 03994 03995 // copy the accumulation buffer image data to the framebuffer and 03996 // perform type conversion and normaliztion on the image data... 03997 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_COPY_FINISH, width, height) ); 03998 #endif 03999 04000 if (lasterror == RT_SUCCESS) { 04001 if (frame_ready || hmd_freerun) { 04002 double bufnewtime = wkf_timer_timenow(ort_timer); 04003 04004 // if an HMD is connected and one of the panoramic image formats 04005 // is in use, we use the appopriate OpenGL HMD viewer for the 04006 // panoramic image format that's currently active, otherwise the 04007 // image is displayed as-is in a window. 04008 #if defined(VMDOPTIX_USE_HMD) 04009 if (hmd_freerun) { 04010 double hmdnewtime = wkf_timer_timenow(ort_timer); 04011 double hmdframetime = (hmdnewtime-hmdoldtime) + 0.00001f; 04012 hmdoldtime=hmdnewtime; 04013 04014 // compute exponential moving average for exp(-1/10) 04015 double hmdframefps = 1.0f/hmdframetime; 04016 hmdfpsexpave = (hmdfpsexpave * 0.90) + (hmdframefps * 0.10); 04017 04018 float hmdquat[4]; 04019 if (hmd_no_draw == 0) { 04020 int hmd_warp_on = (hmd_warp_drawmode!=0); 04021 int hmd_warp_lines = (hmd_warp_drawmode==2 || hmd_warp_drawmode==4); 04022 int hmd_chroma_on = (hmd_warp_drawmode==1 || hmd_warp_drawmode==2); 04023 04024 // update when frame is ready, or when tex caching is disabled 04025 if (frame_ready || (!hmd_tex_caching)) { 04026 // display output image 04027 const unsigned char * img; 04028 rtBufferMap(framebuffer, (void **) &img); 04029 04030 // minimize impact of OptiX buffer map and tex update steps 04031 if (hmd_interleave_draws) { 04032 // query HMD sensors immediately prior to draw... 04033 hmd->get_rot_quat(hmdquat, 1); 04034 if (hmd_warp && hmd_warp_drawmode != 0) { 04035 glwin_spheremap_draw_hmd_warp(win, hmd_warp, 04036 hmd_warp_on, hmd_warp_lines, hmd_chroma_on, 04037 wsx, wsy, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres); 04038 } else { 04039 glwin_spheremap_draw_tex(win, GLWIN_STEREO_OVERUNDER, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres); 04040 } 04041 glwin_swap_buffers(win); 04042 } 04043 04044 glwin_spheremap_upload_tex_rgb3u(win, width, height, img); 04045 04046 // minimize impact of OptiX buffer map and tex update steps 04047 if (hmd_interleave_draws) { 04048 // query HMD sensors immediately prior to draw... 04049 hmd->get_rot_quat(hmdquat, 1); 04050 if (hmd_warp && hmd_warp_drawmode != 0) { 04051 glwin_spheremap_draw_hmd_warp(win, hmd_warp, 04052 hmd_warp_on, hmd_warp_lines, hmd_chroma_on, 04053 wsx, wsy, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres); 04054 } else { 04055 glwin_spheremap_draw_tex(win, GLWIN_STEREO_OVERUNDER, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres); 04056 } 04057 glwin_swap_buffers(win); 04058 } 04059 04060 rtBufferUnmap(framebuffer); 04061 mapbuftotaltime = wkf_timer_timenow(ort_timer) - bufnewtime; 04062 } 04063 04064 // query HMD sensors immediately prior to draw... 04065 hmd->get_rot_quat(hmdquat, 1); 04066 if (hmd_warp && hmd_warp_drawmode != 0) { 04067 glwin_spheremap_draw_hmd_warp(win, hmd_warp, 04068 hmd_warp_on, hmd_warp_lines, hmd_chroma_on, 04069 wsx, wsy, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres); 04070 } else { 04071 glwin_spheremap_draw_tex(win, GLWIN_STEREO_OVERUNDER, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres); 04072 } 04073 glwin_swap_buffers(win); 04074 } 04075 04076 hmdgldrawtime = wkf_timer_timenow(ort_timer) - hmdnewtime; 04077 } else { 04078 #endif 04079 // display output image 04080 const unsigned char * img; 04081 rtBufferMap(framebuffer, (void **) &img); 04082 04083 #if 0 04084 glwin_draw_image_tex_rgb3u(win, (stereoon!=0)*GLWIN_STEREO_OVERUNDER, width, height, img); 04085 #else 04086 glwin_draw_image_rgb3u(win, (stereoon!=0)*GLWIN_STEREO_OVERUNDER, width, height, img); 04087 #endif 04088 04089 #if 1 04090 // push latest frame into the video streaming pipeline 04091 // and pump the event handling mechanism afterwards 04092 if (app->uivs && app->uivs->srv_connected()) { 04093 app->uivs->video_frame_pending(img, width, height); 04094 app->uivs->check_event(); 04095 } 04096 #endif 04097 04098 rtBufferUnmap(framebuffer); 04099 mapbuftotaltime = wkf_timer_timenow(ort_timer) - bufnewtime; 04100 04101 #if defined(VMDOPTIX_USE_HMD) 04102 } 04103 #endif 04104 04105 04106 // if live movie recording is on, we save every displayed frame 04107 // to a sequence sequence of image files, with each file numbered 04108 // by its frame index, which is computed by the multiplying image 04109 // presentation time by the image sequence fixed-rate-FPS value. 04110 if (movie_recording_enabled && movie_recording_on) { 04111 char moviefilename[2048]; 04112 04113 // compute frame number from wall clock time and the 04114 // current fixed-rate movie playback frame rate 04115 double now = wkf_timer_timenow(ort_timer); 04116 double frametime = now - movie_recording_start_time; 04117 int fidx = frametime * movie_recording_fps; 04118 04119 // always force the first recorded frame to be 0 04120 if (movie_framecount==0) 04121 fidx=0; 04122 movie_framecount++; 04123 04124 #if defined(__linux) 04125 // generate symlinks for frame indices between the last written 04126 // frame and the current one so that video encoders such as 04127 // ffmpeg and mencoder can be fed the contiguous frame sequence 04128 // at a fixed frame rate, as they require 04129 sprintf(moviefilename, movie_recording_filebase, 04130 movie_lastframeindex); 04131 int symidx; 04132 for (symidx=movie_lastframeindex; symidx<fidx; symidx++) { 04133 char symlinkfilename[2048]; 04134 sprintf(symlinkfilename, movie_recording_filebase, symidx); 04135 if (symlink(moviefilename, symlinkfilename) < 0) 04136 perror("symlink: "); 04137 } 04138 #endif 04139 04140 // write the new movie frame 04141 sprintf(moviefilename, movie_recording_filebase, fidx); 04142 if (OptiXWriteImage(moviefilename, writealpha, framebuffer, 04143 RT_FORMAT_UNSIGNED_BYTE4, width, height) == -1) { 04144 movie_recording_on = 0; 04145 printf("\n"); 04146 printf("OptiXRenderer) ERROR during writing image during movie recording!\n"); 04147 printf("OptiXRenderer) Movie recording STOPPED\n"); 04148 } 04149 04150 movie_lastframeindex = fidx; // update last frame index written 04151 } 04152 } 04153 } else { 04154 printf("OptiXRenderer) An error occured during rendering. Rendering is aborted.\n"); 04155 done=1; 04156 break; 04157 } 04158 } else { 04159 printf("OptiXRenderer) An error occured in AS generation. Rendering is aborted.\n"); 04160 done=1; 04161 break; 04162 } 04163 } 04164 04165 if (!done && frame_ready) { 04166 double newtime = wkf_timer_timenow(ort_timer); 04167 double frametime = (newtime-oldtime) + 0.00001f; 04168 oldtime=newtime; 04169 04170 // compute exponential moving average for exp(-1/10) 04171 double framefps = 1.0f/frametime; 04172 fpsexpave = (fpsexpave * 0.90) + (framefps * 0.10); 04173 04174 if (hmd_freerun) { 04175 printf("OptiXRenderer) %c AA%2d AO%2d %5d tot RT FPS %.1f HMD FPS %.0f GL%.4f MB%.4f \r", 04176 statestr[state], cur_aa_samples, cur_ao_samples, 04177 totalsamplecount, fpsexpave, 04178 hmdfpsexpave, hmdgldrawtime, mapbuftotaltime); 04179 } else { 04180 printf("OptiXRenderer) %c AA:%2d AO:%2d, %4d tot RT FPS: %.1f %.4f s/frame sf: %d \r", 04181 statestr[state], cur_aa_samples, cur_ao_samples, 04182 totalsamplecount, fpsexpave, frametime, subframe_count); 04183 } 04184 04185 fflush(stdout); 04186 state = (state+1) & 3; 04187 } 04188 04189 } // end of per-cycle event processing 04190 04191 printf("\n"); 04192 04193 // write the output image upon exit... 04194 if (lasterror == RT_SUCCESS) { 04195 #if defined(ORT_RAYSTATS) 04196 double frametime = wkf_timer_timenow(ort_timer) - accumbufstarttime; 04197 OptiXPrintRayStats(raystats1_buffer, raystats2_buffer, frametime); 04198 #endif 04199 04200 wkf_timer_start(ort_timer); 04201 OptiXWriteImage(filename, writealpha, framebuffer); // write output image 04202 wkf_timer_stop(ort_timer); 04203 04204 if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) { 04205 printf("OptiXRenderer) image file I/O time: %f secs\n", wkf_timer_time(ort_timer)); 04206 } 04207 } 04208 04209 #if defined(VMDOPTIX_USE_HMD) 04210 // if using HMD for display, get head tracking data 04211 if (hmd) { 04212 delete hmd; 04213 hmd = NULL; 04214 } 04215 04216 if (hmd_warp != NULL) { 04217 glwin_spheremap_destroy_hmd_warp(win, hmd_warp); 04218 } 04219 #endif 04220 04221 #if defined(VMDUSEEVENTIO) 04222 if (eviodev) { 04223 evio_close(eviodev); 04224 } 04225 #endif 04226 04227 glwin_destroy(win); 04228 } 04229 04230 #endif 04231 04232 04233 04234 void OptiXRenderer::render_to_videostream(const char *filename, int writealpha) { 04235 int i; 04236 04237 if (!context_created) 04238 return; 04239 04240 // flags to interactively enable/disable shadows, AO, DoF 04241 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT) 04242 int gl_shadows_on=(shadows_enabled) ? RT_SHADOWS_ON_REVERSE : RT_SHADOWS_OFF; 04243 #else 04244 int gl_shadows_on=(shadows_enabled) ? RT_SHADOWS_ON : RT_SHADOWS_OFF; 04245 #endif 04246 04247 // int owsx=0, owsy=0; // last win size 04248 int gl_ao_on=(ao_samples > 0); 04249 int gl_dof_on, gl_dof_on_old; 04250 gl_dof_on=gl_dof_on_old=dof_enabled; 04251 int gl_fog_on=(fog_mode != RT_FOG_NONE); 04252 int gl_clip_on=(clipview_mode != RT_CLIP_NONE); 04253 int gl_headlight_on=(headlight_mode != RT_HEADLIGHT_OFF); 04254 04255 // Enable live recording of a session to a stream of image files indexed 04256 // by their display presentation time, mapped to the nearest frame index 04257 // in a fixed-frame-rate image sequence (e.g. 24, 30, or 60 FPS), 04258 // to allow subsequent encoding into a standard movie format. 04259 // XXX this feature is disabled by default at present, to prevent people 04260 // from accidentally turning it on during a live demo or the like 04261 int movie_recording_enabled = (getenv("VMDOPTIXLIVEMOVIECAPTURE") != NULL); 04262 int movie_recording_on = 0; 04263 double movie_recording_start_time = 0.0; 04264 int movie_recording_fps = 30; 04265 int movie_framecount = 0; 04266 int movie_lastframeindex = 0; 04267 const char *movie_recording_filebase = "vmdlivemovie.%05d.tga"; 04268 if (getenv("VMDOPTIXLIVEMOVIECAPTUREFILEBASE")) 04269 movie_recording_filebase = getenv("VMDOPTIXLIVEMOVIECAPTUREFILEBASE"); 04270 04271 // total AA/AO sample count 04272 int totalsamplecount=0; 04273 04274 // counter for snapshots of live image... 04275 //int snapshotcount=0; 04276 04277 // flag to enable automatic AO sample count adjustment for FPS rate control 04278 #if defined(VMDOPTIX_PROGRESSIVEAPI) 04279 #if 1 04280 int autosamplecount=0; // leave disabled for now 04281 #else 04282 int autosamplecount=1; // works partially in current revs of progressive API 04283 #endif 04284 #else 04285 int autosamplecount=1; 04286 #endif 04287 04288 // flag to enable transformation of lights and gradient sky sphere, 04289 // so that they track camera orientation as they do in the VMD OpenGL display 04290 int xformlights=1, xformgradientsphere=1; 04291 04292 // 04293 // allocate or reconfigure the framebuffer, accumulation buffer, 04294 // and output streams required for progressive rendering, either 04295 // using the new progressive APIs, or using our own code. 04296 // 04297 // Unless overridden by environment variables, we use the incoming 04298 // window size parameters from VMD to initialize the RT image dimensions. 04299 // If image size is overridden, often when using HMDs, the incoming 04300 // dims are window dims are used to size the GL window, but the image size 04301 // is set independently. 04302 int wsx=width, wsy=height; 04303 const char *imageszstr = getenv("VMDOPTIXIMAGESIZE"); 04304 if (imageszstr) { 04305 if (sscanf(imageszstr, "%d %d", &width, &height) != 2) { 04306 width=wsx; 04307 height=wsy; 04308 } 04309 } 04310 04311 framebuffer_config(width, height, 1); 04312 04313 // prepare the majority of OptiX rendering state before we go into 04314 // the interactive rendering loop 04315 update_rendering_state(1); 04316 render_compile_and_validate(); 04317 04318 // make a copy of state we're going to interactively manipulate, 04319 // so that we can recover to the original state on-demand 04320 int samples_per_pass = 1; 04321 int force_ao_1 = 0; // whether or not to force AO count per pass to 1 04322 int cur_aa_samples = aa_samples; 04323 int cur_ao_samples = ao_samples; 04324 float cam_zoom_orig = cam_zoom; 04325 float scene_gradient_orig[3] = {0.0f, 1.0f, 0.0f}; 04326 vec_copy(scene_gradient_orig, scene_gradient); 04327 04328 float cam_pos_orig[3] = {0.0f, 0.0f, 2.0f}; 04329 float cam_U_orig[3] = {1.0f, 0.0f, 0.0f}; 04330 float cam_V_orig[3] = {0.0f, 1.0f, 0.0f}; 04331 float cam_W_orig[3] = {0.0f, 0.0f, -1.0f}; 04332 float cam_pos[3], cam_U[3], cam_V[3], cam_W[3]; 04333 float hmd_U[3], hmd_V[3], hmd_W[3]; 04334 04335 vec_copy(cam_pos, cam_pos_orig); 04336 vec_copy(cam_U, cam_U_orig); 04337 vec_copy(cam_V, cam_V_orig); 04338 vec_copy(cam_W, cam_W_orig); 04339 04340 // copy light directions 04341 DirectionalLight *cur_dlights = (DirectionalLight *) calloc(1, directional_lights.num() * sizeof(DirectionalLight)); 04342 for (i=0; i<directional_lights.num(); i++) { 04343 vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir); 04344 vec_normalize((float*)&cur_dlights[i].dir); 04345 } 04346 04347 // check for stereo-capable display 04348 //int havestereo=0, havestencil=0; 04349 int stereoon=0, stereoon_old=0; 04350 // glwin_get_wininfo(win, &havestereo, &havestencil); 04351 04352 // Override AA/AO sample counts since we're doing progressive rendering. 04353 // Choosing an initial AO sample count of 1 will give us the peak progressive 04354 // display update rate, but we end up wasting time on re-tracing many 04355 // primary rays. The automatic FPS optimization scheme below will update 04356 // the number of samples per rendering pass and assign the best values for 04357 // AA/AO samples accordingly. 04358 cur_aa_samples = samples_per_pass; 04359 if (cur_ao_samples > 0) { 04360 cur_aa_samples = 1; 04361 cur_ao_samples = samples_per_pass; 04362 } 04363 04364 const char *statestr = "|/-\\."; 04365 int done=0, winredraw=1; 04366 int state=0; 04367 //float cur_cam_zoom = cam_zoom_orig; 04368 04369 double fpsexpave=0.0; 04370 double accumbufstarttime=wkf_timer_timenow(ort_timer); 04371 double oldtime = wkf_timer_timenow(ort_timer); 04372 // Note: we immediately terminate the rendering loop if 04373 // the videostream server loses its client connection(s) 04374 while (!done && 04375 app->uivs && app->uivs->srv_connected()) { 04376 04377 #if 1 04378 if (app->uivs && app->uivs->srv_connected()) { 04379 if (app->uivs->srv_check_ui_event()) { 04380 int eventtype; 04381 app->uivs->srv_get_last_event_type(eventtype); 04382 switch (eventtype) { 04383 case VideoStream::VS_EV_ROTATE_BY: 04384 { int axis; 04385 float angle; 04386 app->uivs->srv_get_last_rotate_by(angle, axis); 04387 Matrix4 rm; 04388 04389 switch (axis) { 04390 case 'x': 04391 rm.rotate_axis(cam_U, -angle * VMD_PI/180.0f); 04392 break; 04393 04394 case 'y': 04395 rm.rotate_axis(cam_V, -angle * VMD_PI/180.0f); 04396 break; 04397 04398 case 'z': 04399 rm.rotate_axis(cam_W, -angle * VMD_PI/180.0f); 04400 break; 04401 } 04402 rm.multpoint3d(cam_pos, cam_pos); 04403 rm.multnorm3d(cam_U, cam_U); 04404 rm.multnorm3d(cam_V, cam_V); 04405 rm.multnorm3d(cam_W, cam_W); 04406 04407 if (xformgradientsphere) { 04408 rm.multnorm3d(scene_gradient, scene_gradient); 04409 } 04410 04411 if (xformlights) { 04412 // update light directions (comparatively costly) 04413 for (i=0; i<directional_lights.num(); i++) { 04414 rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir); 04415 } 04416 } 04417 winredraw = 1; 04418 } 04419 break; 04420 04421 case VideoStream::VS_EV_TRANSLATE_BY: 04422 { 04423 float dU[3], dV[3], dW[3]; 04424 float tx, ty, tz; 04425 app->uivs->srv_get_last_translate_by(tx, ty, tz); 04426 vec_scale(dU, -tx, cam_U); 04427 vec_scale(dV, -ty, cam_V); 04428 vec_scale(dW, -tz, cam_W); 04429 vec_add(cam_pos, cam_pos, dU); 04430 vec_add(cam_pos, cam_pos, dV); 04431 vec_add(cam_pos, cam_pos, dW); 04432 winredraw = 1; 04433 } 04434 break; 04435 04436 case VideoStream::VS_EV_SCALE_BY: 04437 { float zoominc; 04438 app->uivs->srv_get_last_scale_by(zoominc); 04439 cam_zoom *= 1.0f / zoominc; 04440 winredraw = 1; 04441 } 04442 break; 04443 04444 #if 0 04445 } else if (mm == RTMM_DOF) { 04446 cam_dof_fnumber += txdx * 20.0f; 04447 if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f; 04448 cam_dof_focal_dist += -txdy; 04449 if (cam_dof_focal_dist < 0.01f) cam_dof_focal_dist = 0.01f; 04450 winredraw = 1; 04451 } 04452 } 04453 #endif 04454 case VideoStream::VS_EV_KEYBOARD: 04455 { int keydev, keyval, shift_state; 04456 app->uivs->srv_get_last_keyboard(keydev, keyval, shift_state); 04457 switch (keydev) { 04458 case DisplayDevice::WIN_KBD: 04459 { 04460 switch (keyval) { 04461 // update sample counts 04462 case '1': autosamplecount=0; samples_per_pass=1; winredraw=1; break; 04463 case '2': autosamplecount=0; samples_per_pass=2; winredraw=1; break; 04464 case '3': autosamplecount=0; samples_per_pass=3; winredraw=1; break; 04465 case '4': autosamplecount=0; samples_per_pass=4; winredraw=1; break; 04466 case '5': autosamplecount=0; samples_per_pass=5; winredraw=1; break; 04467 case '6': autosamplecount=0; samples_per_pass=6; winredraw=1; break; 04468 case '7': autosamplecount=0; samples_per_pass=7; winredraw=1; break; 04469 case '8': autosamplecount=0; samples_per_pass=8; winredraw=1; break; 04470 case '9': autosamplecount=0; samples_per_pass=9; winredraw=1; break; 04471 case '0': autosamplecount=0; samples_per_pass=10; winredraw=1; break; 04472 04473 case '=': /* recover back to initial state */ 04474 vec_copy(scene_gradient, scene_gradient_orig); 04475 cam_zoom = cam_zoom_orig; 04476 vec_copy(cam_pos, cam_pos_orig); 04477 vec_copy(cam_U, cam_U_orig); 04478 vec_copy(cam_V, cam_V_orig); 04479 vec_copy(cam_W, cam_W_orig); 04480 04481 // restore original light directions 04482 for (i=0; i<directional_lights.num(); i++) { 04483 vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir); 04484 vec_normalize((float*)&cur_dlights[i].dir); 04485 } 04486 winredraw = 1; 04487 break; 04488 04489 case 'q': /* 'q' key */ 04490 case 'Q': /* 'Q' key */ 04491 printf("\nOptiXRenderer) Exiting on user input. \n"); 04492 done=1; /* exit from interactive RT window */ 04493 break; 04494 } 04495 } 04496 break; 04497 04498 case DisplayDevice::WIN_KBD_ESCAPE: 04499 printf("\nOptiXRenderer) Exiting on user input. \n"); 04500 done=1; /* exit from interactive RT window */ 04501 break; 04502 04503 case DisplayDevice::WIN_KBD_F1: 04504 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT) 04505 gl_shadows_on=(!gl_shadows_on) ? RT_SHADOWS_ON_REVERSE : RT_SHADOWS_OFF; 04506 #else 04507 gl_shadows_on=(!gl_shadows_on) ? RT_SHADOWS_ON : RT_SHADOWS_OFF; 04508 // gl_shadows_on = (!gl_shadows_on); 04509 #endif 04510 04511 printf("\n"); 04512 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT) 04513 printf("OptiXRenderer) Shadows %s\n", 04514 (gl_shadows_on) ? "enabled (reversal opt.)" : "disabled"); 04515 #else 04516 printf("OptiXRenderer) Shadows %s\n", 04517 (gl_shadows_on) ? "enabled" : "disabled"); 04518 #endif 04519 winredraw = 1; 04520 break; 04521 04522 case DisplayDevice::WIN_KBD_F2: 04523 gl_ao_on = (!gl_ao_on); 04524 printf("\n"); 04525 printf("OptiXRenderer) Ambient occlusion %s\n", 04526 (gl_ao_on) ? "enabled" : "disabled"); 04527 winredraw = 1; 04528 break; 04529 04530 case DisplayDevice::WIN_KBD_F3: 04531 gl_dof_on = (!gl_dof_on); 04532 printf("\n"); 04533 printf("OptiXRenderer) Depth-of-field %s\n", 04534 (gl_dof_on) ? "enabled" : "disabled"); 04535 winredraw = 1; 04536 break; 04537 } 04538 } 04539 break; 04540 04541 case VideoStream::VS_EV_NONE: 04542 default: 04543 // should never happen... 04544 break; 04545 } 04546 } 04547 } 04548 #endif 04549 04550 // if there is no HMD, we use the camera orientation directly 04551 vec_copy(hmd_U, cam_U); 04552 vec_copy(hmd_V, cam_V); 04553 vec_copy(hmd_W, cam_W); 04554 04555 // 04556 // handle window resizing, stereoscopic mode changes, 04557 // destroy and recreate affected OptiX buffers 04558 // 04559 int resize_buffers=0; 04560 04561 { 04562 // only process image/window resizing when not drawing spheremaps 04563 if (wsx != width) { 04564 width = wsx; 04565 resize_buffers=1; 04566 } 04567 04568 if (wsy != height || (stereoon != stereoon_old)) { 04569 if (stereoon) { 04570 if (height != wsy * 2) { 04571 height = wsy * 2; 04572 resize_buffers=1; 04573 } 04574 } else { 04575 height = wsy; 04576 resize_buffers=1; 04577 } 04578 } 04579 } 04580 04581 04582 // XXX Prior to OptiX 3.8, we had to manually stop progressive 04583 // mode before changing any OptiX state. 04584 #if defined(VMDOPTIX_PROGRESSIVEAPI) && OPTIX_VERSION < 3080 04585 // 04586 // Check for all conditions that would require modifying OptiX state 04587 // and tell the VCA to stop progressive rendering before we modify 04588 // the rendering state, 04589 // 04590 if (done || winredraw || resize_buffers || 04591 (stereoon != stereoon_old) || (gl_dof_on != gl_dof_on_old)) { 04592 // need to issue stop command before editing optix objects 04593 if (vcarunning) { 04594 rtContextStopProgressive(ctx); 04595 vcarunning=0; 04596 } 04597 } 04598 #endif 04599 04600 // check if stereo mode or DoF mode changed, both cases 04601 // require changing the active color accumulation ray gen program 04602 if ((stereoon != stereoon_old) || (gl_dof_on != gl_dof_on_old)) { 04603 // when stereo mode changes, we have to regenerate the 04604 // the RNG, accumulation buffer, and framebuffer 04605 if (stereoon != stereoon_old) { 04606 resize_buffers=1; 04607 } 04608 04609 // update stereo and DoF state 04610 stereoon_old = stereoon; 04611 gl_dof_on_old = gl_dof_on; 04612 04613 // set the active color accumulation ray gen program based on the 04614 // camera/projection mode, stereoscopic display mode, 04615 // and depth-of-field state 04616 set_accum_raygen_pgm(camera_projection, stereoon, gl_dof_on); 04617 } 04618 04619 if (resize_buffers) { 04620 framebuffer_resize(width, height); 04621 04622 // when movie recording is enabled, print the window size as a guide 04623 // since the user might want to precisely control the size or 04624 // aspect ratio for a particular movie format, e.g. 1080p, 4:3, 16:9 04625 if (movie_recording_enabled) { 04626 printf("\rOptiXRenderer) Window resize: %d x %d \n", width, height); 04627 } 04628 04629 winredraw=1; 04630 } 04631 04632 int frame_ready = 1; // Default to true for the non-VCA case 04633 unsigned int subframe_count = 1; 04634 if (!done) { 04635 // 04636 // If the user interacted with the window in a meaningful way, we 04637 // need to update the OptiX rendering state, recompile and re-validate 04638 // the context, and then re-render... 04639 // 04640 if (winredraw) { 04641 // update camera parameters 04642 RTERR( rtVariableSet1f( cam_zoom_v, cam_zoom) ); 04643 RTERR( rtVariableSet3fv( cam_pos_v, cam_pos) ); 04644 RTERR( rtVariableSet3fv( cam_U_v, hmd_U) ); 04645 RTERR( rtVariableSet3fv( cam_V_v, hmd_V) ); 04646 RTERR( rtVariableSet3fv( cam_W_v, hmd_W) ); 04647 RTERR( rtVariableSet3fv(scene_gradient_v, scene_gradient) ); 04648 04649 // update shadow state 04650 RTERR( rtVariableSet1i(shadows_enabled_v, gl_shadows_on) ); 04651 04652 // update depth cueing state 04653 RTERR( rtVariableSet1i(fog_mode_v, 04654 (int) (gl_fog_on) ? fog_mode : RT_FOG_NONE) ); 04655 04656 // update clipping sphere state 04657 RTERR( rtVariableSet1i(clipview_mode_v, 04658 (int) (gl_clip_on) ? clipview_mode : RT_CLIP_NONE) ); 04659 04660 // update headlight state 04661 RTERR( rtVariableSet1i(headlight_mode_v, 04662 (int) (gl_headlight_on) ? RT_HEADLIGHT_ON : RT_HEADLIGHT_OFF) ); 04663 04664 // update/recompute DoF values 04665 RTERR( rtVariableSet1f(cam_dof_focal_dist_v, cam_dof_focal_dist) ); 04666 RTERR( rtVariableSet1f(cam_dof_aperture_rad_v, cam_dof_focal_dist / (2.0f * cam_zoom * cam_dof_fnumber)) ); 04667 04668 // 04669 // Update light directions in the OptiX light buffer or user object. 04670 // Only update when xformlights is set, otherwise we take a 04671 // speed hit when using a remote VCA cluster for rendering. 04672 // 04673 // We only transform directional lights, since our positional lights 04674 // are normally affixed to the model coordinate system rather than 04675 // the camera. 04676 // 04677 if (xformlights) { 04678 #if defined(VMDOPTIX_LIGHTUSEROBJS) 04679 DirectionalLightList dlights; 04680 memset(&dlights, 0, sizeof(DirectionalLightList) ); 04681 dlights.num_lights = directional_lights.num(); 04682 int dlcount = directional_lights.num(); 04683 dlcount = (dlcount > DISP_LIGHTS) ? DISP_LIGHTS : dlcount; 04684 for (i=0; i<dlcount; i++) { 04685 //vec_copy( (float*)( &lights.dirs[i] ), cur_dlights[i].dir ); 04686 dlights.dirs[i] = cur_dlights[i].dir; 04687 } 04688 RTERR( rtVariableSetUserData(dir_light_list_v, sizeof(DirectionalLightList), &dlights) ); 04689 #else 04690 DirectionalLight *dlbuf; 04691 RTERR( rtBufferMap(dir_lightbuffer, (void **) &dlbuf) ); 04692 for (i=0; i<directional_lights.num(); i++) { 04693 vec_copy((float*)&dlbuf[i].dir, (float*)&cur_dlights[i].dir); 04694 } 04695 RTERR( rtBufferUnmap(dir_lightbuffer) ); 04696 #endif 04697 } 04698 04699 // reset accumulation buffer 04700 totalsamplecount=0; 04701 04702 // 04703 // Sample count updates and OptiX state must always remain in 04704 // sync, so if we only update sample count state during redraw events, 04705 // that's the only time we should recompute the sample counts, since 04706 // they also affect normalization factors for the accumulation buffer 04707 // in the non-VCA case. 04708 // 04709 04710 // Update sample counts to achieve target interactivity 04711 if (autosamplecount) { 04712 if (fpsexpave > 37) 04713 samples_per_pass++; 04714 else if (fpsexpave < 30) 04715 samples_per_pass--; 04716 04717 // clamp sample counts to a "safe" range 04718 if (samples_per_pass > 14) 04719 samples_per_pass=14; 04720 if (samples_per_pass < 1) 04721 samples_per_pass=1; 04722 } 04723 04724 // split samples per pass either among AA and AO, depending on 04725 // whether DoF and AO are enabled or not. 04726 if (force_ao_1) { 04727 cur_aa_samples = samples_per_pass; 04728 cur_ao_samples = 1; 04729 } else if (gl_shadows_on && gl_ao_on) { 04730 if (gl_dof_on) { 04731 if (samples_per_pass < 4) { 04732 cur_aa_samples=samples_per_pass; 04733 cur_ao_samples=1; 04734 } else { 04735 int s = (int) sqrtf(samples_per_pass); 04736 cur_aa_samples=s; 04737 cur_ao_samples=s; 04738 } 04739 } else { 04740 cur_aa_samples=1; 04741 cur_ao_samples=samples_per_pass; 04742 } 04743 } else { 04744 cur_aa_samples=samples_per_pass; 04745 cur_ao_samples=0; 04746 } 04747 04748 // update the current AA/AO sample counts since they may be changing if 04749 // FPS autotuning is enabled... 04750 RTERR( rtVariableSet1i(aa_samples_v, cur_aa_samples) ); 04751 04752 // observe latest AO enable/disable flag, and sample count 04753 if (gl_shadows_on && gl_ao_on) { 04754 RTERR( rtVariableSet1i(ao_samples_v, cur_ao_samples) ); 04755 } else { 04756 cur_ao_samples = 0; 04757 RTERR( rtVariableSet1i(ao_samples_v, 0) ); 04758 } 04759 04760 #ifdef VMDOPTIX_PROGRESSIVEAPI 04761 RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(cur_aa_samples)) ); 04762 #endif 04763 04764 // updated cached copy of previous window dimensions so we can 04765 // trigger updates on HMD spheremaps and FBOs as necessary 04766 // owsx = wsx; 04767 // owsy = wsy; 04768 } 04769 04770 04771 // 04772 // The non-VCA code path must handle the accumulation buffer 04773 // for itself, correctly rescaling the accumulated samples when 04774 // drawing to the output framebuffer. 04775 // 04776 // The VCA code path takes care of normalization for itself. 04777 // 04778 #ifndef VMDOPTIX_PROGRESSIVEAPI 04779 // The accumulation buffer normalization factor must be updated 04780 // to reflect the total accumulation count before the accumulation 04781 // buffer is drawn to the output framebuffer 04782 RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(cur_aa_samples + accum_count)) ); 04783 04784 // The accumulation buffer subframe index must be updated to ensure that 04785 // the RNGs for AA and AO get correctly re-seeded 04786 RTERR( rtVariableSet1ui(accum_count_v, accum_count) ); 04787 04788 // Force context compilation/validation 04789 // If no state has changed, there's no need to recompile/validate. 04790 // This call can be omitted since OptiX will do this automatically 04791 // at the next rtContextLaunchXXX() call. 04792 // render_compile_and_validate(); 04793 #endif 04794 04795 04796 // 04797 // run the renderer 04798 // 04799 frame_ready = 1; // Default to true for the non-VCA case 04800 subframe_count = 1; 04801 if (lasterror == RT_SUCCESS) { 04802 if (winredraw) { 04803 #if defined(ORT_RAYSTATS) 04804 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_RAYSTATS, width, height) ); 04805 accumbufstarttime=wkf_timer_timenow(ort_timer); 04806 #endif 04807 #ifdef VMDOPTIX_PROGRESSIVEAPI 04808 // start the VCA doing progressive rendering... 04809 RTERR( rtContextLaunchProgressive2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height, 0) ); 04810 #else 04811 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, width, height) ); 04812 #endif 04813 winredraw=0; 04814 } 04815 04816 #ifdef VMDOPTIX_PROGRESSIVEAPI 04817 // Wait for the next frame to arrive 04818 RTERR( rtBufferGetProgressiveUpdateReady(framebuffer, &frame_ready, &subframe_count, 0) ); 04819 if (frame_ready) 04820 totalsamplecount = subframe_count * samples_per_pass; 04821 #else 04822 // iterate, adding to the accumulation buffer... 04823 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height) ); 04824 subframe_count++; // increment subframe index 04825 totalsamplecount += samples_per_pass; 04826 accum_count += cur_aa_samples; 04827 04828 // copy the accumulation buffer image data to the framebuffer and 04829 // perform type conversion and normaliztion on the image data... 04830 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_COPY_FINISH, width, height) ); 04831 #endif 04832 04833 if (lasterror == RT_SUCCESS) { 04834 if (frame_ready) { 04835 // display output image 04836 const unsigned char * img; 04837 rtBufferMap(framebuffer, (void **) &img); 04838 04839 #if 1 04840 // push latest frame into the video streaming pipeline 04841 // and pump the event handling mechanism afterwards 04842 if (app->uivs && app->uivs->srv_connected()) { 04843 app->uivs->video_frame_pending(img, width, height); 04844 app->uivs->check_event(); 04845 } 04846 #endif 04847 04848 rtBufferUnmap(framebuffer); 04849 04850 // if live movie recording is on, we save every displayed frame 04851 // to a sequence sequence of image files, with each file numbered 04852 // by its frame index, which is computed by the multiplying image 04853 // presentation time by the image sequence fixed-rate-FPS value. 04854 if (movie_recording_enabled && movie_recording_on) { 04855 char moviefilename[2048]; 04856 04857 // compute frame number from wall clock time and the 04858 // current fixed-rate movie playback frame rate 04859 double now = wkf_timer_timenow(ort_timer); 04860 double frametime = now - movie_recording_start_time; 04861 int fidx = frametime * movie_recording_fps; 04862 04863 // always force the first recorded frame to be 0 04864 if (movie_framecount==0) 04865 fidx=0; 04866 movie_framecount++; 04867 04868 #if defined(__linux) 04869 // generate symlinks for frame indices between the last written 04870 // frame and the current one so that video encoders such as 04871 // ffmpeg and mencoder can be fed the contiguous frame sequence 04872 // at a fixed frame rate, as they require 04873 sprintf(moviefilename, movie_recording_filebase, 04874 movie_lastframeindex); 04875 int symidx; 04876 for (symidx=movie_lastframeindex; symidx<fidx; symidx++) { 04877 char symlinkfilename[2048]; 04878 sprintf(symlinkfilename, movie_recording_filebase, symidx); 04879 if (symlink(moviefilename, symlinkfilename) < 0) 04880 perror("symlink: "); 04881 } 04882 #endif 04883 04884 // write the new movie frame 04885 sprintf(moviefilename, movie_recording_filebase, fidx); 04886 if (OptiXWriteImage(moviefilename, writealpha, framebuffer, 04887 RT_FORMAT_UNSIGNED_BYTE4, width, height) == -1) { 04888 movie_recording_on = 0; 04889 printf("\n"); 04890 printf("OptiXRenderer) ERROR during writing image during movie recording!\n"); 04891 printf("OptiXRenderer) Movie recording STOPPED\n"); 04892 } 04893 04894 movie_lastframeindex = fidx; // update last frame index written 04895 } 04896 } 04897 } else { 04898 printf("OptiXRenderer) An error occured during rendering. Rendering is aborted.\n"); 04899 done=1; 04900 break; 04901 } 04902 } else { 04903 printf("OptiXRenderer) An error occured in AS generation. Rendering is aborted.\n"); 04904 done=1; 04905 break; 04906 } 04907 } 04908 04909 if (!done && frame_ready) { 04910 double newtime = wkf_timer_timenow(ort_timer); 04911 double frametime = (newtime-oldtime) + 0.00001f; 04912 oldtime=newtime; 04913 04914 // compute exponential moving average for exp(-1/10) 04915 double framefps = 1.0f/frametime; 04916 fpsexpave = (fpsexpave * 0.90) + (framefps * 0.10); 04917 04918 printf("OptiXRenderer) %c AA:%2d AO:%2d, %4d tot RT FPS: %.1f %.4f s/frame sf: %d \r", 04919 statestr[state], cur_aa_samples, cur_ao_samples, 04920 totalsamplecount, fpsexpave, frametime, subframe_count); 04921 04922 fflush(stdout); 04923 state = (state+1) & 3; 04924 } 04925 04926 } // end of per-cycle event processing 04927 04928 printf("\n"); 04929 04930 // write the output image upon exit... 04931 if (lasterror == RT_SUCCESS) { 04932 #if defined(ORT_RAYSTATS) 04933 double frametime = wkf_timer_timenow(ort_timer) - accumbufstarttime; 04934 OptiXPrintRayStats(raystats1_buffer, raystats2_buffer, frametime); 04935 #endif 04936 04937 wkf_timer_start(ort_timer); 04938 OptiXWriteImage(filename, writealpha, framebuffer); // write output image 04939 wkf_timer_stop(ort_timer); 04940 04941 if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) { 04942 printf("OptiXRenderer) image file I/O time: %f secs\n", wkf_timer_time(ort_timer)); 04943 } 04944 } 04945 } 04946 04947 04948 void OptiXRenderer::render_to_file(const char *filename, int writealpha) { 04949 if (!context_created) 04950 return; 04951 04952 // Unless overridden by environment variables, we use the incoming 04953 // window size parameters from VMD to initialize the RT image dimensions. 04954 int wsx=width, wsy=height; 04955 const char *imageszstr = getenv("VMDOPTIXIMAGESIZE"); 04956 if (imageszstr) { 04957 if (sscanf(imageszstr, "%d %d", &width, &height) != 2) { 04958 width=wsx; 04959 height=wsy; 04960 } 04961 } 04962 04963 // config/allocate framebuffer and accumulation buffer 04964 framebuffer_config(width, height, 0); 04965 04966 update_rendering_state(0); 04967 render_compile_and_validate(); 04968 double starttime = wkf_timer_timenow(ort_timer); 04969 04970 // 04971 // run the renderer 04972 // 04973 if (lasterror == RT_SUCCESS) { 04974 #if defined(ORT_RAYSTATS) 04975 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_RAYSTATS, width, height) ); 04976 #endif 04977 // clear the accumulation buffer 04978 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, width, height) ); 04979 04980 // Render to the accumulation buffer for the required number of passes 04981 if (getenv("VMDOPTIXNORENDER") == NULL) { 04982 int accum_sample; 04983 for (accum_sample=0; accum_sample<ext_aa_loops; accum_sample++) { 04984 // The accumulation subframe count must be updated to ensure that 04985 // the RNGs for AA and AO get correctly re-seeded 04986 RTERR( rtVariableSet1ui(accum_count_v, accum_sample) ); 04987 04988 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height) ); 04989 } 04990 } 04991 04992 // copy the accumulation buffer image data to the framebuffer and perform 04993 // type conversion and normaliztion on the image data... 04994 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_COPY_FINISH, width, height) ); 04995 double rtendtime = wkf_timer_timenow(ort_timer); 04996 time_ray_tracing = rtendtime - starttime; 04997 04998 if (lasterror == RT_SUCCESS) { 04999 // write output image to a file unless we are benchmarking 05000 if (getenv("VMDOPTIXNOSAVE") == NULL) { 05001 OptiXWriteImage(filename, writealpha, framebuffer); 05002 } 05003 #if defined(ORT_RAYSTATS) 05004 OptiXPrintRayStats(raystats1_buffer, raystats2_buffer, time_ray_tracing); 05005 #endif 05006 time_image_io = wkf_timer_timenow(ort_timer) - rtendtime; 05007 } else { 05008 printf("OptiXRenderer) Error during rendering. Rendering aborted.\n"); 05009 } 05010 05011 if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) { 05012 printf("OptiXRenderer) ctx setup %.2f valid %.2f AS %.2f RT %.2f io %.2f\n", time_ctx_setup, time_ctx_validate, time_ctx_AS_build, time_ray_tracing, time_image_io); 05013 } 05014 } else { 05015 printf("OptiXRenderer) Error during AS generation. Rendering aborted.\n"); 05016 } 05017 } 05018 05019 05020 #if defined(VMDOPTIXRTRT) 05021 05022 void OptiXRenderer::add_material_cmdlist(const VMDDisplayList *cmdList) { 05023 add_material(cmdList->materialtag, 05024 cmdList->ambient, 05025 cmdList->diffuse, 05026 cmdList->specular, 05027 cmdList->shininess, 05028 cmdList->mirror, 05029 cmdList->opacity, 05030 cmdList->outline, 05031 cmdList->outlinewidth, 05032 cmdList->transmode); 05033 } 05034 05035 05036 void OptiXRenderer::scene_aggregate_cmdlist(const VMDDisplayList *cmdList, 05037 const float *colorData) { 05038 // printf("OptiXRenderer) --> RTX RTRT Passthrough\n"); 05039 05040 char *cmdptr = NULL; // ptr to current display command data 05041 int tok; // what display command was encountered 05042 05043 // early exit if any of these conditions are true. 05044 if (!cmdList) 05045 return; 05046 05047 Stack<Matrix4> transMat(10); 05048 Matrix4 m; 05049 transMat.push(m); // push on the identity matrix 05050 (transMat.top()).multmatrix(cmdList->mat); // save transformation matrix 05051 05052 // set up text matrices 05053 // Matrix4 textMat(ogl_textMat); 05054 // textMat.multmatrix(cmdList->mat); 05055 05056 #if 0 05057 // enable/disable clipping planes 05058 for (int cp=0; cp<VMD_MAX_CLIP_PLANE; cp++) { 05059 // don't cache 'on' state since the parameters will likely differ, 05060 // just setup the clip plane from the new state 05061 if (cmdList->clipplanes[cp].mode) { 05062 } 05063 } 05064 #endif 05065 05066 #if 0 05067 // Compute periodic image transformation matrices 05068 ResizeArray<Matrix4> pbcImages; 05069 find_pbc_images(cmdList, pbcImages); 05070 int npbcimages = pbcImages.num(); 05071 05072 // Retreive instance image transformation matrices 05073 ResizeArray<Matrix4> instanceImages; 05074 find_instance_images(cmdList, instanceImages); 05075 int ninstances = instanceImages.num(); 05076 05077 for (int pbcimage = 0; pbcimage < npbcimages; pbcimage++) { 05078 transMat.dup(); 05079 (transMat.top()).multmatrix(pbcImages[pbcimage]); 05080 for (int instanceimage = 0; instanceimage < ninstances; instanceimage++) { 05081 transMat.dup(); 05082 (transMat.top()).multmatrix(instanceImages[instanceimage]); 05083 } 05084 } 05085 #endif 05086 05087 #if 0 05088 // find previously cached display list for this object 05089 if (ogl_cacheenabled && !ogl_cacheskip) { 05090 ogl_cachedid = displaylistcache.markUsed(cmdList->serial); 05091 05092 // add to the cache and regenerate if we didn't find it 05093 if (ogl_cachedid == GLCACHE_FAIL) { 05094 ogl_cachedid = glGenLists(1); 05095 displaylistcache.encache(cmdList->serial, ogl_cachedid); 05096 05097 // create the display list, and execute it. 05098 glNewList(ogl_cachedid, GL_COMPILE_AND_EXECUTE); 05099 ogl_cachecreated = 1; // a new display list was created 05100 } 05101 } 05102 05103 // XXX Draw OpenGL geometry only when caching is disabled or when 05104 // we have new geometry to cache 05105 if ((!ogl_cacheenabled) || ogl_cacheskip || (ogl_cacheenabled && ogl_cachecreated)) { 05106 #endif 05107 05108 05109 // scan through the list, getting each command and executing it, until 05110 // the end of commands token is found 05111 int colorIndex = 0; 05112 VMDDisplayList::VMDLinkIter cmditer; 05113 cmdList->first(&cmditer); 05114 while((tok = cmdList->next(&cmditer, cmdptr)) != DLASTCOMMAND) { 05115 switch (tok) { 05116 case DCOLORINDEX: 05117 colorIndex = (((DispCmdColorIndex *)cmdptr)->color); 05118 break; 05119 05120 case DCYLINDER: // plot a cylinder 05121 { 05122 add_material_cmdlist(cmdList); 05123 05124 // XXX these should be getting aggregated in a batch 05125 05126 float points[6], radii[1], colors[3]; 05127 memcpy(points, (float *)cmdptr, 3L*sizeof(float)); 05128 memcpy(&points[3], ((float *)cmdptr) + 3, 3L*sizeof(float)); 05129 radii[0] = ((float *)cmdptr)[6]; 05130 int filled = ((int) ((float *) cmdptr)[8]); 05131 memcpy(colors, &colorData[colorIndex*3L], 3L*sizeof(float)); 05132 05133 float *mat = &transMat.top().mat[0]; 05134 float scaleFactor = 05135 (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) + 05136 sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) + 05137 sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f; 05138 05139 // Submit all geometry in one buffer 05140 cylinder_array_color(&transMat.top(), scaleFactor, 05141 1, points, radii, colors, 05142 cmdList->materialtag); 05143 05144 // XXX no filled cylinder caps yet 05145 05146 } 05147 break; 05148 05149 case DCYLINDERARRAY: 05150 { 05151 add_material_cmdlist(cmdList); 05152 05153 DispCmdCylinderArray *ca = (DispCmdCylinderArray *)cmdptr; 05154 float *points, *radii, *colors; 05155 ca->getpointers(points, radii, colors); 05156 05157 float *mat = &transMat.top().mat[0]; 05158 float scaleFactor = 05159 (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) + 05160 sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) + 05161 sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f; 05162 05163 // Submit all geometry in one buffer 05164 cylinder_array_color(&transMat.top(), scaleFactor, 05165 ca->numcylinders, points, radii, colors, 05166 cmdList->materialtag); 05167 } 05168 break; 05169 05170 case DSPHERE: 05171 { 05172 add_material_cmdlist(cmdList); 05173 05174 // XXX these should be getting aggregated in a batch 05175 05176 float centers[3], radii[1], color[3]; 05177 memcpy(centers, (float *)cmdptr, 3L*sizeof(float)); 05178 radii[0] = ((float *)cmdptr)[3]; 05179 05180 float *mat = &transMat.top().mat[0]; 05181 float scaleFactor = 05182 (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) + 05183 sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) + 05184 sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f; 05185 05186 // Submit all geometry in one buffer 05187 sphere_array_color(transMat.top(), scaleFactor, 05188 1, centers, radii, &colorData[colorIndex*3L], 05189 cmdList->materialtag); 05190 } 05191 break; 05192 05193 case DSPHEREARRAY: 05194 { 05195 add_material_cmdlist(cmdList); 05196 05197 DispCmdSphereArray *sa = (DispCmdSphereArray *)cmdptr; 05198 float *centers, *radii, *colors; 05199 sa->getpointers(centers, radii, colors); 05200 05201 float *mat = &transMat.top().mat[0]; 05202 float scaleFactor = 05203 (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) + 05204 sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) + 05205 sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f; 05206 05207 // Submit all geometry in one buffer 05208 sphere_array_color(transMat.top(), scaleFactor, 05209 sa->numspheres, centers, radii, colors, 05210 cmdList->materialtag); 05211 } 05212 break; 05213 05214 case DTRIMESH_C3F_N3F_V3F: // draw a triangle mesh 05215 { 05216 add_material_cmdlist(cmdList); 05217 05218 DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr; 05219 float *c=NULL, *n=NULL, *v=NULL; 05220 05221 if (cmd->pervertexcolors) { 05222 cmd->getpointers(c, n, v); 05223 #if 1 05224 printf("Dropped trimesh_c3f_n3f_v3f()\n"); 05225 #else 05226 // XXX unimplemented 05227 trimesh_c3f_n3f_v3f(transMat.top(), c, n, v, cmd->numfacets, 05228 cmdList->materialtag); 05229 #endif 05230 } else if (cmd->pervertexnormals) { 05231 cmd->getpointers(n, v); 05232 trimesh_n3f_v3f(transMat.top(), &colorData[colorIndex * 3], 05233 n, v, cmd->numfacets, cmdList->materialtag); 05234 } else { 05235 cmd->getpointers(n, v); 05236 trimesh_v3f(transMat.top(), &colorData[colorIndex * 3], 05237 v, cmd->numfacets, cmdList->materialtag); 05238 } 05239 } 05240 break; 05241 05242 case DTRIMESH_C4F_N3F_V3F: 05243 { 05244 add_material_cmdlist(cmdList); 05245 05246 // draw a triangle mesh 05247 DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr; 05248 int ind = cmd->numfacets * 3; 05249 float *cnv; 05250 int *f; 05251 cmd->getpointers(cnv, f); 05252 trimesh_c4n3v3(transMat.top(), cmd->numverts, cnv, cmd->numfacets, f, 05253 cmdList->materialtag); 05254 } 05255 break; 05256 05257 case DTRIMESH_C4U_N3B_V3F: // draw a triangle mesh 05258 { 05259 add_material_cmdlist(cmdList); 05260 05261 DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr; 05262 unsigned char *c=NULL; 05263 signed char *n=NULL; 05264 float *v=NULL; 05265 05266 if (cmd->pervertexcolors) { 05267 cmd->getpointers(c, n, v); 05268 trimesh_c4u_n3b_v3f(transMat.top(), c, n, v, cmd->numfacets, 05269 cmdList->materialtag); 05270 } else { 05271 cmd->getpointers(n, v); 05272 trimesh_n3b_v3f(transMat.top(), &colorData[colorIndex * 3], 05273 n, v, cmd->numfacets, cmdList->materialtag); 05274 } 05275 } 05276 break; 05277 05278 case DTRISTRIP: // draw a triangle strip 05279 { 05280 add_material_cmdlist(cmdList); 05281 05282 DispCmdTriStrips *cmd = (DispCmdTriStrips *) cmdptr; 05283 float *cnv=NULL; 05284 int *f=NULL; 05285 int *vertsperstrip; 05286 cmd->getpointers(cnv, f, vertsperstrip); 05287 tristrip(transMat.top(), cmd->numverts, cnv, cmd->numstrips, 05288 vertsperstrip, f, cmdList->materialtag); 05289 } 05290 break; 05291 05292 05293 #if 0 05294 default: 05295 // msgErr << "OpenGLRenderer: Unknown drawing token " << tok 05296 // << " encountered ... Skipping this command." << sendmsg; 05297 break; 05298 #endif 05299 } 05300 } 05301 } 05302 05303 05305 void OptiXRenderer::scene_aggregation_complete() { 05306 update_rendering_state(0); 05307 render_compile_and_validate(); 05308 } 05309 05310 05311 // launch rendering pass(es) 05312 void OptiXRenderer::render_current_scene() { 05313 if (lasterror == RT_SUCCESS) { 05314 // clear the accumulation buffer 05315 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, width, height) ); 05316 05317 // Render to the accumulation buffer for the required number of passes 05318 if (getenv("VMDOPTIXNORENDER") == NULL) { 05319 int accum_sample; 05320 for (accum_sample=0; accum_sample<ext_aa_loops; accum_sample++) { 05321 // The accumulation subframe count must be updated to ensure that 05322 // the RNGs for AA and AO get correctly re-seeded 05323 RTERR( rtVariableSet1ui(accum_count_v, accum_sample) ); 05324 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height) ); 05325 } 05326 } 05327 05328 // copy the accumulation buffer image data to the framebuffer and perform 05329 // type conversion and normaliztion on the image data... 05330 RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_COPY_FINISH, width, height) ); 05331 } 05332 } 05333 05334 #endif 05335 05336 05337 void OptiXRenderer::destroy_context() { 05338 if (!context_created) 05339 return; 05340 05341 #ifdef VMDOPTIX_PROGRESSIVEAPI 05342 // ensure that there's no way we could be leaving the VCA running 05343 rtContextStopProgressive(ctx); 05344 #endif 05345 05346 framebuffer_destroy(); 05347 05348 if ((lasterror = rtContextDestroy(ctx)) != RT_SUCCESS) { 05349 msgErr << "OptiXRenderer) An error occured while destroying the OptiX context" << sendmsg; 05350 } 05351 } 05352 05353 05354 void OptiXRenderer::add_material(int matindex, 05355 float ambient, float diffuse, float specular, 05356 float shininess, float reflectivity, 05357 float opacity, 05358 float outline, float outlinewidth, 05359 int transmode) { 05360 int oldmatcount = materialcache.num(); 05361 if (oldmatcount <= matindex) { 05362 ort_material m; 05363 memset(&m, 0, sizeof(m)); 05364 05365 // XXX do something noticable so we see that we got a bad entry... 05366 m.ambient = 0.5f; 05367 m.diffuse = 0.7f; 05368 m.specular = 0.0f; 05369 m.shininess = 10.0f; 05370 m.reflectivity = 0.0f; 05371 m.opacity = 1.0f; 05372 m.transmode = 0; 05373 05374 materialcache.appendN(m, matindex - oldmatcount + 1); 05375 } 05376 05377 if (materialcache[matindex].isvalid) { 05378 return; 05379 } else { 05380 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) Adding material[%d]\n", matindex); 05381 05382 materialcache[matindex].ambient = ambient; 05383 materialcache[matindex].diffuse = diffuse; 05384 materialcache[matindex].specular = specular; 05385 materialcache[matindex].shininess = shininess; 05386 materialcache[matindex].reflectivity = reflectivity; 05387 materialcache[matindex].opacity = opacity; 05388 materialcache[matindex].outline = outline; 05389 materialcache[matindex].outlinewidth = outlinewidth; 05390 materialcache[matindex].transmode = transmode; 05391 materialcache[matindex].isvalid = 1; 05392 } 05393 } 05394 05395 05396 void OptiXRenderer::init_materials() { 05397 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) init_materials()\n"); 05398 05399 // pre-register all of the hit programs to be shared by all materials 05400 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "closest_hit_radiance_general", &closest_hit_pgm_general) ); 05401 #if defined(ORT_USERTXAPIS) 05402 // OptiX RTX triangle API 05403 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "closest_hit_radiance_general_hwtri", &closest_hit_pgm_general_hwtri) ); 05404 #endif 05405 05406 #if defined(ORT_USE_TEMPLATE_SHADERS) 05407 // build up the list of closest hit programs from all combinations 05408 // of shader parameters 05409 int i; 05410 for (i=0; i<ORTMTABSZ; i++) { 05411 char ch_program_name[256]; 05412 snprintf(ch_program_name, sizeof(ch_program_name), 05413 "closest_hit_radiance_" 05414 "CLIP_VIEW_%s_" 05415 "HEADLIGHT_%s_" 05416 "FOG_%s_" 05417 "SHADOWS_%s_" 05418 "AO_%s_" 05419 "OUTLINE_%s_" 05420 "REFL_%s_" 05421 "TRANS_%s", 05422 #if defined(VMDOPTIX_VCA_TABSZHACK) 05423 onoffstr(1), 05424 onoffstr(1), 05425 #else 05426 onoffstr(i & 128), 05427 onoffstr(i & 64), 05428 #endif 05429 onoffstr(i & 32), 05430 onoffstr(i & 16), 05431 onoffstr(i & 8), 05432 onoffstr(i & 4), 05433 onoffstr(i & 2), 05434 onoffstr(i & 1)); 05435 05436 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, ch_program_name, &closest_hit_pgm_special[i] ) ); 05437 05438 #if defined(ORT_USERTXAPIS) 05439 #error OptiX RTX triangle API not implemented for template shader expansion 05440 #endif 05441 05442 } 05443 #endif 05444 05445 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "any_hit_opaque", &any_hit_pgm_opaque) ); 05446 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "any_hit_transmission", &any_hit_pgm_transmission) ); 05447 RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "any_hit_clip_sphere", &any_hit_pgm_clip_sphere) ); 05448 05449 RTERR( rtMaterialCreate(ctx, &material_general) ); 05450 RTERR( rtMaterialSetClosestHitProgram(material_general, RT_RAY_TYPE_RADIANCE, closest_hit_pgm_general) ); 05451 RTERR( rtMaterialSetAnyHitProgram(material_general, RT_RAY_TYPE_SHADOW, any_hit_pgm_clip_sphere) ); 05452 05453 05454 #if defined(ORT_USERTXAPIS) 05455 RTERR( rtMaterialCreate(ctx, &material_general_hwtri) ); 05456 RTERR( rtMaterialSetClosestHitProgram(material_general_hwtri, RT_RAY_TYPE_RADIANCE, closest_hit_pgm_general_hwtri) ); 05457 RTERR( rtMaterialSetAnyHitProgram(material_general_hwtri, RT_RAY_TYPE_SHADOW, any_hit_pgm_clip_sphere) ); 05458 #endif 05459 05460 05461 #if defined(ORT_USE_TEMPLATE_SHADERS) 05462 // build up the list of materials from all combinations of shader parameters 05463 for (i=0; i<ORTMTABSZ; i++) { 05464 RTERR( rtMaterialCreate(ctx, &material_special[i]) ); 05465 RTERR( rtMaterialSetClosestHitProgram(material_special[i], RT_RAY_TYPE_RADIANCE, closest_hit_pgm_special[i]) ); 05466 05467 // select correct any hit program depending on opacity 05468 if (clipview_mode == RT_CLIP_SPHERE) { 05469 RTERR( rtMaterialSetAnyHitProgram(material_special[i], RT_RAY_TYPE_SHADOW, any_hit_pgm_clip_sphere) ); 05470 } else { 05471 if (i & 1) { 05472 RTERR( rtMaterialSetAnyHitProgram(material_special[i], RT_RAY_TYPE_SHADOW, any_hit_pgm_transmission) ); 05473 } else { 05474 RTERR( rtMaterialSetAnyHitProgram(material_special[i], RT_RAY_TYPE_SHADOW, any_hit_pgm_opaque) ); 05475 } 05476 } 05477 05478 #if defined(ORT_USERTXAPIS) 05479 #error OptiX RTX triangle API not implemented for template shader expansion 05480 #endif 05481 05482 // zero out the array of material usage counts for the scene 05483 material_special_counts[i] = 0; 05484 } 05485 #endif 05486 } 05487 05488 05489 void OptiXRenderer::set_material(RTgeometryinstance instance, int matindex, 05490 const float *uniform_color, int hwtri) { 05491 if (!context_created) 05492 return; 05493 05494 //if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) setting material\n"); 05495 RTvariable ka, kd, ks, phongexp, krefl; 05496 RTvariable opacity, outline, outlinewidth, transmode, uniform_col; 05497 RTmaterial material = material_general; 05498 05499 #if defined(ORT_USERTXAPIS) 05500 // OptiX RTX hardware-triangle APIs require special material handling 05501 if (hwtri) { 05502 material = material_general_hwtri; 05503 } 05504 #endif 05505 05506 #if defined(ORT_USE_TEMPLATE_SHADERS) 05507 if (getenv("VMDOPTIXFORCEGENERALSHADER") == NULL) { 05508 unsigned int specialized_material_index = 05509 ((clipview_mode != RT_CLIP_NONE) << 7) | // VR clip pln/sph 05510 ((headlight_mode != RT_HEADLIGHT_OFF) << 6) | // VR headlight 05511 ((fog_mode != RT_FOG_NONE) << 5) | // fog 05512 ((shadows_enabled != RT_SHADOWS_OFF) << 4) | // shadows 05513 ((ao_samples != 0) << 3) | // AO 05514 ((materialcache[matindex].outline != 0) << 2) | // outline 05515 ((materialcache[matindex].reflectivity != 0) << 1) | // reflection 05516 ((materialcache[matindex].opacity != 1) ); // transmission 05517 05518 #if defined(VMDOPTIX_VCA_TABSZHACK) 05519 // XXX hack to mask down the material index down to the range 05520 // that works without creating trouble for the VCA 05521 if (specialized_material_index >= ORTMTABSZ) { 05522 specialized_material_index &= (ORTMTABSZ - 1); 05523 } 05524 #endif 05525 05526 material = material_special[specialized_material_index]; 05527 05528 // increment material usage counter 05529 material_special_counts[specialized_material_index]++; 05530 } 05531 #endif 05532 05533 RTERR( rtGeometryInstanceSetMaterialCount(instance, 1) ); 05534 RTERR( rtGeometryInstanceSetMaterial(instance, 0, material) ); 05535 05536 if (uniform_color != NULL) { 05537 RTERR( rtGeometryInstanceDeclareVariable(instance, "uniform_color", &uniform_col) ); 05538 RTERR( rtVariableSet3fv(uniform_col, uniform_color) ); 05539 } 05540 05541 RTERR( rtGeometryInstanceDeclareVariable(instance, "Ka", &ka) ); 05542 RTERR( rtGeometryInstanceDeclareVariable(instance, "Kd", &kd) ); 05543 RTERR( rtGeometryInstanceDeclareVariable(instance, "Ks", &ks) ); 05544 RTERR( rtGeometryInstanceDeclareVariable(instance, "phong_exp", &phongexp) ); 05545 RTERR( rtGeometryInstanceDeclareVariable(instance, "Krefl", &krefl) ); 05546 RTERR( rtGeometryInstanceDeclareVariable(instance, "opacity", &opacity) ); 05547 RTERR( rtGeometryInstanceDeclareVariable(instance, "outline", &outline) ); 05548 RTERR( rtGeometryInstanceDeclareVariable(instance, "outlinewidth", &outlinewidth) ); 05549 RTERR( rtGeometryInstanceDeclareVariable(instance, "transmode", &transmode) ); 05550 05551 RTERR( rtVariableSet1f(ka, materialcache[matindex].ambient) ); 05552 RTERR( rtVariableSet1f(kd, materialcache[matindex].diffuse) ); 05553 RTERR( rtVariableSet1f(ks, materialcache[matindex].specular) ); 05554 RTERR( rtVariableSet1f(phongexp, materialcache[matindex].shininess) ); 05555 RTERR( rtVariableSet1f(krefl, materialcache[matindex].reflectivity) ); 05556 RTERR( rtVariableSet1f(opacity, materialcache[matindex].opacity) ); 05557 RTERR( rtVariableSet1f(outline, materialcache[matindex].outline) ); 05558 RTERR( rtVariableSet1f(outlinewidth, materialcache[matindex].outlinewidth) ); 05559 RTERR( rtVariableSet1i(transmode, materialcache[matindex].transmode) ); 05560 } 05561 05562 05563 void OptiXRenderer::add_directional_light(const float *dir, const float *color) { 05564 ort_directional_light l; 05565 vec_copy(l.dir, dir); 05566 vec_copy(l.color, color); 05567 05568 directional_lights.append(l); 05569 } 05570 05571 05572 void OptiXRenderer::add_positional_light(const float *pos, const float *color) { 05573 ort_positional_light l; 05574 vec_copy(l.pos, pos); 05575 vec_copy(l.color, color); 05576 05577 positional_lights.append(l); 05578 } 05579 05580 05583 float OptiXRenderer::calc_matrix_scale_factor(const float *mat) { 05584 float scaleFactor = 05585 (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) + 05586 sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) + 05587 sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f; 05588 05589 return scaleFactor; 05590 } 05591 05592 05593 void OptiXRenderer::cylinder_array(Matrix4 *wtrans, float radius, 05594 const float *uniform_color, 05595 int cylnum, const float *points, 05596 int matindex) { 05597 if (!context_created) return; 05598 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating cylinder array: %d...\n", cylnum); 05599 cylinder_array_cnt += cylnum; 05600 05601 int i, ind; 05602 RTbuffer buf; 05603 RTgeometry geom; 05604 RTgeometryinstance instance; 05605 vmd_cylinder *cyldata; 05606 05607 // create and fill the OptiX cylinder array memory buffer 05608 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 05609 rtBufferSetFormat(buf, RT_FORMAT_USER); 05610 rtBufferSetElementSize(buf, sizeof(vmd_cylinder)); 05611 rtBufferSetSize1D(buf, cylnum); 05612 // rtBufferValidate(buf); 05613 rtBufferMap(buf, (void **) &cyldata); // map buffer for writing by host 05614 05615 if (wtrans == NULL) { 05616 for (i=0,ind=0; i<cylnum; i++,ind+=6) { 05617 // transform to eye coordinates 05618 vec_copy((float*) &cyldata[i].start, &points[ind]); 05619 cyldata[i].radius = radius; 05620 vec_sub((float*) &cyldata[i].axis, &points[ind+3], &points[ind]); 05621 } 05622 } else { 05623 for (i=0,ind=0; i<cylnum; i++,ind+=6) { 05624 // transform to eye coordinates 05625 wtrans->multpoint3d(&points[ind], (float*) &cyldata[i].start); 05626 cyldata[i].radius = radius; 05627 float ctmp[3]; 05628 wtrans->multpoint3d(&points[ind+3], ctmp); 05629 vec_sub((float*) &cyldata[i].axis, ctmp, &points[ind]); 05630 } 05631 } 05632 rtBufferUnmap(buf); // cylinder array is complete, unmap buffer 05633 05634 RTERR( rtGeometryCreate(ctx, &geom) ); 05635 RTERR( rtGeometrySetPrimitiveCount(geom, cylnum) ); 05636 RTERR( rtGeometrySetBoundingBoxProgram(geom, cylinder_array_bbox_pgm) ); 05637 RTERR( rtGeometrySetIntersectionProgram(geom, cylinder_array_isct_pgm) ); 05638 05639 // this cyl buffer is associated only with this particular geometry node 05640 RTvariable buf_v; 05641 RTERR( rtGeometryDeclareVariable(geom, "cylinder_buffer", &buf_v) ); 05642 RTERR( rtVariableSetObject(buf_v, buf) ); 05643 05644 // create a geometry instance node and bind materials to this geometry 05645 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 05646 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 05647 05648 set_material(instance, matindex, uniform_color); 05649 05650 append_objects(buf, geom, instance); 05651 } 05652 05653 05654 void OptiXRenderer::cylinder_array_color(Matrix4 *wtrans, float rscale, 05655 int cylnum, const float *points, 05656 const float *radii, 05657 const float *colors, int matindex) { 05658 if (!context_created) return; 05659 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating cylinder color array: %d...\n", cylnum); 05660 cylinder_array_color_cnt += cylnum; 05661 05662 int i, ind; 05663 RTbuffer buf; 05664 RTgeometry geom; 05665 RTgeometryinstance instance; 05666 vmd_cylinder_color *cyldata; 05667 05668 // create and fill the OptiX cylinder array memory buffer 05669 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 05670 rtBufferSetFormat(buf, RT_FORMAT_USER); 05671 rtBufferSetElementSize(buf, sizeof(vmd_cylinder_color)); 05672 rtBufferSetSize1D(buf, cylnum); 05673 // rtBufferValidate(buf); 05674 rtBufferMap(buf, (void **) &cyldata); // map buffer for writing by host 05675 05676 if (wtrans == NULL) { 05677 // already transformed to eye coordinates 05678 if (radii == NULL) { 05679 for (i=0,ind=0; i<cylnum; i++,ind+=6) { 05680 vec_copy((float*) &cyldata[i].start, &points[ind]); 05681 cyldata[i].radius = rscale; 05682 vec_sub((float*) &cyldata[i].axis, &points[ind+3], &points[ind]); 05683 vec_copy((float*) &cyldata[i].color, &colors[i*3]); 05684 } 05685 } else { 05686 for (i=0,ind=0; i<cylnum; i++,ind+=6) { 05687 vec_copy((float*) &cyldata[i].start, &points[ind]); 05688 cyldata[i].radius = rscale * radii[i]; 05689 vec_sub((float*) &cyldata[i].axis, &points[ind+3], &points[ind]); 05690 vec_copy((float*) &cyldata[i].color, &colors[i*3]); 05691 } 05692 } 05693 } else { 05694 // transform to eye coordinates 05695 if (radii == NULL) { 05696 for (i=0,ind=0; i<cylnum; i++,ind+=6) { 05697 wtrans->multpoint3d(&points[ind], (float*) &cyldata[i].start); 05698 cyldata[i].radius = rscale; 05699 float ctmp[3]; 05700 wtrans->multpoint3d(&points[ind+3], ctmp); 05701 vec_sub((float*) &cyldata[i].axis, ctmp, (float*) &cyldata[i].start); 05702 vec_copy((float*) &cyldata[i].color, &colors[i*3]); 05703 } 05704 } else { 05705 for (i=0,ind=0; i<cylnum; i++,ind+=6) { 05706 wtrans->multpoint3d(&points[ind], (float*) &cyldata[i].start); 05707 cyldata[i].radius = rscale * radii[i]; 05708 float ctmp[3]; 05709 wtrans->multpoint3d(&points[ind+3], ctmp); 05710 vec_sub((float*) &cyldata[i].axis, ctmp, (float*) &cyldata[i].start); 05711 vec_copy((float*) &cyldata[i].color, &colors[i*3]); 05712 } 05713 } 05714 } 05715 rtBufferUnmap(buf); // cylinder array is complete, unmap buffer 05716 05717 RTERR( rtGeometryCreate(ctx, &geom) ); 05718 RTERR( rtGeometrySetPrimitiveCount(geom, cylnum) ); 05719 RTERR( rtGeometrySetBoundingBoxProgram(geom, cylinder_array_color_bbox_pgm) ); 05720 RTERR( rtGeometrySetIntersectionProgram(geom, cylinder_array_color_isct_pgm) ); 05721 05722 // this cyl buffer is associated only with this particular geometry node 05723 RTvariable buf_v; 05724 RTERR( rtGeometryDeclareVariable(geom, "cylinder_color_buffer", &buf_v) ); 05725 RTERR( rtVariableSetObject(buf_v, buf) ); 05726 05727 // create a geometry instance node and bind materials to this geometry 05728 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 05729 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 05730 05731 set_material(instance, matindex, NULL); 05732 05733 append_objects(buf, geom, instance); 05734 } 05735 05736 05737 void OptiXRenderer::ring_array_color(Matrix4 & wtrans, float rscale, 05738 int rnum, const float *centers, 05739 const float *norms, const float *radii, 05740 const float *colors, int matindex) { 05741 if (!context_created) return; 05742 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating ring array color: %d...\n", rnum); 05743 ring_array_color_cnt += rnum; 05744 05745 int i, ind; 05746 RTbuffer buf; 05747 RTgeometry geom; 05748 RTgeometryinstance instance; 05749 vmd_ring_color *rdata; 05750 05751 // create and fill the OptiX ring array memory buffer 05752 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 05753 rtBufferSetFormat(buf, RT_FORMAT_USER); 05754 rtBufferSetElementSize(buf, sizeof(vmd_ring_color)); 05755 rtBufferSetSize1D(buf, rnum); 05756 // rtBufferValidate(buf); 05757 rtBufferMap(buf, (void **) &rdata); // map buffer for writing by host 05758 05759 for (i=0,ind=0; i<rnum; i++,ind+=3) { 05760 // transform to eye coordinates 05761 wtrans.multpoint3d(¢ers[ind], (float*) &rdata[i].center); 05762 wtrans.multnorm3d(&norms[ind], (float*) &rdata[i].norm); 05763 vec_normalize((float*) &rdata[i].norm); 05764 rdata[i].inrad = rscale * radii[i*2]; 05765 rdata[i].outrad = rscale * radii[i*2+1]; 05766 vec_copy((float*) &rdata[i].color, &colors[ind]); 05767 rdata[i].pad = 0.0f; // please valgrind 05768 } 05769 rtBufferUnmap(buf); // ring array is complete, unmap buffer 05770 05771 RTERR( rtGeometryCreate(ctx, &geom) ); 05772 RTERR( rtGeometrySetPrimitiveCount(geom, rnum) ); 05773 RTERR( rtGeometrySetBoundingBoxProgram(geom, ring_array_color_bbox_pgm) ); 05774 RTERR( rtGeometrySetIntersectionProgram(geom, ring_array_color_isct_pgm) ); 05775 05776 // this ring buffer is associated only with this particular geometry node 05777 RTvariable buf_v; 05778 RTERR( rtGeometryDeclareVariable(geom, "ring_color_buffer", &buf_v) ); 05779 RTERR( rtVariableSetObject(buf_v, buf) ); 05780 05781 // create a geometry instance node and bind materials to this geometry 05782 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 05783 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 05784 05785 set_material(instance, matindex, NULL); 05786 05787 append_objects(buf, geom, instance); 05788 } 05789 05790 05791 void OptiXRenderer::sphere_array(Matrix4 *wtrans, float rscale, 05792 const float *uniform_color, 05793 int spnum, const float *centers, 05794 const float *radii, 05795 int matindex) { 05796 if (!context_created) return; 05797 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating sphere array: %d...\n", spnum); 05798 sphere_array_cnt += spnum; 05799 05800 int i, ind; 05801 RTbuffer buf; 05802 RTgeometry geom; 05803 RTgeometryinstance instance; 05804 vmd_sphere *spdata; 05805 05806 // create and fill the OptiX sphere array memory buffer 05807 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 05808 rtBufferSetFormat(buf, RT_FORMAT_USER); 05809 rtBufferSetElementSize(buf, sizeof(vmd_sphere)); 05810 rtBufferSetSize1D(buf, spnum); 05811 // rtBufferValidate(buf); 05812 rtBufferMap(buf, (void **) &spdata); // map buffer for writing by host 05813 05814 if (wtrans == NULL) { 05815 if (radii == NULL) { 05816 for (i=0,ind=0; i<spnum; i++,ind+=3) { 05817 // transform to eye coordinates 05818 vec_copy((float*) &spdata[i].center, ¢ers[ind]); 05819 spdata[i].radius = rscale; // use "rscale" as radius... 05820 } 05821 } else { 05822 for (i=0,ind=0; i<spnum; i++,ind+=3) { 05823 // transform to eye coordinates 05824 vec_copy((float*) &spdata[i].center, ¢ers[ind]); 05825 spdata[i].radius = rscale * radii[i]; 05826 } 05827 } 05828 } else { 05829 if (radii == NULL) { 05830 for (i=0,ind=0; i<spnum; i++,ind+=3) { 05831 // transform to eye coordinates 05832 wtrans->multpoint3d(¢ers[ind], (float*) &spdata[i].center); 05833 spdata[i].radius = rscale; // use "rscale" as radius... 05834 } 05835 } else { 05836 for (i=0,ind=0; i<spnum; i++,ind+=3) { 05837 // transform to eye coordinates 05838 wtrans->multpoint3d(¢ers[ind], (float*) &spdata[i].center); 05839 spdata[i].radius = rscale * radii[i]; 05840 } 05841 } 05842 } 05843 rtBufferUnmap(buf); // sphere array is complete, unmap buffer 05844 05845 RTERR( rtGeometryCreate(ctx, &geom) ); 05846 RTERR( rtGeometrySetPrimitiveCount(geom, spnum) ); 05847 RTERR( rtGeometrySetBoundingBoxProgram(geom, sphere_array_bbox_pgm) ); 05848 RTERR( rtGeometrySetIntersectionProgram(geom, sphere_array_isct_pgm) ); 05849 05850 // this sphere buffer is associated only with this particular geometry node 05851 RTvariable buf_v; 05852 RTERR( rtGeometryDeclareVariable(geom, "sphere_buffer", &buf_v) ); 05853 RTERR( rtVariableSetObject(buf_v, buf) ); 05854 05855 // create a geometry instance node and bind materials to this geometry 05856 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 05857 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 05858 05859 set_material(instance, matindex, uniform_color); 05860 05861 append_objects(buf, geom, instance); 05862 } 05863 05864 05865 void OptiXRenderer::sphere_array_color(Matrix4 & wtrans, float rscale, 05866 int spnum, const float *centers, 05867 const float *radii, const float *colors, 05868 int matindex) { 05869 if (!context_created) return; 05870 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating sphere array color: %d...\n", spnum); 05871 sphere_array_color_cnt += spnum; 05872 05873 int i, ind; 05874 RTbuffer buf; 05875 RTgeometry geom; 05876 RTgeometryinstance instance; 05877 vmd_sphere_color *spdata; 05878 05879 // create and fill the OptiX sphere array memory buffer 05880 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 05881 rtBufferSetFormat(buf, RT_FORMAT_USER); 05882 rtBufferSetElementSize(buf, sizeof(vmd_sphere_color)); 05883 rtBufferSetSize1D(buf, spnum); 05884 // rtBufferValidate(buf); 05885 rtBufferMap(buf, (void **) &spdata); // map buffer for writing by host 05886 05887 for (i=0,ind=0; i<spnum; i++,ind+=3) { 05888 // transform to eye coordinates 05889 wtrans.multpoint3d(¢ers[ind], (float*) &spdata[i].center); 05890 spdata[i].radius = rscale * radii[i]; 05891 vec_copy((float*) &spdata[i].color, &colors[ind]); 05892 spdata[i].pad = 0.0f; // please valgrind 05893 } 05894 rtBufferUnmap(buf); // sphere array is complete, unmap buffer 05895 05896 RTERR( rtGeometryCreate(ctx, &geom) ); 05897 RTERR( rtGeometrySetPrimitiveCount(geom, spnum) ); 05898 RTERR( rtGeometrySetBoundingBoxProgram(geom, sphere_array_color_bbox_pgm) ); 05899 RTERR( rtGeometrySetIntersectionProgram(geom, sphere_array_color_isct_pgm) ); 05900 05901 // this sphere buffer is associated only with this particular geometry node 05902 RTvariable buf_v; 05903 RTERR( rtGeometryDeclareVariable(geom, "sphere_color_buffer", &buf_v) ); 05904 RTERR( rtVariableSetObject(buf_v, buf) ); 05905 05906 // create a geometry instance node and bind materials to this geometry 05907 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 05908 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 05909 05910 set_material(instance, matindex, NULL); 05911 05912 append_objects(buf, geom, instance); 05913 } 05914 05915 05916 #if defined(ORT_USERTXAPIS) 05917 void OptiXRenderer::tricolor_list_hwtri(Matrix4 & wtrans, int numtris, 05918 const float *vnc, int matindex) { 05919 if (!context_created) return; 05920 //if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating tricolor list: %d...\n", numtris); 05921 tricolor_cnt += numtris; 05922 05923 RTbuffer vbuf, nbuf, cbuf; 05924 RTgeometryinstance instance_hwtri; 05925 RTgeometrytriangles geom_hwtri; 05926 05927 // Create and fill vertex/normal/color buffers 05928 float3 *vertices; 05929 uint4 *normals; 05930 uchar4 *colors; 05931 hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numtris, vbuf, vertices, nbuf, normals, 05932 cbuf, 1, colors, NULL); 05933 05934 int i, ind, tcnt; 05935 for (i=0,ind=0,tcnt=0; i<numtris; i++,ind+=27) { 05936 int taddr = 3 * tcnt; 05937 05938 // transform to eye coordinates 05939 wtrans.multpoint3d(&vnc[ind ], (float*) &vertices[taddr + 0]); 05940 wtrans.multpoint3d(&vnc[ind + 3], (float*) &vertices[taddr + 1]); 05941 wtrans.multpoint3d(&vnc[ind + 6], (float*) &vertices[taddr + 2]); 05942 05943 // Compute geometric normal, detect and cull degenerate triangles 05944 float3 Ng; 05945 if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) { 05946 continue; // cull any triangle that fails degeneracy tests 05947 } 05948 05949 float3 n0, n1, n2; 05950 wtrans.multnorm3d(&vnc[ind + 9], (float*) &n0); 05951 wtrans.multnorm3d(&vnc[ind + 12], (float*) &n1); 05952 wtrans.multnorm3d(&vnc[ind + 15], (float*) &n2); 05953 05954 // Pack normals 05955 normals[tcnt].x = packNormal(Ng); 05956 normals[tcnt].y = packNormal(n0); 05957 normals[tcnt].z = packNormal(n1); 05958 normals[tcnt].w = packNormal(n2); 05959 05960 // convert color format 05961 colors[taddr + 0].x = vnc[ind + 18] * 255.0f; 05962 colors[taddr + 0].y = vnc[ind + 19] * 255.0f; 05963 colors[taddr + 0].z = vnc[ind + 20] * 255.0f; 05964 05965 colors[taddr + 1].x = vnc[ind + 21] * 255.0f; 05966 colors[taddr + 1].y = vnc[ind + 22] * 255.0f; 05967 colors[taddr + 1].z = vnc[ind + 23] * 255.0f; 05968 05969 colors[taddr + 2].x = vnc[ind + 24] * 255.0f; 05970 colors[taddr + 2].y = vnc[ind + 25] * 255.0f; 05971 colors[taddr + 2].z = vnc[ind + 26] * 255.0f; 05972 05973 tcnt++; // count non-culled triangles 05974 } 05975 05976 rtBufferUnmap(vbuf); 05977 rtBufferUnmap(nbuf); 05978 rtBufferUnmap(cbuf); 05979 05980 RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) ); 05981 RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) ); 05982 RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 05983 0, sizeof(float3), RT_FORMAT_FLOAT3) ); 05984 #if defined(VMDOPTIXRTXRELEASEBUFS) 05985 RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) ); 05986 #else 05987 append_buffer(vbuf); 05988 #endif 05989 05990 // create a geometry instance and bind materials to this geometry 05991 RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) ); 05992 RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) ); 05993 05994 // Enable per-vertex normals, enable per-vertex colors 05995 hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1); 05996 05997 // We have to pass the explicit hardware triangle parameter for this geometry 05998 set_material(instance_hwtri, matindex, NULL, 1); 05999 06000 // The vertex buffer is released automatically after construction. 06001 // We need to keep track of normal and color buffers for ourselves. 06002 append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri); 06003 } 06004 #endif 06005 06006 06007 void OptiXRenderer::tricolor_list(Matrix4 & wtrans, int numtris, 06008 const float *vnc, int matindex) { 06009 if (!context_created) return; 06010 //if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating tricolor list: %d...\n", numtris); 06011 tricolor_cnt += numtris; 06012 06013 int i, ind; 06014 RTbuffer buf; 06015 RTgeometry geom; 06016 RTgeometryinstance instance; 06017 vmd_tricolor *trimesh; 06018 06019 // create and fill the OptiX trimesh memory buffer 06020 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 06021 rtBufferSetFormat(buf, RT_FORMAT_USER); 06022 rtBufferSetElementSize(buf, sizeof(vmd_tricolor)); 06023 rtBufferSetSize1D(buf, numtris); 06024 // rtBufferValidate(buf); 06025 rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host 06026 06027 for (i=0,ind=0; i<numtris; i++,ind+=27) { 06028 // transform to eye coordinates 06029 wtrans.multpoint3d(&vnc[ind ], (float*) &trimesh[i].v0); 06030 wtrans.multpoint3d(&vnc[ind + 3], (float*) &trimesh[i].v1); 06031 wtrans.multpoint3d(&vnc[ind + 6], (float*) &trimesh[i].v2); 06032 06033 wtrans.multnorm3d(&vnc[ind + 9], (float*) &trimesh[i].n0); 06034 wtrans.multnorm3d(&vnc[ind + 12], (float*) &trimesh[i].n1); 06035 wtrans.multnorm3d(&vnc[ind + 15], (float*) &trimesh[i].n2); 06036 06037 vec_copy((float*) &trimesh[i].c0, &vnc[ind + 18]); 06038 vec_copy((float*) &trimesh[i].c1, &vnc[ind + 21]); 06039 vec_copy((float*) &trimesh[i].c2, &vnc[ind + 24]); 06040 } 06041 rtBufferUnmap(buf); // triangle list is complete, unmap buffer 06042 06043 RTERR( rtGeometryCreate(ctx, &geom) ); 06044 RTERR( rtGeometrySetPrimitiveCount(geom, numtris) ); 06045 RTERR( rtGeometrySetBoundingBoxProgram(geom, tricolor_bbox_pgm) ); 06046 RTERR( rtGeometrySetIntersectionProgram(geom, tricolor_isct_pgm) ); 06047 06048 // this buffer is associated only with this particular geometry node 06049 RTvariable buf_v; 06050 RTERR( rtGeometryDeclareVariable(geom, "tricolor_buffer", &buf_v) ); 06051 RTERR( rtVariableSetObject(buf_v, buf) ); 06052 06053 // create a geometry instance and bind materials to this geometry 06054 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 06055 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 06056 // RTERR( rtGeometryInstanceSetMaterialCount(instance, 1) ); 06057 06058 set_material(instance, matindex, NULL); 06059 06060 append_objects(buf, geom, instance); 06061 } 06062 06063 06064 #if defined(ORT_USERTXAPIS) 06065 void OptiXRenderer::trimesh_c4n3v3_hwtri(Matrix4 & wtrans, 06066 int numverts, const float *cnv, 06067 int numfacets, const int * facets, 06068 int matindex) { 06069 if (!context_created) return; 06070 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4n3v3_hwtri: %d...\n", numfacets); 06071 trimesh_c4u_n3b_v3f_cnt += numfacets; 06072 06073 RTbuffer vbuf, nbuf, cbuf; 06074 RTgeometryinstance instance_hwtri; 06075 RTgeometrytriangles geom_hwtri; 06076 06077 // Create and fill vertex/normal/color buffers 06078 float3 *vertices; 06079 uint4 *normals; 06080 uchar4 *colors; 06081 hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 06082 cbuf, numfacets * 3, colors, NULL); 06083 06084 int i, ind, tcnt; 06085 for (i=0,ind=0,tcnt=0; i<numfacets; i++,ind+=3) { 06086 int taddr = 3 * tcnt; 06087 06088 int v0 = facets[ind ] * 10; 06089 int v1 = facets[ind + 1] * 10; 06090 int v2 = facets[ind + 2] * 10; 06091 06092 // transform to eye coordinates 06093 wtrans.multpoint3d(cnv + v0 + 7, (float*) &vertices[taddr + 0]); 06094 wtrans.multpoint3d(cnv + v1 + 7, (float*) &vertices[taddr + 1]); 06095 wtrans.multpoint3d(cnv + v2 + 7, (float*) &vertices[taddr + 2]); 06096 06097 // Compute geometric normal, detect and cull degenerate triangles 06098 float3 Ng; 06099 if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) { 06100 continue; // cull any triangle that fails degeneracy tests 06101 } 06102 06103 float3 n0, n1, n2; 06104 wtrans.multnorm3d(cnv + v0 + 4, (float*) &n0); 06105 wtrans.multnorm3d(cnv + v1 + 4, (float*) &n1); 06106 wtrans.multnorm3d(cnv + v2 + 4, (float*) &n2); 06107 06108 // Pack normals 06109 normals[tcnt].x = packNormal(Ng); 06110 normals[tcnt].y = packNormal(n0); 06111 normals[tcnt].z = packNormal(n1); 06112 normals[tcnt].w = packNormal(n2); 06113 06114 // convert color format 06115 colors[taddr + 0].x = cnv[v0 + 0] * 255.0f; 06116 colors[taddr + 0].y = cnv[v0 + 1] * 255.0f; 06117 colors[taddr + 0].z = cnv[v0 + 2] * 255.0f; 06118 06119 colors[taddr + 1].x = cnv[v1 + 0] * 255.0f; 06120 colors[taddr + 1].y = cnv[v1 + 1] * 255.0f; 06121 colors[taddr + 1].z = cnv[v1 + 2] * 255.0f; 06122 06123 colors[taddr + 2].x = cnv[v2 + 0] * 255.0f; 06124 colors[taddr + 2].y = cnv[v2 + 1] * 255.0f; 06125 colors[taddr + 2].z = cnv[v2 + 2] * 255.0f; 06126 06127 tcnt++; // count non-culled triangles 06128 } 06129 06130 rtBufferUnmap(vbuf); 06131 rtBufferUnmap(nbuf); 06132 rtBufferUnmap(cbuf); 06133 06134 RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) ); 06135 RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) ); 06136 RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 06137 0, sizeof(float3), RT_FORMAT_FLOAT3) ); 06138 #if defined(VMDOPTIXRTXRELEASEBUFS) 06139 RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) ); 06140 #else 06141 append_buffer(vbuf); 06142 #endif 06143 06144 // create a geometry instance and bind materials to this geometry 06145 RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) ); 06146 RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) ); 06147 06148 // Enable per-vertex normals, enable per-vertex colors 06149 hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1); 06150 06151 // We have to pass the explicit hardware triangle parameter for this geometry 06152 set_material(instance_hwtri, matindex, NULL, 1); 06153 06154 // The vertex buffer is released automatically after construction. 06155 // We need to keep track of normal and color buffers for ourselves. 06156 append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri); 06157 } 06158 #endif 06159 06160 06161 void OptiXRenderer::trimesh_c4n3v3(Matrix4 & wtrans, 06162 int numverts, const float *cnv, 06163 int numfacets, const int * facets, 06164 int matindex) { 06165 if (!context_created) return; 06166 06167 #if defined(ORT_USERTXAPIS) 06168 // OptiX 5.2 hardware-accelerated triangle API 06169 if (hwtri_enabled) { 06170 trimesh_c4n3v3_hwtri(wtrans, numverts, cnv, numfacets, facets, matindex); 06171 return; 06172 } 06173 #endif 06174 06175 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4n3v3: %d...\n", numfacets); 06176 trimesh_c4u_n3b_v3f_cnt += numfacets; 06177 06178 int i, ind; 06179 RTbuffer buf; 06180 RTgeometry geom; 06181 RTgeometryinstance instance; 06182 vmd_tricolor *trimesh; 06183 06184 // create and fill the OptiX trimesh memory buffer 06185 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 06186 rtBufferSetFormat(buf, RT_FORMAT_USER); 06187 rtBufferSetElementSize(buf, sizeof(vmd_tricolor)); 06188 rtBufferSetSize1D(buf, numfacets); 06189 // rtBufferValidate(buf); 06190 rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host 06191 06192 for (i=0,ind=0; i<numfacets; i++,ind+=3) { 06193 int v0 = facets[ind ] * 10; 06194 int v1 = facets[ind + 1] * 10; 06195 int v2 = facets[ind + 2] * 10; 06196 06197 // transform to eye coordinates 06198 wtrans.multpoint3d(cnv + v0 + 7, (float*) &trimesh[i].v0); 06199 wtrans.multpoint3d(cnv + v1 + 7, (float*) &trimesh[i].v1); 06200 wtrans.multpoint3d(cnv + v2 + 7, (float*) &trimesh[i].v2); 06201 06202 wtrans.multnorm3d(cnv + v0 + 4, (float*) &trimesh[i].n0); 06203 wtrans.multnorm3d(cnv + v1 + 4, (float*) &trimesh[i].n1); 06204 wtrans.multnorm3d(cnv + v2 + 4, (float*) &trimesh[i].n2); 06205 06206 vec_copy((float*) &trimesh[i].c0, cnv + v0); 06207 vec_copy((float*) &trimesh[i].c1, cnv + v1); 06208 vec_copy((float*) &trimesh[i].c2, cnv + v2); 06209 } 06210 rtBufferUnmap(buf); // triangle list is complete, unmap buffer 06211 06212 RTERR( rtGeometryCreate(ctx, &geom) ); 06213 RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) ); 06214 RTERR( rtGeometrySetBoundingBoxProgram(geom, tricolor_bbox_pgm) ); 06215 RTERR( rtGeometrySetIntersectionProgram(geom, tricolor_isct_pgm) ); 06216 06217 // this buffer is associated only with this particular geometry node 06218 RTvariable buf_v; 06219 RTERR( rtGeometryDeclareVariable(geom, "tricolor_buffer", &buf_v) ); 06220 RTERR( rtVariableSetObject(buf_v, buf) ); 06221 06222 // create a geometry instance and bind materials to this geometry 06223 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 06224 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 06225 06226 set_material(instance, matindex, NULL); 06227 06228 append_objects(buf, geom, instance); 06229 } 06230 06231 06232 #if defined(ORT_USERTXAPIS) 06233 // 06234 // This implementation translates from the most-compact host representation 06235 // to a GPU-specific organization that balances performance vs. memory 06236 // storage efficiency. 06237 // 06238 void OptiXRenderer::trimesh_c4u_n3b_v3f_hwtri(Matrix4 & wtrans, 06239 const unsigned char *c, 06240 const signed char *n, 06241 const float *v, int numfacets, 06242 int matindex) { 06243 if (!context_created) return; 06244 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4u_n3b_v3f_hwtri: %d...\n", numfacets); 06245 trimesh_c4u_n3b_v3f_cnt += numfacets; 06246 06247 RTbuffer vbuf, nbuf, cbuf; 06248 RTgeometryinstance instance_hwtri; 06249 RTgeometrytriangles geom_hwtri; 06250 06251 // Create and fill vertex/normal/color buffers 06252 float3 *vertices; 06253 uint4 *normals; 06254 uchar4 *colors; 06255 hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 06256 cbuf, numfacets * 3, colors, NULL); 06257 06258 const float ci2f = 1.0f / 255.0f; 06259 const float cn2f = 1.0f / 127.5f; 06260 int i, j, ind, tcnt; 06261 for (ind=0,i=0,j=0,tcnt=0; ind<numfacets; ind++,i+=9,j+=12) { 06262 float norm[9]; 06263 int taddr = 3 * tcnt; 06264 06265 // transform to eye coordinates 06266 wtrans.multpoint3d(v + i , (float*) &vertices[taddr + 0]); 06267 wtrans.multpoint3d(v + i + 3, (float*) &vertices[taddr + 1]); 06268 wtrans.multpoint3d(v + i + 6, (float*) &vertices[taddr + 2]); 06269 06270 // Compute geometric normal, detect and cull degenerate triangles 06271 float3 Ng; 06272 if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) { 06273 continue; // cull any triangle that fails degeneracy tests 06274 } 06275 06276 // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1 06277 // float = (2c+1)/(2^8-1) 06278 norm[0] = n[i ] * cn2f + ci2f; 06279 norm[1] = n[i + 1] * cn2f + ci2f; 06280 norm[2] = n[i + 2] * cn2f + ci2f; 06281 norm[3] = n[i + 3] * cn2f + ci2f; 06282 norm[4] = n[i + 4] * cn2f + ci2f; 06283 norm[5] = n[i + 5] * cn2f + ci2f; 06284 norm[6] = n[i + 6] * cn2f + ci2f; 06285 norm[7] = n[i + 7] * cn2f + ci2f; 06286 norm[8] = n[i + 8] * cn2f + ci2f; 06287 06288 // transform normals 06289 float3 n0, n1, n2; 06290 wtrans.multnorm3d(&norm[0], (float*) &n0); 06291 wtrans.multnorm3d(&norm[3], (float*) &n1); 06292 wtrans.multnorm3d(&norm[6], (float*) &n2); 06293 06294 // Pack normals 06295 normals[tcnt].x = packNormal(Ng); 06296 normals[tcnt].y = packNormal(n0); 06297 normals[tcnt].z = packNormal(n1); 06298 normals[tcnt].w = packNormal(n2); 06299 06300 memcpy(&colors[tcnt * 3], &c[j], 12); // copy colors (same memory format) 06301 06302 tcnt++; // count non-culled triangles 06303 } 06304 06305 rtBufferUnmap(vbuf); 06306 rtBufferUnmap(nbuf); 06307 rtBufferUnmap(cbuf); 06308 06309 RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) ); 06310 RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) ); 06311 RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 06312 0, sizeof(float3), RT_FORMAT_FLOAT3) ); 06313 #if defined(VMDOPTIXRTXRELEASEBUFS) 06314 RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) ); 06315 #else 06316 append_buffer(vbuf); 06317 #endif 06318 06319 // create a geometry instance and bind materials to this geometry 06320 RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) ); 06321 RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) ); 06322 06323 // Enable per-vertex normals, enable per-vertex colors 06324 hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1); 06325 06326 // We have to pass the explicit hardware triangle parameter for this geometry 06327 set_material(instance_hwtri, matindex, NULL, 1); 06328 06329 // The vertex buffer is released automatically after construction. 06330 // We need to keep track of normal and color buffers for ourselves. 06331 append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri); 06332 } 06333 #endif 06334 06335 06336 // 06337 // This implementation translates from the most-compact host representation 06338 // to a GPU-specific organization that balances performance vs. memory 06339 // storage efficiency. 06340 // 06341 void OptiXRenderer::trimesh_c4u_n3b_v3f(Matrix4 & wtrans, 06342 const unsigned char *c, 06343 const signed char *n, const float *v, 06344 int numfacets, int matindex) { 06345 if (!context_created) return; 06346 06347 #if defined(ORT_USERTXAPIS) 06348 // OptiX RTX hardware-accelerated triangle API 06349 if (hwtri_enabled) { 06350 trimesh_c4u_n3b_v3f_hwtri(wtrans, c, n, v, numfacets, matindex); 06351 return; 06352 } 06353 #endif 06354 06355 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4u_n3b_v3f: %d...\n", numfacets); 06356 trimesh_n3b_v3f_cnt += numfacets; 06357 06358 int i, j, ind; 06359 RTbuffer buf; 06360 RTgeometry geom; 06361 RTgeometryinstance instance; 06362 vmd_trimesh_c4u_n3b_v3f *trimesh; 06363 06364 // create and fill the OptiX trimesh memory buffer 06365 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 06366 rtBufferSetFormat(buf, RT_FORMAT_USER); 06367 rtBufferSetElementSize(buf, sizeof(vmd_trimesh_c4u_n3b_v3f)); 06368 rtBufferSetSize1D(buf, numfacets); 06369 // rtBufferValidate(buf); 06370 rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host 06371 06372 const float ci2f = 1.0f / 255.0f; 06373 const float cn2f = 1.0f / 127.5f; 06374 for (ind=0,i=0,j=0; ind<numfacets; ind++,i+=9,j+=12) { 06375 float norm[9]; 06376 06377 // transform to eye coordinates 06378 wtrans.multpoint3d(v + i , (float*) &trimesh[ind].v0); 06379 wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1); 06380 wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2); 06381 06382 // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1 06383 // float = (2c+1)/(2^8-1) 06384 norm[0] = n[i ] * cn2f + ci2f; 06385 norm[1] = n[i + 1] * cn2f + ci2f; 06386 norm[2] = n[i + 2] * cn2f + ci2f; 06387 norm[3] = n[i + 3] * cn2f + ci2f; 06388 norm[4] = n[i + 4] * cn2f + ci2f; 06389 norm[5] = n[i + 5] * cn2f + ci2f; 06390 norm[6] = n[i + 6] * cn2f + ci2f; 06391 norm[7] = n[i + 7] * cn2f + ci2f; 06392 norm[8] = n[i + 8] * cn2f + ci2f; 06393 06394 // transform normals 06395 float3 tmpn; 06396 wtrans.multnorm3d(&norm[0], (float*) &tmpn); 06397 tmpn = tmpn * 127.5f - 0.5f; 06398 trimesh[ind].n0 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0); 06399 wtrans.multnorm3d(&norm[3], (float*) &tmpn); 06400 tmpn = tmpn * 127.5f - 0.5f; 06401 trimesh[ind].n1 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0); 06402 wtrans.multnorm3d(&norm[6], (float*) &tmpn); 06403 tmpn = tmpn * 127.5f - 0.5f; 06404 trimesh[ind].n2 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0); 06405 06406 memcpy(&trimesh[ind].c0, &c[j ], 4); 06407 memcpy(&trimesh[ind].c1, &c[j+4], 4); 06408 memcpy(&trimesh[ind].c2, &c[j+8], 4); 06409 } 06410 rtBufferUnmap(buf); // triangle list is complete, unmap buffer 06411 06412 RTERR( rtGeometryCreate(ctx, &geom) ); 06413 RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) ); 06414 RTERR( rtGeometrySetBoundingBoxProgram(geom, trimesh_c4u_n3b_v3f_bbox_pgm) ); 06415 RTERR( rtGeometrySetIntersectionProgram(geom, trimesh_c4u_n3b_v3f_isct_pgm) ); 06416 06417 // this trimesh buffer is associated only with this particular geometry node 06418 RTvariable buf_v; 06419 RTERR( rtGeometryDeclareVariable(geom, "trimesh_c4u_n3b_v3f_buffer", &buf_v) ); 06420 RTERR( rtVariableSetObject(buf_v, buf) ); 06421 06422 // create a geometry instance and bind materials to this geometry 06423 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 06424 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 06425 06426 set_material(instance, matindex, NULL); 06427 06428 append_objects(buf, geom, instance); 06429 } 06430 06431 06432 #if defined(ORT_USERTXAPIS) 06433 void OptiXRenderer::trimesh_c4u_n3f_v3f_hwtri(Matrix4 & wtrans, 06434 const unsigned char *c, 06435 const float *n, const float *v, 06436 int numfacets, int matindex) { 06437 if (!context_created) return; 06438 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4u_n3f_v3f: %d...\n", numfacets); 06439 tricolor_cnt += numfacets; 06440 06441 RTbuffer vbuf, nbuf, cbuf; 06442 RTgeometryinstance instance_hwtri; 06443 RTgeometrytriangles geom_hwtri; 06444 06445 // Create and fill vertex/normal/color buffers 06446 float3 *vertices; 06447 uint4 *normals; 06448 uchar4 *colors; 06449 hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 06450 cbuf, 1, colors, NULL); 06451 06452 int i, j, ind, tcnt; 06453 for (ind=0,i=0,j=0,tcnt=0; ind<numfacets; ind++,i+=9,j+=12) { 06454 int taddr = 3 * tcnt; 06455 06456 // transform to eye coordinates 06457 wtrans.multpoint3d(v + i , (float*) &vertices[taddr + 0]); 06458 wtrans.multpoint3d(v + i + 3, (float*) &vertices[taddr + 1]); 06459 wtrans.multpoint3d(v + i + 6, (float*) &vertices[taddr + 2]); 06460 06461 // Compute geometric normal, detect and cull degenerate triangles 06462 float3 Ng; 06463 if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) { 06464 continue; // cull any triangle that fails degeneracy tests 06465 } 06466 06467 float3 n0, n1, n2; 06468 wtrans.multnorm3d(n + i , (float*) &n0); 06469 wtrans.multnorm3d(n + i + 3, (float*) &n1); 06470 wtrans.multnorm3d(n + i + 6, (float*) &n2); 06471 06472 // Pack normals 06473 normals[tcnt].x = packNormal(Ng); 06474 normals[tcnt].y = packNormal(n0); 06475 normals[tcnt].z = packNormal(n1); 06476 normals[tcnt].w = packNormal(n2); 06477 06478 memcpy(&colors[taddr + 0], &c[j ], sizeof(uchar4)); 06479 memcpy(&colors[taddr + 1], &c[j+4], sizeof(uchar4)); 06480 memcpy(&colors[taddr + 2], &c[j+8], sizeof(uchar4)); 06481 06482 tcnt++; // count non-culled triangles 06483 } 06484 06485 rtBufferUnmap(vbuf); 06486 rtBufferUnmap(nbuf); 06487 rtBufferUnmap(cbuf); 06488 06489 RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) ); 06490 RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) ); 06491 RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 06492 0, sizeof(float3), RT_FORMAT_FLOAT3) ); 06493 #if defined(VMDOPTIXRTXRELEASEBUFS) 06494 RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) ); 06495 #else 06496 append_buffer(vbuf); 06497 #endif 06498 06499 // create a geometry instance and bind materials to this geometry 06500 RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) ); 06501 RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) ); 06502 06503 // Enable per-vertex normals, enable per-vertex colors 06504 hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1); 06505 06506 // We have to pass the explicit hardware triangle parameter for this geometry 06507 set_material(instance_hwtri, matindex, NULL, 1); 06508 06509 // The vertex buffer is released automatically after construction. 06510 // We need to keep track of normal and color buffers for ourselves. 06511 append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri); 06512 } 06513 #endif 06514 06515 06516 void OptiXRenderer::trimesh_c4u_n3f_v3f(Matrix4 & wtrans, 06517 const unsigned char *c, 06518 const float *n, const float *v, 06519 int numfacets, int matindex) { 06520 if (!context_created) return; 06521 06522 #if defined(ORT_USERTXAPIS) 06523 // OptiX RTX hardware-accelerated triangle API 06524 if (hwtri_enabled) { 06525 trimesh_c4u_n3f_v3f_hwtri(wtrans, c, n, v, numfacets, matindex); 06526 return; 06527 } 06528 #endif 06529 06530 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4u_n3f_v3f: %d...\n", numfacets); 06531 tricolor_cnt += numfacets; 06532 06533 int i, j, ind; 06534 RTbuffer buf; 06535 RTgeometry geom; 06536 RTgeometryinstance instance; 06537 vmd_tricolor *trimesh; 06538 06539 // create and fill the OptiX trimesh memory buffer 06540 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 06541 rtBufferSetFormat(buf, RT_FORMAT_USER); 06542 rtBufferSetElementSize(buf, sizeof(vmd_tricolor)); 06543 rtBufferSetSize1D(buf, numfacets); 06544 // rtBufferValidate(buf); 06545 rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host 06546 06547 const float ci2f = 1.0f / 255.0f; 06548 for (ind=0,i=0,j=0; ind<numfacets; ind++,i+=9,j+=12) { 06549 // transform to eye coordinates 06550 wtrans.multpoint3d(v + i , (float*) &trimesh[ind].v0); 06551 wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1); 06552 wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2); 06553 06554 wtrans.multnorm3d(n + i , (float*) &trimesh[ind].n0); 06555 wtrans.multnorm3d(n + i + 3, (float*) &trimesh[ind].n1); 06556 wtrans.multnorm3d(n + i + 6, (float*) &trimesh[ind].n2); 06557 06558 // conversion from GLubyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1 06559 // float = c/(2^8-1) 06560 float col[9]; 06561 col[0] = c[j ] * ci2f; 06562 col[1] = c[j + 1] * ci2f; 06563 col[2] = c[j + 2] * ci2f; 06564 col[3] = c[j + 4] * ci2f; 06565 col[4] = c[j + 5] * ci2f; 06566 col[5] = c[j + 6] * ci2f; 06567 col[6] = c[j + 8] * ci2f; 06568 col[7] = c[j + 9] * ci2f; 06569 col[8] = c[j + 10] * ci2f; 06570 06571 vec_copy((float*) &trimesh[ind].c0, &col[0]); 06572 vec_copy((float*) &trimesh[ind].c1, &col[3]); 06573 vec_copy((float*) &trimesh[ind].c2, &col[6]); 06574 } 06575 rtBufferUnmap(buf); // triangle list is complete, unmap buffer 06576 06577 RTERR( rtGeometryCreate(ctx, &geom) ); 06578 RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) ); 06579 RTERR( rtGeometrySetBoundingBoxProgram(geom, tricolor_bbox_pgm) ); 06580 RTERR( rtGeometrySetIntersectionProgram(geom, tricolor_isct_pgm) ); 06581 06582 // this buffer is associated only with this particular geometry node 06583 RTvariable buf_v; 06584 RTERR( rtGeometryDeclareVariable(geom, "tricolor_buffer", &buf_v) ); 06585 RTERR( rtVariableSetObject(buf_v, buf) ); 06586 06587 // create a geometry instance and bind materials to this geometry 06588 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 06589 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 06590 06591 set_material(instance, matindex, NULL); 06592 06593 append_objects(buf, geom, instance); 06594 } 06595 06596 06597 #if defined(ORT_USERTXAPIS) 06598 void OptiXRenderer::trimesh_n3b_v3f_hwtri(Matrix4 & wtrans, 06599 const float *uniform_color, 06600 const signed char *n, const float *v, 06601 int numfacets, int matindex) { 06602 if (!context_created) return; 06603 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_n3b_v3f_hwtri: %d...\n", numfacets); 06604 trimesh_n3b_v3f_cnt += numfacets; 06605 06606 RTbuffer vbuf, nbuf, cbuf; 06607 RTgeometryinstance instance_hwtri; 06608 RTgeometrytriangles geom_hwtri; 06609 06610 // Create and fill vertex/normal/color buffers 06611 float3 *vertices; 06612 uint4 *normals; 06613 uchar4 *colors; 06614 hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 06615 cbuf, 1, colors, uniform_color); 06616 06617 const float ci2f = 1.0f / 255.0f; 06618 const float cn2f = 1.0f / 127.5f; 06619 int i, ind, tcnt; 06620 for (ind=0,i=0,tcnt=0; ind<numfacets; ind++,i+=9) { 06621 float norm[9]; 06622 int taddr = 3 * tcnt; 06623 06624 // transform to eye coordinates 06625 wtrans.multpoint3d(v + i , (float*) &vertices[taddr + 0]); 06626 wtrans.multpoint3d(v + i + 3, (float*) &vertices[taddr + 1]); 06627 wtrans.multpoint3d(v + i + 6, (float*) &vertices[taddr + 2]); 06628 06629 // Compute geometric normal, detect and cull degenerate triangles 06630 float3 Ng; 06631 if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) { 06632 continue; // cull any triangle that fails degeneracy tests 06633 } 06634 06635 // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1 06636 // float = (2c+1)/(2^8-1) 06637 norm[0] = n[i ] * cn2f + ci2f; 06638 norm[1] = n[i + 1] * cn2f + ci2f; 06639 norm[2] = n[i + 2] * cn2f + ci2f; 06640 norm[3] = n[i + 3] * cn2f + ci2f; 06641 norm[4] = n[i + 4] * cn2f + ci2f; 06642 norm[5] = n[i + 5] * cn2f + ci2f; 06643 norm[6] = n[i + 6] * cn2f + ci2f; 06644 norm[7] = n[i + 7] * cn2f + ci2f; 06645 norm[8] = n[i + 8] * cn2f + ci2f; 06646 06647 // transform normals 06648 float3 n0, n1, n2; 06649 wtrans.multnorm3d(&norm[0], (float*) &n0); 06650 wtrans.multnorm3d(&norm[3], (float*) &n1); 06651 wtrans.multnorm3d(&norm[6], (float*) &n2); 06652 06653 // Pack normals 06654 normals[tcnt].x = packNormal(Ng); 06655 normals[tcnt].y = packNormal(n0); 06656 normals[tcnt].z = packNormal(n1); 06657 normals[tcnt].w = packNormal(n2); 06658 06659 tcnt++; // count non-culled triangles 06660 } 06661 06662 rtBufferUnmap(vbuf); 06663 rtBufferUnmap(nbuf); 06664 rtBufferUnmap(cbuf); 06665 06666 RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) ); 06667 RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) ); 06668 RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 06669 0, sizeof(float3), RT_FORMAT_FLOAT3) ); 06670 #if defined(VMDOPTIXRTXRELEASEBUFS) 06671 RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) ); 06672 #else 06673 append_buffer(vbuf); 06674 #endif 06675 06676 // create a geometry instance and bind materials to this geometry 06677 RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) ); 06678 RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) ); 06679 06680 // Enable per-vertex normals, disable per-vertex colors (use uniform color) 06681 hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 0); 06682 06683 // We have to pass the explicit hardware triangle parameter for this geometry 06684 set_material(instance_hwtri, matindex, uniform_color, 1); 06685 06686 // The vertex buffer is released automatically after construction. 06687 // We need to keep track of normal and color buffers for ourselves. 06688 append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri); 06689 } 06690 #endif 06691 06692 06693 void OptiXRenderer::trimesh_n3b_v3f(Matrix4 & wtrans, 06694 const float *uniform_color, 06695 const signed char *n, const float *v, 06696 int numfacets, int matindex) { 06697 if (!context_created) return; 06698 06699 #if defined(ORT_USERTXAPIS) 06700 // OptiX RTX hardware-accelerated triangle API 06701 if (hwtri_enabled) { 06702 trimesh_n3b_v3f_hwtri(wtrans, uniform_color, n, v, numfacets, matindex); 06703 return; 06704 } 06705 #endif 06706 06707 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_n3b_v3f: %d...\n", numfacets); 06708 trimesh_n3b_v3f_cnt += numfacets; 06709 06710 int i, ind; 06711 RTbuffer buf; 06712 RTgeometry geom; 06713 RTgeometryinstance instance; 06714 vmd_trimesh_n3b_v3f *trimesh; 06715 06716 // create and fill the OptiX trimesh memory buffer 06717 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 06718 rtBufferSetFormat(buf, RT_FORMAT_USER); 06719 rtBufferSetElementSize(buf, sizeof(vmd_trimesh_n3b_v3f)); 06720 rtBufferSetSize1D(buf, numfacets); 06721 // rtBufferValidate(buf); 06722 rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host 06723 06724 const float ci2f = 1.0f / 255.0f; 06725 const float cn2f = 1.0f / 127.5f; 06726 for (ind=0,i=0; ind<numfacets; ind++,i+=9) { 06727 float norm[9]; 06728 06729 // transform to eye coordinates 06730 wtrans.multpoint3d(v + i , (float*) &trimesh[ind].v0); 06731 wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1); 06732 wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2); 06733 06734 // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1 06735 // float = (2c+1)/(2^8-1) 06736 norm[0] = n[i ] * cn2f + ci2f; 06737 norm[1] = n[i + 1] * cn2f + ci2f; 06738 norm[2] = n[i + 2] * cn2f + ci2f; 06739 norm[3] = n[i + 3] * cn2f + ci2f; 06740 norm[4] = n[i + 4] * cn2f + ci2f; 06741 norm[5] = n[i + 5] * cn2f + ci2f; 06742 norm[6] = n[i + 6] * cn2f + ci2f; 06743 norm[7] = n[i + 7] * cn2f + ci2f; 06744 norm[8] = n[i + 8] * cn2f + ci2f; 06745 06746 // transform normals 06747 float3 tmpn; 06748 wtrans.multnorm3d(&norm[0], (float*) &tmpn); 06749 tmpn = tmpn * 127.5f - 0.5f; 06750 trimesh[ind].n0 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0); 06751 wtrans.multnorm3d(&norm[3], (float*) &tmpn); 06752 tmpn = tmpn * 127.5f - 0.5f; 06753 trimesh[ind].n1 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0); 06754 wtrans.multnorm3d(&norm[6], (float*) &tmpn); 06755 tmpn = tmpn * 127.5f - 0.5f; 06756 trimesh[ind].n2 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0); 06757 } 06758 rtBufferUnmap(buf); // triangle list is complete, unmap buffer 06759 06760 RTERR( rtGeometryCreate(ctx, &geom) ); 06761 RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) ); 06762 RTERR( rtGeometrySetBoundingBoxProgram(geom, trimesh_n3b_v3f_bbox_pgm) ); 06763 RTERR( rtGeometrySetIntersectionProgram(geom, trimesh_n3b_v3f_isct_pgm) ); 06764 06765 // this buffer is associated only with this particular geometry node 06766 RTvariable buf_v; 06767 RTERR( rtGeometryDeclareVariable(geom, "trimesh_n3b_v3f_buffer", &buf_v) ); 06768 RTERR( rtVariableSetObject(buf_v, buf) ); 06769 06770 // create a geometry instance and bind materials to this geometry 06771 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 06772 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 06773 06774 set_material(instance, matindex, uniform_color); 06775 06776 append_objects(buf, geom, instance); 06777 } 06778 06779 06780 #if defined(ORT_USERTXAPIS) 06781 void OptiXRenderer::trimesh_n3f_v3f_hwtri(Matrix4 & wtrans, 06782 const float *uniform_color, 06783 const float *n, const float *v, 06784 int numfacets, int matindex) { 06785 if (!context_created) return; 06786 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_n3f_v3f_hwtri: %d...\n", numfacets); 06787 trimesh_n3f_v3f_cnt += numfacets; 06788 06789 RTbuffer vbuf, nbuf, cbuf; 06790 RTgeometryinstance instance_hwtri; 06791 RTgeometrytriangles geom_hwtri; 06792 06793 // Create and fill vertex/normal/color buffers 06794 float3 *vertices; 06795 uint4 *normals; 06796 uchar4 *colors; 06797 hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 06798 cbuf, 1, colors, uniform_color); 06799 06800 float3 n0, n1, n2; 06801 int i, tcnt; 06802 for (i=0, tcnt=0; i < numfacets; i++) { 06803 int taddr = 3 * tcnt; 06804 06805 // transform to eye coordinates 06806 wtrans.multpoint3d(v + 9 * i + 0, (float*) &vertices[taddr + 0]); 06807 wtrans.multpoint3d(v + 9 * i + 3, (float*) &vertices[taddr + 1]); 06808 wtrans.multpoint3d(v + 9 * i + 6, (float*) &vertices[taddr + 2]); 06809 06810 // Compute geometric normal, detect and cull degenerate triangles 06811 float3 Ng; 06812 if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) { 06813 continue; // cull any triangle that fails degeneracy tests 06814 } 06815 06816 wtrans.multnorm3d(n + 9 * i + 0, (float*) &n0.x); 06817 wtrans.multnorm3d(n + 9 * i + 3, (float*) &n1.x); 06818 wtrans.multnorm3d(n + 9 * i + 6, (float*) &n2.x); 06819 06820 // Pack normals 06821 normals[i].x = packNormal(Ng); 06822 normals[i].y = packNormal(n0); 06823 normals[i].z = packNormal(n1); 06824 normals[i].w = packNormal(n2); 06825 06826 tcnt++; // count non-culled triangles 06827 } 06828 06829 rtBufferUnmap(vbuf); 06830 rtBufferUnmap(nbuf); 06831 rtBufferUnmap(cbuf); 06832 06833 RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) ); 06834 RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) ); 06835 RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 06836 0, sizeof(float3), RT_FORMAT_FLOAT3) ); 06837 #if defined(VMDOPTIXRTXRELEASEBUFS) 06838 RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) ); 06839 #else 06840 append_buffer(vbuf); 06841 #endif 06842 06843 // create a geometry instance and bind materials to this geometry 06844 RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) ); 06845 RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) ); 06846 06847 // Enable per-vertex normals, disable per-vertex colors (use uniform color) 06848 hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 0); 06849 06850 // We have to pass the explicit hardware triangle parameter for this geometry 06851 set_material(instance_hwtri, matindex, uniform_color, 1); 06852 06853 // The vertex buffer is released automatically after construction. 06854 // We need to keep track of normal and color buffers for ourselves. 06855 append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri); 06856 } 06857 #endif 06858 06859 06860 void OptiXRenderer::trimesh_n3f_v3f(Matrix4 & wtrans, 06861 const float *uniform_color, 06862 const float *n, const float *v, 06863 int numfacets, int matindex) { 06864 if (!context_created) return; 06865 06866 #if defined(ORT_USERTXAPIS) 06867 // OptiX RTX hardware-accelerated triangle API 06868 if (hwtri_enabled) { 06869 trimesh_n3f_v3f_hwtri(wtrans, uniform_color, n, v, numfacets, matindex); 06870 return; 06871 } 06872 #endif 06873 06874 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_n3f_v3f: %d...\n", numfacets); 06875 trimesh_n3f_v3f_cnt += numfacets; 06876 06877 int i, ind; 06878 RTbuffer buf; 06879 RTgeometry geom; 06880 RTgeometryinstance instance; 06881 vmd_trimesh_n3f_v3f *trimesh; 06882 06883 // create and fill the OptiX trimesh memory buffer 06884 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 06885 rtBufferSetFormat(buf, RT_FORMAT_USER); 06886 rtBufferSetElementSize(buf, sizeof(vmd_trimesh_n3f_v3f)); 06887 rtBufferSetSize1D(buf, numfacets); 06888 // rtBufferValidate(buf); 06889 rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host 06890 06891 for (ind=0,i=0; ind<numfacets; ind++,i+=9) { 06892 // transform to eye coordinates 06893 wtrans.multpoint3d(v + i , (float*) &trimesh[ind].v0); 06894 wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1); 06895 wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2); 06896 06897 wtrans.multnorm3d(n + i , (float*) &trimesh[ind].n0); 06898 wtrans.multnorm3d(n + i + 3, (float*) &trimesh[ind].n1); 06899 wtrans.multnorm3d(n + i + 6, (float*) &trimesh[ind].n2); 06900 } 06901 rtBufferUnmap(buf); // triangle list is complete, unmap buffer 06902 06903 RTERR( rtGeometryCreate(ctx, &geom) ); 06904 RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) ); 06905 RTERR( rtGeometrySetBoundingBoxProgram(geom, trimesh_n3f_v3f_bbox_pgm) ); 06906 RTERR( rtGeometrySetIntersectionProgram(geom, trimesh_n3f_v3f_isct_pgm) ); 06907 06908 // this buffer is associated only with this particular geometry node 06909 RTvariable buf_v; 06910 RTERR( rtGeometryDeclareVariable(geom, "trimesh_n3f_v3f_buffer", &buf_v) ); 06911 RTERR( rtVariableSetObject(buf_v, buf) ); 06912 06913 // create a geometry instance and bind materials to this geometry 06914 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 06915 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 06916 06917 set_material(instance, matindex, uniform_color); 06918 06919 append_objects(buf, geom, instance); 06920 } 06921 06922 06923 #if defined(ORT_USERTXAPIS) 06924 void OptiXRenderer::trimesh_v3f_hwtri(Matrix4 & wtrans, 06925 const float *uniform_color, 06926 const float *v, 06927 int numfacets, int matindex) { 06928 if (!context_created) return; 06929 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_v3f_hwtri: %d...\n", numfacets); 06930 trimesh_v3f_cnt += numfacets; 06931 06932 RTbuffer vbuf, nbuf, cbuf; 06933 RTgeometryinstance instance_hwtri; 06934 RTgeometrytriangles geom_hwtri; 06935 06936 // Create and fill vertex/normal/color buffers 06937 float3 *vertices; 06938 uint4 *normals; 06939 uchar4 *colors; 06940 hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 06941 cbuf, 1, colors, uniform_color); 06942 06943 int i, tcnt; 06944 for (i=0, tcnt=0; i < numfacets; i++) { 06945 int taddr = 3 * tcnt; 06946 06947 // transform to eye coordinates 06948 wtrans.multpoint3d(v + 9 * i + 0, (float*) &vertices[taddr + 0]); 06949 wtrans.multpoint3d(v + 9 * i + 3, (float*) &vertices[taddr + 1]); 06950 wtrans.multpoint3d(v + 9 * i + 6, (float*) &vertices[taddr + 2]); 06951 06952 // Compute geometric normal, detect and cull degenerate triangles 06953 float3 Ng; 06954 if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) { 06955 continue; // cull any triangle that fails degeneracy tests 06956 } 06957 06958 // Pack normal (we don't have per-vertex normals, so leave them empty) 06959 normals[i].x = packNormal(Ng); 06960 // XXX we could initialize the others for paranoia's sake... 06961 // normals[i].y = normals[i].z = normals[i].w = normals[i].x; 06962 06963 tcnt++; // count non-culled triangles 06964 } 06965 06966 rtBufferUnmap(vbuf); 06967 rtBufferUnmap(nbuf); 06968 rtBufferUnmap(cbuf); 06969 06970 RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) ); 06971 RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) ); 06972 RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 06973 0, sizeof(float3), RT_FORMAT_FLOAT3) ); 06974 #if defined(VMDOPTIXRTXRELEASEBUFS) 06975 RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) ); 06976 #else 06977 append_buffer(vbuf); 06978 #endif 06979 06980 // create a geometry instance and bind materials to this geometry 06981 RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) ); 06982 RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) ); 06983 06984 // Disable per-vertex normals, disable per-vertex colors (use uniform color) 06985 hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 0, 0); 06986 06987 // We have to pass the explicit hardware triangle parameter for this geometry 06988 set_material(instance_hwtri, matindex, uniform_color, 1); 06989 06990 // The vertex buffer is released automatically after construction. 06991 // We need to keep track of normal and color buffers for ourselves. 06992 append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri); 06993 } 06994 #endif 06995 06996 06997 void OptiXRenderer::trimesh_v3f(Matrix4 & wtrans, const float *uniform_color, 06998 const float *v, int numfacets, int matindex) { 06999 if (!context_created) return; 07000 07001 #if defined(ORT_USERTXAPIS) 07002 // OptiX RTX hardware-accelerated triangle API 07003 if (hwtri_enabled) { 07004 trimesh_v3f_hwtri(wtrans, uniform_color, v, numfacets, matindex); 07005 return; 07006 } 07007 #endif 07008 07009 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_v3f: %d...\n", numfacets); 07010 trimesh_v3f_cnt += numfacets; 07011 07012 long i, ind; 07013 RTbuffer buf; 07014 RTgeometry geom; 07015 RTgeometryinstance instance; 07016 vmd_trimesh_v3f *trimesh; 07017 07018 // create and fill the OptiX trimesh memory buffer 07019 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 07020 rtBufferSetFormat(buf, RT_FORMAT_USER); 07021 rtBufferSetElementSize(buf, sizeof(vmd_trimesh_v3f)); 07022 rtBufferSetSize1D(buf, numfacets); 07023 // rtBufferValidate(buf); 07024 rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host 07025 07026 for (ind=0,i=0; ind<numfacets; ind++,i+=9) { 07027 // transform to eye coordinates 07028 wtrans.multpoint3d(v + i , (float*) &trimesh[ind].v0); 07029 wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1); 07030 wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2); 07031 } 07032 rtBufferUnmap(buf); // triangle list is complete, unmap buffer 07033 07034 RTERR( rtGeometryCreate(ctx, &geom) ); 07035 RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) ); 07036 RTERR( rtGeometrySetBoundingBoxProgram(geom, trimesh_v3f_bbox_pgm) ); 07037 RTERR( rtGeometrySetIntersectionProgram(geom, trimesh_v3f_isct_pgm) ); 07038 07039 // this buffer is associated only with this particular geometry node 07040 RTvariable buf_v; 07041 RTERR( rtGeometryDeclareVariable(geom, "trimesh_v3f_buffer", &buf_v) ); 07042 RTERR( rtVariableSetObject(buf_v, buf) ); 07043 07044 // create a geometry instance and bind materials to this geometry 07045 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 07046 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 07047 07048 set_material(instance, matindex, uniform_color); 07049 07050 append_objects(buf, geom, instance); 07051 } 07052 07053 07054 #if defined(ORT_USERTXAPIS) 07055 void OptiXRenderer::tristrip_hwtri(Matrix4 & wtrans, int numverts, 07056 const float * cnv, 07057 int numstrips, const int *vertsperstrip, 07058 const int *facets, int matindex) { 07059 if (!context_created) return; 07060 int i; 07061 int numfacets = 0; 07062 for (i=0; i<numstrips; i++) 07063 numfacets += (vertsperstrip[i] - 2); 07064 07065 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating tristrip_hwtri: %d...\n", numfacets); 07066 tricolor_cnt += numfacets; 07067 07068 RTbuffer vbuf, nbuf, cbuf; 07069 RTgeometryinstance instance_hwtri; 07070 RTgeometrytriangles geom_hwtri; 07071 07072 // Create and fill vertex/normal/color buffers 07073 float3 *vertices; 07074 uint4 *normals; 07075 uchar4 *colors; 07076 hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 07077 cbuf, numfacets * 3, colors, NULL); 07078 07079 // render triangle strips one triangle at a time 07080 // triangle winding order is: 07081 // v0, v1, v2, then v2, v1, v3, then v2, v3, v4, etc. 07082 int strip, t, v = 0; 07083 int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} }; 07084 07085 // loop over all of the triangle strips 07086 int tcnt=0; // set triangle index to 0 07087 for (strip=0; strip < numstrips; strip++) { 07088 // loop over all triangles in this triangle strip 07089 for (t = 0; t < (vertsperstrip[strip] - 2); t++) { 07090 int taddr = 3 * tcnt; 07091 07092 // render one triangle, using lookup table to fix winding order 07093 int v0 = facets[v + (stripaddr[t & 0x01][0])] * 10; 07094 int v1 = facets[v + (stripaddr[t & 0x01][1])] * 10; 07095 int v2 = facets[v + (stripaddr[t & 0x01][2])] * 10; 07096 07097 // transform to eye coordinates 07098 wtrans.multpoint3d(cnv + v0 + 7, (float*) &vertices[taddr + 0]); 07099 wtrans.multpoint3d(cnv + v1 + 7, (float*) &vertices[taddr + 1]); 07100 wtrans.multpoint3d(cnv + v2 + 7, (float*) &vertices[taddr + 2]); 07101 07102 // Compute geometric normal, detect and cull degenerate triangles 07103 float3 Ng; 07104 if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) { 07105 v++; // move on to next vertex 07106 continue; // cull any triangle that fails degeneracy tests 07107 } 07108 07109 float3 n0, n1, n2; 07110 wtrans.multnorm3d(cnv + v0 + 4, (float*) &n0); 07111 wtrans.multnorm3d(cnv + v1 + 4, (float*) &n1); 07112 wtrans.multnorm3d(cnv + v2 + 4, (float*) &n2); 07113 07114 // Pack normals 07115 normals[tcnt].x = packNormal(Ng); 07116 normals[tcnt].y = packNormal(n0); 07117 normals[tcnt].z = packNormal(n1); 07118 normals[tcnt].w = packNormal(n2); 07119 07120 // convert color format 07121 colors[taddr + 0].x = cnv[v0 + 0] * 255.0f; 07122 colors[taddr + 0].y = cnv[v0 + 1] * 255.0f; 07123 colors[taddr + 0].z = cnv[v0 + 2] * 255.0f; 07124 07125 colors[taddr + 1].x = cnv[v1 + 0] * 255.0f; 07126 colors[taddr + 1].y = cnv[v1 + 1] * 255.0f; 07127 colors[taddr + 1].z = cnv[v1 + 2] * 255.0f; 07128 07129 colors[taddr + 2].x = cnv[v2 + 0] * 255.0f; 07130 colors[taddr + 2].y = cnv[v2 + 1] * 255.0f; 07131 colors[taddr + 2].z = cnv[v2 + 2] * 255.0f; 07132 07133 v++; // move on to next vertex 07134 tcnt++; // count non-culled triangles 07135 } 07136 v+=2; // last two vertices are already used by last triangle 07137 } 07138 07139 rtBufferUnmap(vbuf); 07140 rtBufferUnmap(nbuf); 07141 rtBufferUnmap(cbuf); 07142 07143 RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) ); 07144 RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) ); 07145 RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 07146 0, sizeof(float3), RT_FORMAT_FLOAT3) ); 07147 #if defined(VMDOPTIXRTXRELEASEBUFS) 07148 RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) ); 07149 #else 07150 append_buffer(vbuf); 07151 #endif 07152 07153 // create a geometry instance and bind materials to this geometry 07154 RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) ); 07155 RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) ); 07156 07157 // Enable per-vertex normals, enable per-vertex colors 07158 hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1); 07159 07160 // We have to pass the explicit hardware triangle parameter for this geometry 07161 set_material(instance_hwtri, matindex, NULL, 1); 07162 07163 // The vertex buffer is released automatically after construction. 07164 // We need to keep track of normal and color buffers for ourselves. 07165 append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri); 07166 } 07167 #endif 07168 07169 07170 void OptiXRenderer::tristrip(Matrix4 & wtrans, int numverts, const float * cnv, 07171 int numstrips, const int *vertsperstrip, 07172 const int *facets, int matindex) { 07173 if (!context_created) return; 07174 int i; 07175 int numfacets = 0; 07176 for (i=0; i<numstrips; i++) 07177 numfacets += (vertsperstrip[i] - 2); 07178 07179 #if defined(ORT_USERTXAPIS) 07180 // OptiX RTX hardware-accelerated triangle API 07181 if (hwtri_enabled) { 07182 tristrip_hwtri(wtrans, numverts, cnv, numstrips, 07183 vertsperstrip, facets, matindex); 07184 return; 07185 } 07186 #endif 07187 07188 if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating tristrip: %d...\n", numfacets); 07189 tricolor_cnt += numfacets; 07190 07191 RTbuffer buf; 07192 RTgeometry geom; 07193 RTgeometryinstance instance; 07194 vmd_tricolor *trimesh; 07195 07196 // create and fill the OptiX trimesh memory buffer 07197 rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf); 07198 rtBufferSetFormat(buf, RT_FORMAT_USER); 07199 rtBufferSetElementSize(buf, sizeof(vmd_tricolor)); 07200 rtBufferSetSize1D(buf, numfacets); 07201 // rtBufferValidate(buf); 07202 rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host 07203 07204 // render triangle strips one triangle at a time 07205 // triangle winding order is: 07206 // v0, v1, v2, then v2, v1, v3, then v2, v3, v4, etc. 07207 int strip, t, v = 0; 07208 int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} }; 07209 07210 // loop over all of the triangle strips 07211 i=0; // set triangle index to 0 07212 for (strip=0; strip < numstrips; strip++) { 07213 // loop over all triangles in this triangle strip 07214 for (t = 0; t < (vertsperstrip[strip] - 2); t++) { 07215 // render one triangle, using lookup table to fix winding order 07216 int v0 = facets[v + (stripaddr[t & 0x01][0])] * 10; 07217 int v1 = facets[v + (stripaddr[t & 0x01][1])] * 10; 07218 int v2 = facets[v + (stripaddr[t & 0x01][2])] * 10; 07219 07220 // transform to eye coordinates 07221 wtrans.multpoint3d(cnv + v0 + 7, (float*) &trimesh[i].v0); 07222 wtrans.multpoint3d(cnv + v1 + 7, (float*) &trimesh[i].v1); 07223 wtrans.multpoint3d(cnv + v2 + 7, (float*) &trimesh[i].v2); 07224 07225 wtrans.multnorm3d(cnv + v0 + 4, (float*) &trimesh[i].n0); 07226 wtrans.multnorm3d(cnv + v1 + 4, (float*) &trimesh[i].n1); 07227 wtrans.multnorm3d(cnv + v2 + 4, (float*) &trimesh[i].n2); 07228 07229 vec_copy((float*) &trimesh[i].c0, cnv + v0); 07230 vec_copy((float*) &trimesh[i].c1, cnv + v1); 07231 vec_copy((float*) &trimesh[i].c2, cnv + v2); 07232 07233 v++; // move on to next vertex 07234 i++; // next triangle 07235 } 07236 v+=2; // last two vertices are already used by last triangle 07237 } 07238 rtBufferUnmap(buf); // triangle list is complete, unmap buffer 07239 07240 RTERR( rtGeometryCreate(ctx, &geom) ); 07241 RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) ); 07242 RTERR( rtGeometrySetBoundingBoxProgram(geom, tricolor_bbox_pgm) ); 07243 RTERR( rtGeometrySetIntersectionProgram(geom, tricolor_isct_pgm) ); 07244 07245 // this buffer is associated only with this particular geometry node 07246 RTvariable buf_v; 07247 RTERR( rtGeometryDeclareVariable(geom, "tricolor_buffer", &buf_v) ); 07248 RTERR( rtVariableSetObject(buf_v, buf) ); 07249 07250 // create a geometry instance and bind materials to this geometry 07251 RTERR( rtGeometryInstanceCreate(ctx, &instance) ); 07252 RTERR( rtGeometryInstanceSetGeometry(instance, geom) ); 07253 07254 set_material(instance, matindex, NULL); 07255 07256 append_objects(buf, geom, instance); 07257 } 07258 07259 07260 #if !defined(VMDOPENGL) 07261 // A hack to prevent VMD from having to be linked to libGL.so to resolve 07262 // OptiX dependencies for OpenGL interop, e.g. when compiling on 07263 // a supercomputer/cluster lacking OpenGL support (e.g. ORNL Titan): 07264 // 07265 // Linking vmd_LINUXAMD64 ... 07266 // /usr/lib64/libGL.so.1: undefined reference to `xcb_glx_set_client_info_arb' 07267 // /usr/lib64/libGL.so.1: undefined reference to `xcb_glx_create_context_attribs_arb_checked' 07268 // /usr/lib64/libGL.so.1: undefined reference to `xcb_glx_set_client_info_2arb' 07269 // /usr/bin/ld: link errors found, deleting executable `vmd_LINUXAMD64' 07270 // collect2: error: ld returned 1 exit status 07271 // make: *** [vmd_LINUXAMD64] Error 1 07272 // 07273 extern "C" { 07274 typedef struct { 07275 unsigned int sequence; 07276 } xcb_void_cookie_t; 07277 static xcb_void_cookie_t fake_cookie = { 0 }; 07278 xcb_void_cookie_t xcb_glx_set_client_info_arb(void) { 07279 return fake_cookie; 07280 } 07281 xcb_void_cookie_t xcb_glx_create_context_attribs_arb_checked(void) { 07282 return fake_cookie; 07283 } 07284 xcb_void_cookie_t xcb_glx_set_client_info_2arb(void) { 07285 return fake_cookie; 07286 } 07287 } 07288 #endif 07289 07290 07291