Tachyon (current)  Current Main Branch
knot.cpp
Go to the documentation of this file.
1 /*
2  * knot.cpp - Knot plotting example scene.
3  *
4  * (C) Copyright 2013-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: knot.cpp,v 1.8 2022/04/04 05:01:24 johns Exp $
8  *
9  */
10 
17 //
18 // Knot plotting example
19 // John E. Stone, Dec 2021
20 //
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include "ProfileHooks.h"
27 
28 #define STB_IMAGE_WRITE_IMPLEMENTATION
29 #include "stb_image_write.h"
30 
31 #include "TachyonOptiX.h"
32 
33 #if defined(TACHYON_USEPINNEDMEMORY)
34 #include <cuda_runtime.h>
35 #endif
36 
37 
38 // http://katlas.org/wiki/36_Torus_Knots
39 // https://www.maa.org/sites/default/files/images/upload_library/23/stemkoski/knots/page5.html
40 float * pq_torus_knot(int p, int q, int points) {
41  float * coords = (float *) malloc(points * 3 * sizeof(float));
42 
43  int i;
44  for (i=0; i<points; i++) {
45  float theta = 2.0f * M_PI * float(i) / float(points);
46  float r = 2.0f + cos(p * theta);
47  int ind = 3*i;
48  coords[ind ] = r * cos(q * theta); // X
49  coords[ind + 1] = r * sin(q * theta); // Y
50  coords[ind + 2] = -sin(p * theta); // Z
51  }
52 
53  return coords;
54 }
55 
56 
57 void HSItoRGB(float h, float s, float i, float &r, float &g, float &b) {
58  float t=2.0f * M_PI * h;
59  float scale = i / 2.0f;
60  r=(1.0f + s*sin(t - 2.0f*M_PI/3.0f)) * scale;
61  g=(1.0f + s*sin(t)) * scale;
62  b=(1.0f + s*sin(t + 2.0f*M_PI/3.0f)) * scale;
63 }
64 
65 
66 float *knot_colors(int numpts) {
67  float *colors = (float *) malloc(numpts * 3 * sizeof(float));
68 
69  for (int i=0; i<numpts; i++) {
70  int ind = i * 3;
71  float h = float(i) / float(numpts);
72  float s = 1.0f;
73  float l = (fmodf(h*40.0f, 1.0f) > 0.5f) ? 0.85f : 0.35f;
74  HSItoRGB(h, s, l, colors[ind], colors[ind + 1], colors[ind + 2]);
75  }
76 
77  return colors;
78 }
79 
80 
81 //
82 // Draw the knot geometry using an array of spheres
83 //
84 void gen_knot(TachyonOptiX *rt, float *coords, float *colors,
85  int numpts, float radius, int mat) {
86 
87  SphereArray spheres;
88  spheres.center.resize(numpts);
89  spheres.radius.resize(numpts);
90  spheres.primcolors3f.resize(numpts);
91 
92  float3 *verts = spheres.center.data();
93  float *radii = spheres.radius.data();
94  float3 *cols = spheres.primcolors3f.data();
95 
96  memcpy(verts, coords, numpts * 3 * sizeof(float));
97  memcpy(cols, colors, numpts * 3 * sizeof(float));
98  for (int i=0; i<numpts; i++)
99  radii[i]=radius;
100 
101  rt->add_spherearray(spheres, mat);
102 }
103 
104 
105 //
106 // Draw a quad or triangle mesh for the floor
107 //
108 void gen_floor(TachyonOptiX *rt, float width, float height, float length, int mat) {
109  float vertex[] = {
110  -100.0f, 4.0f, -100.0f,
111  -100.0f, 4.0f, 100.0f,
112  100.0f, 4.0f, -100.0f,
113  100.0f, 4.0f, 100.0f
114  };
115  float color[] = {
116  1.0f, 1.0f, 1.0f, 1.0f,
117  1.0f, 1.0f, 1.0f, 1.0f,
118  1.0f, 1.0f, 1.0f, 1.0f,
119  1.0f, 1.0f, 1.0f, 1.0f
120  };
121  int index[] = {
122  0, 1, 2, // triangle-1
123  1, 2, 3 // triangle-2
124  };
125 
126  vertex[ 0] = -width / 2.0f;
127  vertex[ 3] = -width / 2.0f;
128  vertex[ 6] = width / 2.0f;
129  vertex[ 9] = width / 2.0f;
130 
131  vertex[ 1] = height;
132  vertex[ 4] = height;
133  vertex[ 7] = height;
134  vertex[10] = height;
135 
136  vertex[ 2] = -length / 2.0f;
137  vertex[ 5] = length / 2.0f;
138  vertex[ 8] = -length / 2.0f;
139  vertex[11] = length / 2.0f;
140 
141  TriangleMesh mesh;
142  mesh.vertices.resize(4);
143  mesh.vertcolors3f.resize(4);
144  mesh.indices.resize(2*3);
145 
146  float3 *verts = mesh.vertices.data();
147  float3 *cols = mesh.vertcolors3f.data();
148  int3 *indices = mesh.indices.data();
149 
150  memcpy(verts, vertex, 4 * 3 * sizeof(float));
151  memcpy(cols, color, 4 * 3 * sizeof(float));
152  memcpy(indices, index, 2 * 3 * sizeof(int));
153 
154  rt->add_trimesh(mesh, mat);
155 }
156 
157 
158 int main(int argc, const char **argv) {
159  // some sane defaults
160  int imgSize[2] = {4096, 4096 }; // W x H
161  int numpts = 1000;
162  int p = 5;
163  int q = 3;
164 
165  //
166  // parse args
167  //
168  if (argc == 1) {
169  printf("Usage: %s P Q\n", argv[0]);
170  printf(" Knot params P and Q control the knot type generated.\n");
171  printf("Using defaults, P=5 and Q=3\n");
172  // return -1;
173  }
174 
175  if (argc > 2) {
176  p = atoi(argv[1]);
177  q = atoi(argv[2]);
178  }
179  if (argc > 3) {
180  numpts = atoi(argv[3]);
181  }
182 
183 
184  //
185  // camera defaults
186  //
187 #if 0
188  float cam_pos[] = {-2.0f, 0.0f, -8.0f}; // look at origin from -Z
189  float cam_up[] = {0.0f, 1.0f, 0.0f}; // Y-up
190  float cam_view[3];
191 
192  // look at origin
193  float invlen = 1.0f / sqrtf(cam_pos[0]*cam_pos[0] +
194  cam_pos[1]*cam_pos[1] +
195  cam_pos[2]*cam_pos[2]);
196  cam_view[0] = -cam_pos[0] * invlen;
197  cam_view[1] = -cam_pos[1] * invlen;
198  cam_view[2] = -cam_pos[2] * invlen;
199 #endif
200 
201 
202 
203  //
204  // Build scene
205  //
206  printf("Calculating knot, p: %d, q: %d, points: %d\n", p, q, numpts);
207  float *coords = pq_torus_knot(p, q, numpts);
208  float *colors = knot_colors(numpts);
209 
210 
211  PROFILE_PUSH_RANGE("Initialize Tachyon", 0);
212  printf("Initializing TachyonOptiX...");
213 
216  unsigned int devcount = TachyonOptiX::device_count();
217  unsigned int optixversion = TachyonOptiX::optix_version();
218 
219  printf("Found %u OptiX devices\n", devcount);
220  printf("OptiX version used for build: %d.%d.%d (%u)\n",
221  optixversion/10000,
222  (optixversion%10000)/100,
223  (optixversion%100),
224  optixversion);
225 
226  TachyonOptiX *rt = new TachyonOptiX();
228 
229  PROFILE_PUSH_RANGE("Build Scene", 0);
230 
231  // create and setup camera
233  rt->framebuffer_resize(imgSize[0], imgSize[1]);
234 // rt->set_verbose_mode(TachyonOptiX::RT_VERB_MIN);
235 // rt->set_verbose_mode(TachyonOptiX::RT_VERB_DEBUG);
236  float rtbgcolor[] = { 1.0, 1.0, 1.0 };
237  float rtbggradtopcolor[] = { 0.6, 0.0, 0.0 };
238  float rtbggradbotcolor[] = { 0.0, 0.0, 0.6 };
239 
240  rt->set_bg_color(rtbgcolor);
241  rt->set_bg_color_grad_top(rtbggradtopcolor);
242  rt->set_bg_color_grad_bot(rtbggradbotcolor);
243 
244  float bggradient[] = { 0.0f, 1.0f, 0.0f };
245  rt->set_bg_gradient(bggradient);
246  rt->set_bg_gradient_topval(1.0f);
247  rt->set_bg_gradient_botval(-1.0f);
248 
249 // rt->set_bg_mode(TachyonOptiX::RT_BACKGROUND_TEXTURE_SOLID);
251 // rt->set_bg_mode(TachyonOptiX::RT_BACKGROUND_TEXTURE_SKY_SPHERE);
252 
253  rt->set_aa_samples(16);
254  rt->shadows_enable(1);
255 
256  //
257  // Optionally add AO
258  //
259 #if 1
260  rt->set_ao_samples(16);
261  rt->set_ao_ambient(0.9);
262  rt->set_ao_direct(0.2);
263  rt->set_ao_maxdist(100.2);
264 #endif
265 
266  rt->camera_dof_enable(0);
267 
268 
269  float lightdir0[] = { -0.5f, 0.5f, -1.0f };
270  float lightcolor0[] = { 1.0f, 1.0f, 1.0f };
271  rt->add_directional_light(lightdir0, lightcolor0);
272 
273  // set camera params
275 // rt->set_camera_type(TachyonOptiX::RT_ORTHOGRAPHIC);
276 
277  float campos[3] = {0.0f, 10.0f, 12.0f};
278 // float camU[3] = {1.0f, 0.0f, 0.0f};
279  float camV[3] = {0.0f, 1.0f, 0.0f};
280 // float camW[3] = {0.0f, 0.0f, 1.0f};
281  float camat[3] = {0.0f, 0.0f, 0.0f};
282 
283  rt->set_camera_pos(campos);
284 // rt->set_camera_ONB(camU, camV, camW);
285  rt->set_camera_lookat(camat, camV);
286 
287  rt->set_camera_zoom(0.5f);
288  rt->set_camera_dof_fnumber(64.0f);
289  rt->set_camera_dof_focal_dist(0.7f);
290  // set stereoscopic display parameters
291  rt->set_camera_stereo_eyesep(0.6f);
293 
294  // set depth cueing parameters
295  float start = 1.0f;
296  float end = 30.0f;
297  float density = 0.33f;
298 // rt->set_cue_mode(TachyonOptiX::RT_FOG_LINEAR, start, end, density);
299 // rt->set_cue_mode(TachyonOptiX::RT_FOG_EXP, start, end, density);
300 // rt->set_cue_mode(TachyonOptiX::RT_FOG_EXP2, start, end, density);
301  rt->set_cue_mode(TachyonOptiX::RT_FOG_NONE, start, end, density);
302 
303 
304  //
305  // Set the material rendering parameters
306  //
307  int mat = 0;
308  int mat2 = 1;
309  float ambient = 0.0f;
310  float diffuse = 0.7f;
311  float specular = 0.0f;
312  float shininess = 0.0f;
313  float reflectivity = 0.0f;
314  float opacity = 1.0f;
315  float outline = 0.0f;
316  float outlinewidth = 0.0f;
317  int transmode = 0;
318 
319  rt->add_material(ambient, diffuse, specular, shininess, reflectivity,
320  opacity, outline, outlinewidth, transmode, mat);
321 
322  rt->add_material(ambient, diffuse, specular, shininess, reflectivity,
323  opacity, outline, outlinewidth, transmode, mat2);
325 
327 #if 1
328  PROFILE_PUSH_RANGE("Renderer Warmup Passes", 0);
329  // force warmup passes on an empty scene so our timings of subsequent
330  // scene data are way more realistic
331  for (int w=0; w<100; w++) {
332  rt->render();
333  rt->framebuffer_clear();
334  }
336 #endif
338 
339  PROFILE_PUSH_RANGE("Generate Scene", 0);
340  gen_knot(rt, coords, colors, numpts, 0.33f, mat);
341  gen_floor(rt, 200.0f, -3.5f, 200.0f, mat2);
343 
344 
345  char filename[1024];
346  sprintf(filename, "knot-%d-%d.png", p, q);
347  printf("rendering 100 accumulated frames to '%s'...\n", filename);
348 
349  PROFILE_PUSH_RANGE("Render Scene", 0);
350 
351  // render 100 accumulated frames
352 // const char *statestr = "|/-\\.";
353 // int state=0;
354 // for (int frames = 0; frames < 100; frames++,state=(state+1) & 3) {
355 
356  rt->render();
357 
358 // printf("%c\r", statestr[state]);
359 // fflush(stdout);
360 // }
361 // printf("\n");
362 
364 
365  rt->print_raystats_info();
366 
367  PROFILE_PUSH_RANGE("Write Output Image", 0);
368 
369  // access frame and write its content as PNG file
370  if (filename != NULL) {
371  rt->framebuffer_get_size(imgSize[0], imgSize[1]);
372  size_t bufsz = imgSize[0] * imgSize[1] * sizeof(int);
373  unsigned char *rgb4u = (unsigned char *) calloc(1, bufsz);
374  rt->framebuffer_download_rgb4u(rgb4u);
375 
376 #if 0
377  if (writealpha) {
378 printf("Writing rgba4u alpha channel output image 2\n");
379  if (write_image_file_rgba4u(filename, rgb4u, imgSize[0], imgSize[1]))
380  printf("Failed to write image '%s'!!\n", filename);
381  } else {
382  if (write_image_file_rgb4u(filename, rgb4u, imgSize[0], imgSize[1]))
383  printf("Failed to write image '%s'!!\n", filename);
384  }
385 #else
387 
388  stbi_write_png(filename, imgSize[0], imgSize[1], 4, rgb4u, imgSize[0] * sizeof(int));
389 #endif
390 
391  free(rgb4u);
392  }
393 
394  free(coords);
395  free(colors);
396 
397  delete rt;
398 
400 
401  return 0;
402 }
403 
404 
STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean)
void set_ao_maxdist(float dist)
set AO maximum occlusion distance
std::vector< float3 PINALLOCS(float3)> center
Definition: TachyonOptiX.h:245
void set_bg_gradient_topval(float v)
set background gradient "top" value (view direction dot product)
float * pq_torus_knot(int p, int q, int points)
Definition: knot.cpp:40
void set_ao_samples(int cnt)
ambient occlusion (samples > 1 == on)
void framebuffer_get_size(int &fbwidth, int &fbheight)
void add_directional_light(const float *dir, const float *color)
int add_material(float ambient, float diffuse, float specular, float shininess, float reflectivity, float opacity, float outline, float outlinewidth, int transmode, int userindex)
add a material with an associated user-provided index
CPU and GPU profiling utility macros/routines.
#define PROFILE_PUSH_RANGE(name, cid)
Pushes a time range annotation onto the profiler&#39;s trace stack, beginning at the time of submission...
Definition: ProfileHooks.h:275
std::vector< float PINALLOCS(float)> radius
Definition: TachyonOptiX.h:246
void framebuffer_resize(int fbwidth, int fbheight)
void camera_dof_enable(int onoff)
depth of field on/off
static int device_count(void)
static GPU device query
void set_camera_lookat(const float *at, const float *V)
set camera orientation to look "at" a point in space, with a given "up" direction (camera ONB "V" vec...
#define M_PI
void print_raystats_info(void)
report performance statistics
std::vector< float3 PINALLOCS(float3) > vertices
Definition: TachyonOptiX.h:286
Adobe sRGB (gamma 2.2)
Output timing/perf data only.
Definition: TachyonOptiX.h:649
void set_ao_direct(float aod)
set AO direct lighting rescale factor
void HSItoRGB(float h, float s, float i, float &r, float &g, float &b)
Definition: knot.cpp:57
void framebuffer_clear(void)
void set_bg_gradient(float *vec)
set world "up" direction for background gradient
void add_spherearray(SphereArray &model, int matidx)
conventional perspective
Definition: TachyonOptiX.h:638
No console output.
Definition: TachyonOptiX.h:648
std::vector< float3 PINALLOCS(float3) > vertcolors3f
Definition: TachyonOptiX.h:290
#define PROFILE_POP_RANGE()
Pops the innermost time range off of the profiler&#39;s trace stack, at the time of execution.
Definition: ProfileHooks.h:279
void set_camera_zoom(float zoomfactor)
set camera zoom factor
void set_camera_dof_fnumber(float n)
set depth of field f/stop number
float * knot_colors(int numpts)
Definition: knot.cpp:66
void set_bg_color_grad_bot(float *rgb)
set color for "bottom" of background gradient
void set_camera_type(CameraType m)
set the camera projection mode
void framebuffer_download_rgb4u(unsigned char *imgrgb4u)
void set_camera_stereo_convergence_dist(float dist)
set stereo convergence distance
void shadows_enable(int onoff)
enable/disable shadows
void set_bg_color(float *rgb)
set solid background color
void set_ao_ambient(float aoa)
set AO ambient lighting factor
void set_aa_samples(int cnt)
antialiasing (samples > 1 == on)
void set_cue_mode(FogMode mode, float start, float end, float density)
set depth cueing mode and parameters
void set_bg_gradient_botval(float v)
set background gradient "bottom" value (view direction dot product)
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes)
void set_verbose_mode(TachyonOptiX::Verbosity mode)
programmatically set verbosity
void set_bg_color_grad_top(float *rgb)
set color for "top" of background gradient
void gen_knot(TachyonOptiX *rt, float *coords, float *colors, int numpts, float radius, int mat)
Definition: knot.cpp:84
__host__ __device__ float length(const float3 &v)
void set_camera_pos(const float *pos)
set the camera position
static unsigned int optix_version(void)
static OptiX version query
std::vector< int3 PINALLOCS(int3) > indices
Definition: TachyonOptiX.h:287
int main(int argc, const char **argv)
Definition: knot.cpp:158
void set_camera_stereo_eyesep(float eyesep)
set stereo eye separation
void gen_floor(TachyonOptiX *rt, float width, float height, float length, int mat)
Definition: knot.cpp:108
void framebuffer_colorspace(int colspace)
Tachyon ray tracing host side routines and internal APIs that provide the core ray OptiX-based RTX-ac...
void set_bg_mode(BGMode m)
set background rendering mode
void set_camera_dof_focal_dist(float d)
set depth of field focal plane distance
std::vector< float3 PINALLOCS(float3)> primcolors3f
Definition: TachyonOptiX.h:247
void add_trimesh(TriangleMesh &model, int matidx)