diff --git a/.gitignore b/.gitignore index 11c9714..9234d82 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,28 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake +#Files created by the CI scripts (downloading and installing premake) +premake5 +premake5.tar.gz + +#built examples +/examples/raytrace/bin/ + +#visual studio files +*.sln +*.vcxproj* +.vs + +#binary directories +bin/ +obj/ + +#runtime gui config +imgui.ini + +#visual stuido code +.vscode + # Prerequisites *.d diff --git a/.travis-before-install.sh b/.travis-before-install.sh new file mode 100755 index 0000000..ea6615a --- /dev/null +++ b/.travis-before-install.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +if [[ "$TRAVIS_OS_NAME" == "osx" ]] +then + brew upgrade + curl -o premake5.tar.gz https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-macosx.tar.gz +else + wget https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-linux.tar.gz -O premake5.tar.gz +fi +tar xzf premake5.tar.gz diff --git a/.travis.yml b/.travis.yml index 08acd20..6e731e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ matrix: env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0" before_install: -- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew upgrade; fi + - ./.travis-before-install.sh script: @@ -42,3 +42,6 @@ script: - ${CC} -v - ${CXX} ${EXTRA_CXXFLAGS} -std=c++11 -Wall -g -o loader_example loader_example.cc - ./loader_example ./models/Cube/Cube.gltf + - cd examples/raytrace + - ../../premake5 gmake + - make diff --git a/appveyor.yml b/appveyor.yml index 8a027f8..545253e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,3 +13,6 @@ configuration: Release build: parallel: true project: TinyGLTFSolution.sln + +after_build: + - examples.bat diff --git a/examples.bat b/examples.bat new file mode 100644 index 0000000..11e35e7 --- /dev/null +++ b/examples.bat @@ -0,0 +1,3 @@ + cd examples\raytrace + ..\..\tools\windows\premake5.exe vs2015 + msbuild NanoSGSolution.sln /property:Configuration=Release diff --git a/examples/raytrace/README.md b/examples/raytrace/README.md index 7436d3e..477935d 100644 --- a/examples/raytrace/README.md +++ b/examples/raytrace/README.md @@ -1,31 +1,128 @@ -# Raytrace example +# NanoSG -Simple raytracing example with OpenGL preview +Simple, minimal and header-only scene graph library for NanoRT. -## Status +NanoSG itself shoud be compiled with C++-03 compiler, but demo code uses C++11 features. -Not working yet. Still in work in progress. +![screenshot of the demo program](images/nanosg-demo.png) + +![Animation showing node manipulation](https://media.giphy.com/media/l3JDO29fMFndyObHW/giphy.gif) ## Build ### Linux or macOS -``` -$ premake5 gmake -$ make +```bash +premake5 gmake +make ``` ### Windows -``` -$ premake5 vs2015 +```bash +premake5 vs2015 ``` +## Data structure -## Third party libraries and its icenses. +### Node + +Node represents scene graph node. Tansformation node or Mesh(shape) node. +Node is interpreted as transformation node when passing `nullptr` to Node class constructure. + +Node can contain multiple children. + +### Scene + +Scene contains root nodes and provides the method to find an intersection of nodes. + +## User defined data structure + +Following are required in user application. + +### Mesh class + +Current example code assumes mesh is all composed of triangle meshes. + +Following method must be implemented for `Scene::Traversal`. + +```cpp +/// +/// Get the geometric normal and the shading normal at `face_idx' th face. +/// +template +void GetNormal(T Ng[3], T Ns[3], const unsigned int face_idx, const T u, const T v) const; +``` + +### Intersection class + +Represents intersection(hit) information. + +### Transform + +Transformation is done in the following procedure. + +`M' = parent_xform x local_xform x local_pivot` + +## Memory management + +`Scene` and `Node` does not create a copy of asset data(e.g. vertices, indices). Thus user must care about memory management of scene assets in user side. + +## API + +API is still subject to change. + +### Node + +```cpp +void Node::SetName(const std::string &name); +``` + +Set (unique) name for the node. + +```cpp +void Node::AddChild(const type &child); +``` + +Add node as child node. + +```cpp +void Node::SetLocalXform(const T xform[4][4]) { +``` + +Set local transformation matrix. Default is identity matrix. + +### Scene + +```cpp +bool Scene::AddNode(const Node &node); +``` + +Add a node to the scene. + +```cpp +bool Scene::Commit() { +``` + +Commit the scene. After adding nodes to the scene or changed transformation matrix, call this `Commit` before tracing rays. +`Commit` triggers BVH build in each nodes and updates node's transformation matrix. + +```cpp +template +bool Scene::Traverse(nanort::Ray &ray, H *isect, const bool cull_back_face = false) const; +``` + +Trace ray into the scene and find an intersection. +Returns `true` when there is an intersection and hit information is stored in `isect`. + +## TODO + +* [ ] Compute pivot point of each node(mesh). + +## Third party libraries and its icenses * picojson : BSD license. -* bt3gui : zlib license. +* bt3gui : zlib license. * glew : BSD/MIT license. * tinyobjloader : MIT license. * glm : The Happy Bunny License (Modified MIT License). Copyright (c) 2005 - 2017 G-Truc Creation diff --git a/examples/raytrace/config.json b/examples/raytrace/config.json index e2dcf67..e78c54c 100644 --- a/examples/raytrace/config.json +++ b/examples/raytrace/config.json @@ -1,9 +1,23 @@ -{ "gltf_filename" : "../../models/Cube/Cube.gltf", - "scene_scale" : 1.0, - "width" : 512, - "height" : 512, - "eye" : [0, 2.5, 15], - "up" : [0, 1, 0], - "look_at" : [0, 0, 0], - "dummy" : 0 +{ + "commented_out_obj_filename": "cornellbox_suzanne.obj", + "gltf_filename": "../../models/Cube/Cube.gltf", + "scene_scale": 1.0, + "width": 512, + "height": 512, + "eye": [ + 0, + 2.5, + 15 + ], + "up": [ + 0, + 1, + 0 + ], + "look_at": [ + 0, + 0, + 0 + ], + "dummy": 0 } diff --git a/examples/raytrace/cornellbox_suzanne.obj b/examples/raytrace/cornellbox_suzanne.obj new file mode 100644 index 0000000..ad96197 --- /dev/null +++ b/examples/raytrace/cornellbox_suzanne.obj @@ -0,0 +1,1529 @@ +# Blender v2.67 (sub 0) OBJ File: 'cornellbox.blend' +# www.blender.org +mtllib cornellbox_suzanne.mtl +o ceil_Plane.005 +v -5.060082 9.574966 -4.955276 +v 4.658843 9.574966 -4.955276 +v -5.060082 9.574966 4.763649 +v 4.658843 9.574966 4.763649 +usemtl None +s off +f 2 1 3 4 +o left_Plane.004 +v -4.971709 -0.000988 -4.950935 +v -5.028017 9.717773 -4.950935 +v -4.971709 -0.000988 4.767989 +v -5.028017 9.717773 4.767989 +usemtl None +s off +f 6 5 7 8 +o right_Plane.003 +v 4.547822 -0.031673 -4.932439 +v 4.491515 9.687088 -4.932439 +v 4.547822 -0.031673 4.786486 +v 4.491515 9.687088 4.786486 +usemtl None +s off +f 10 9 11 12 +o back_Plane.002 +v -5.109836 9.772833 -4.479764 +v 4.609088 9.772833 -4.479764 +v -5.109836 0.056570 -4.707224 +v 4.609088 0.056570 -4.707224 +usemtl None +s off +f 14 13 15 16 +o lightobj_Plane.001 +v -1.964923 8.501755 -2.347890 +v 1.555262 8.501755 -2.347890 +v -1.964923 8.501755 1.207072 +v 1.555262 8.501755 1.207072 +usemtl None +s off +f 18 17 19 20 +o floor_Plane +v -5.144927 0.117050 -4.948757 +v 4.573997 0.117050 -4.948757 +v -5.144927 0.117050 4.770167 +v 4.573997 0.117050 4.770167 +usemtl None +s off +f 22 21 23 24 +o suzanne_tri +v 0.871029 1.442251 -0.053177 +v 0.873030 1.370656 -0.008330 +v 0.878278 1.279165 -0.089297 +v 0.876081 1.414948 -0.177287 +v 0.192109 1.279165 0.638144 +v 0.272632 1.370656 0.628181 +v 0.227745 1.442251 0.628799 +v 0.104140 1.414948 0.641084 +v 0.844029 1.207378 -0.186042 +v 0.843525 1.380200 -0.293914 +v 0.093531 1.207378 0.609597 +v -0.014187 1.380200 0.615388 +v 0.812424 1.229832 0.052639 +v 0.755010 1.145711 -0.001518 +v 0.272547 1.145711 0.509965 +v 0.329961 1.229832 0.564121 +v 0.832062 1.345989 0.071162 +v 0.349599 1.345989 0.582645 +v 0.782010 1.380584 0.131347 +v 0.712293 1.296540 0.162243 +v 0.433536 1.296540 0.457766 +v 0.406761 1.380584 0.529167 +v 0.624492 1.229716 0.143861 +v 0.410064 1.229717 0.371187 +v 0.635102 1.437287 0.175349 +v 0.532940 1.409984 0.164901 +v 0.425726 1.409984 0.278564 +v 0.442117 1.437287 0.379942 +v 0.742512 1.454661 0.137049 +v 0.410148 1.454661 0.489403 +v 0.744094 1.536146 0.095582 +v 0.643682 1.578034 0.097525 +v 0.364926 1.578034 0.393048 +v 0.368844 1.536146 0.493402 +v 0.536020 1.592696 0.060409 +v 0.321592 1.592696 0.287735 +v 0.714925 1.629850 -0.039329 +v 0.630427 1.656845 -0.119032 +v 0.147964 1.656845 0.392450 +v 0.232462 1.629850 0.472153 +v 0.779701 1.560813 0.021772 +v 0.297238 1.560813 0.533255 +v 0.835113 1.526218 -0.044096 +v 0.809668 1.560659 -0.154015 +v 0.123498 1.560659 0.573426 +v 0.234715 1.526218 0.592416 +v 0.755557 1.570357 -0.269494 +v 0.005059 1.570357 0.526145 +v 0.849446 1.538590 -0.041316 +v 0.887167 1.447215 -0.048694 +v 0.238326 1.538590 0.606561 +v 0.233161 1.447215 0.644648 +v 0.792256 1.583075 0.033615 +v 0.309793 1.583075 0.545097 +v 0.753093 1.551000 0.114811 +v 0.388566 1.551000 0.501264 +v 0.747956 1.462107 0.163664 +v 0.437036 1.462107 0.493286 +v 0.794621 1.380622 0.153982 +v 0.430093 1.380622 0.540436 +v 0.851839 1.338620 0.089817 +v 0.369376 1.338620 0.601300 +v 0.890974 1.368212 -0.002145 +v 0.279854 1.368212 0.645733 +v 0.839116 1.464589 0.077817 +v 0.356653 1.464589 0.589299 +v 0.812437 0.229518 0.288924 +v 0.846574 0.291378 0.342604 +v 0.742999 0.279044 0.470439 +v 0.708918 0.222149 0.438291 +v 0.621425 0.291378 0.581296 +v 0.565844 0.229518 0.550348 +v 0.887318 0.241813 0.155503 +v 0.891210 0.306193 0.288050 +v 0.569568 0.306193 0.629038 +v 0.437020 0.241813 0.632887 +v 0.906872 0.296149 0.120249 +v 0.912541 0.405014 0.265212 +v 0.548013 0.405014 0.651665 +v 0.402966 0.296150 0.654463 +v 0.877955 0.493753 0.114452 +v 0.890902 0.523576 0.266280 +v 0.547817 0.523576 0.630001 +v 0.395492 0.493753 0.625934 +v 0.791569 0.738209 0.086665 +v 0.820681 0.775478 0.253742 +v 0.531204 0.775478 0.560632 +v 0.362713 0.738209 0.541316 +v 0.653352 0.972774 0.106646 +v 0.781785 1.007292 -0.094398 +v 0.830312 1.140862 0.005074 +v 0.752323 1.133685 0.307398 +v 0.283520 1.140862 0.584754 +v 0.181387 1.007292 0.542113 +v 0.374596 0.972774 0.402170 +v 0.580780 1.133685 0.489259 +v 0.897719 1.106075 -0.253534 +v 0.924607 1.222270 -0.206692 +v 0.077617 1.222270 0.691243 +v 0.029286 1.106075 0.667134 +v 0.923739 1.254076 -0.497483 +v 0.949185 1.355571 -0.333864 +v -0.047905 1.355571 0.723199 +v -0.212729 1.254076 0.707342 +v 0.982568 1.567914 -0.484951 +v 0.957906 1.535916 -0.347118 +v -0.060627 1.535916 0.732678 +v -0.196786 1.567914 0.765339 +v 0.889630 1.629696 -0.368561 +v 0.959851 1.595293 -0.270105 +v 0.016368 1.595293 0.730127 +v -0.086017 1.629696 0.665770 +v 0.755557 1.760668 -0.194316 +v 0.806113 1.743563 -0.071451 +v 0.205714 1.743563 0.565060 +v 0.080109 1.760668 0.521759 +v 0.633843 1.923716 -0.072852 +v 0.725619 1.844866 0.024457 +v 0.296763 1.844866 0.479108 +v 0.194266 1.923716 0.393166 +v 0.546462 1.894123 0.070259 +v 0.666763 1.827607 0.119296 +v 0.388006 1.827607 0.414819 +v 0.332034 1.894123 0.297584 +v 0.529106 1.676817 0.182764 +v 0.635018 1.647339 0.228968 +v 0.495640 1.647339 0.376730 +v 0.443335 1.676817 0.273694 +v 0.495276 1.615073 0.236771 +v 0.567218 1.565816 0.304631 +v 0.633017 1.610185 0.141163 +v 0.668568 1.657075 0.056561 +v 0.325483 1.657075 0.420281 +v 0.407867 1.610185 0.379855 +v 0.709592 1.659519 -0.012140 +v 0.259293 1.659519 0.465244 +v 0.772143 1.615034 -0.092754 +v 0.182466 1.615034 0.532391 +v 0.866802 1.538398 -0.239739 +v 0.041254 1.538398 0.635464 +v 0.900883 1.459356 -0.261289 +v 0.021729 1.459356 0.670745 +v 0.915440 1.355648 -0.226080 +v 0.057728 1.355648 0.683222 +v 0.869363 1.244570 -0.086968 +v 0.193914 1.244570 0.629108 +v 0.821340 1.210052 0.028830 +v 0.306713 1.210052 0.574411 +v 0.712293 1.296540 0.162243 +v 0.433536 1.296540 0.457766 +v 0.680045 1.343468 0.185523 +v 0.572970 1.247129 0.310057 +v 0.454895 1.343468 0.424214 +v 0.626102 1.503995 0.188339 +v 0.454560 1.503995 0.370199 +v 0.561997 1.415102 0.299707 +v 0.647741 1.412620 0.198010 +v 0.465477 1.412620 0.391237 +v 0.809161 0.355680 0.446930 +v 0.762693 0.345791 0.489015 +v 0.723390 0.355680 0.537860 +v 0.846631 0.405091 0.407095 +v 0.685809 0.405091 0.577589 +v 0.830353 0.523653 0.402481 +v 0.680253 0.523653 0.561609 +v 0.756493 0.787888 0.375770 +v 0.828491 0.553284 0.389985 +v 0.667670 0.553284 0.560479 +v 0.649279 0.787888 0.489433 +v 0.720354 0.933561 0.330942 +v 0.670414 0.896522 0.401972 +v 0.702886 0.787888 0.432602 +v 0.602419 0.933561 0.455971 +v 0.746275 0.560692 0.473529 +v 0.766136 0.479207 0.492263 +v 0.738102 0.995305 0.293985 +v 0.775795 1.010197 0.318799 +v 0.749047 0.960786 0.347268 +v 0.620390 0.960786 0.483663 +v 0.593531 1.010197 0.512026 +v 0.566560 0.995305 0.475845 +v 0.698576 1.066900 0.288920 +v 0.727269 1.094126 0.305245 +v 0.577169 1.094126 0.464373 +v 0.559197 1.066900 0.436681 +v 0.627081 1.074308 0.361098 +v 0.677217 1.101533 0.354690 +v 0.623610 1.101533 0.411522 +v 0.645109 1.024936 0.378102 +v 0.675635 1.047236 0.406897 +v 0.695552 0.916340 0.425684 +v 0.749075 0.990456 0.368773 +v 0.704496 0.953417 0.434120 +v 0.641861 0.990456 0.482436 +v 0.700801 1.042348 0.430635 +v 0.709549 1.089238 0.374448 +v 0.645221 1.089238 0.442646 +v 0.743519 1.081831 0.342053 +v 0.614862 1.081831 0.478448 +v 0.781268 1.020125 0.356180 +v 0.631168 1.020125 0.515308 +v 0.741573 0.968079 0.243560 +v 0.516424 0.968079 0.482252 +v 0.768544 0.901409 0.247522 +v 0.521952 0.901409 0.508946 +v 0.714377 0.851768 0.089031 +v 0.360571 0.851768 0.464118 +v 0.683851 0.911030 0.092456 +v 0.362209 0.911030 0.433444 +v 0.757164 0.466835 0.483800 +v 0.819659 0.498948 0.413873 +v 0.691002 0.498948 0.550269 +v 0.826937 0.419906 0.420739 +v 0.698281 0.419906 0.557134 +v 0.789440 0.368014 0.449807 +v 0.725112 0.368014 0.518005 +v 0.759082 0.360606 0.485609 +v 0.748108 0.365455 0.410820 +v 0.717750 0.358047 0.446622 +v 0.683780 0.365455 0.479018 +v 0.776633 0.404976 0.373289 +v 0.647977 0.404976 0.509684 +v 0.778355 0.471684 0.374913 +v 0.649698 0.471684 0.511308 +v 0.715860 0.439571 0.444840 +v 0.708682 1.365730 0.180316 +v 0.688905 1.427474 0.183140 +v 0.451368 1.365730 0.453107 +v 0.453034 1.427474 0.433198 +v 0.676210 1.501551 0.160426 +v 0.429618 1.501551 0.421850 +v 0.679597 1.575629 0.120662 +v 0.390119 1.575629 0.427552 +v 0.751707 1.323766 0.167202 +v 0.440787 1.323766 0.496824 +v 0.837450 1.266909 0.044026 +v 0.322823 1.266909 0.589607 +v 0.881946 1.296501 -0.053619 +v 0.227940 1.296501 0.639724 +v 0.903025 1.372984 -0.173352 +v 0.109641 1.372984 0.667752 +v 0.892107 1.464359 -0.194390 +v 0.088002 1.464359 0.658081 +v 0.866970 1.526103 -0.185882 +v 0.095029 1.526103 0.632490 +v 0.813531 1.595370 -0.042975 +v 0.234575 1.595370 0.570804 +v 0.736563 1.620037 0.002562 +v 0.275543 1.620037 0.491311 +v 0.706261 1.617593 0.059896 +v 0.331012 1.617593 0.457715 +v 0.683124 1.553367 0.091770 +v 0.711649 1.592888 0.054239 +v 0.361482 1.553367 0.432759 +v 0.325679 1.592888 0.463425 +v 0.736591 1.595331 0.002588 +v 0.275571 1.595331 0.491338 +v 0.793810 1.580516 -0.050837 +v 0.225575 1.580516 0.551575 +v 0.838361 1.506323 -0.169909 +v 0.109305 1.506323 0.602997 +v 0.861693 1.451987 -0.180120 +v 0.100473 1.451987 0.626886 +v 0.872582 1.385317 -0.159109 +v 0.122084 1.385317 0.636531 +v 0.856836 1.306353 -0.055825 +v 0.224273 1.306353 0.614785 +v 0.821256 1.284168 0.028751 +v 0.306629 1.284168 0.574332 +v 0.742651 1.331135 0.137181 +v 0.410288 1.331135 0.489535 +v 0.699626 1.373099 0.150295 +v 0.420870 1.373099 0.445818 +v 0.670765 1.494105 0.133811 +v 0.402730 1.494105 0.417968 +v 0.681626 1.424953 0.144056 +v 0.413591 1.424953 0.428213 +v 0.471496 1.602509 0.063984 +v 0.403696 1.548172 0.150387 +v 0.321396 1.602509 0.223112 +v 0.488908 1.797592 -0.037729 +v 0.220873 1.797592 0.246428 +v 0.563818 1.812369 -0.160383 +v 0.102798 1.812369 0.328367 +v 0.669422 1.674027 -0.264825 +v 0.004695 1.674027 0.439884 +v 0.783802 1.557870 -0.425427 +v -0.148960 1.557870 0.563439 +v 0.853491 1.503495 -0.520787 +v -0.240092 1.503496 0.638573 +v 0.834105 1.246553 -0.506854 +v -0.227313 1.246553 0.618407 +v 0.781030 1.103401 -0.320644 +v -0.044518 1.103401 0.554559 +v 0.727843 1.031882 -0.145281 +v 0.127444 1.031882 0.491231 +v 0.435397 0.532851 0.180288 +v 0.388592 0.601926 0.136139 +v 0.479472 0.661150 -0.025150 +v 0.540889 0.574893 0.107961 +v 0.232880 0.661150 0.236275 +v 0.369347 0.574893 0.289821 +v 0.505729 0.318065 0.246631 +v 0.607554 0.369958 0.149364 +v 0.414569 0.369958 0.353957 +v 0.626282 0.192326 0.360344 +v 0.715468 0.214511 0.218936 +v 0.490319 0.214511 0.457628 +v 0.793877 0.231731 0.067363 +v 0.343578 0.231731 0.544747 +v 0.709352 0.419368 0.041332 +v 0.312660 0.419368 0.461884 +v 0.639187 0.621859 0.028847 +v 0.296102 0.621859 0.392568 +v 0.604938 0.767571 0.018020 +v 0.283296 0.767571 0.359008 +v 0.594133 0.841686 0.029307 +v 0.603077 0.905951 0.048483 +v 0.313599 0.905951 0.355373 +v 0.293933 0.841686 0.347563 +v 0.606632 0.967733 0.062577 +v 0.327875 0.967733 0.358100 +v -0.504797 0.775424 -0.706562 +v -0.157513 0.812732 -0.840789 +v -0.018989 0.659843 -0.720864 +v -0.335634 0.573202 -0.546997 +v -0.490730 0.659843 -0.220747 +v -0.618533 0.812732 -0.352039 +v 0.175368 0.591153 -0.473096 +v -0.071364 0.497181 -0.297721 +v -0.232045 0.591153 -0.041177 +v 0.430834 0.653588 -0.113987 +v 0.318511 0.594365 0.070035 +v 0.141356 0.653588 0.192902 +v 0.645892 0.949744 -0.630690 +v 0.650526 1.211458 -0.787415 +v -0.361919 0.949744 0.437740 +v -0.518107 1.211458 0.451509 +v -0.634712 1.234665 -0.829107 +v -0.187157 1.163301 -1.040586 +v -0.819720 1.163301 -0.369976 +v 0.074399 1.915578 -0.160228 +v 0.358432 1.853757 -0.515212 +v 0.130217 1.831034 -0.730479 +v -0.198731 1.880406 -0.417861 +v -0.491624 1.831034 -0.071235 +v -0.263409 1.853757 0.144032 +v -0.070886 1.672490 -0.920172 +v -0.502192 1.649998 -0.704105 +v -0.692728 1.672490 -0.260928 +v 0.719026 1.463783 -0.550966 +v 0.606143 1.490855 -0.528568 +v -0.278065 1.463783 0.506098 +v -0.262290 1.490855 0.392100 +v 0.585666 1.544922 -0.773416 +v 0.397454 1.655923 -0.736156 +v -0.507917 1.544922 0.385943 +v -0.481701 1.655923 0.195878 +v 0.405978 1.519832 -0.942910 +v 0.214182 1.620943 -0.909030 +v -0.687605 1.519833 0.216450 +v -0.664972 1.620943 0.023005 +v 0.256984 1.368811 -1.083451 +v 0.057994 1.474848 -1.056357 +v -0.836599 1.368812 0.075909 +v -0.821161 1.474848 -0.124322 +v 0.250209 1.084720 -1.057622 +v 0.026165 1.096823 -1.054161 +v -0.820826 1.096823 -0.156225 +v -0.811210 1.084720 0.067639 +v 0.574343 1.604683 -0.322290 +v -0.058220 1.604683 0.348320 +v 0.344225 1.693807 0.094289 +v 0.565972 1.260677 -0.877910 +v -0.613382 1.260677 0.372380 +v 0.429589 1.218444 -0.952857 +v -0.696158 1.218444 0.240602 +v 0.277137 0.719643 -0.559675 +v 0.503519 0.856041 -0.313918 +v -0.312540 0.719643 0.065470 +v -0.053994 0.856041 0.277128 +v 0.405794 0.801205 -0.663851 +v -0.409032 0.801205 0.199986 +v 0.227660 0.827931 -0.896317 +v 0.032393 0.820332 -0.865711 +v -0.632334 0.820332 -0.161002 +v -0.651495 0.827931 0.035717 +v 0.459220 1.324442 -1.204139 +v 0.438225 1.282593 -1.041368 +v 0.481279 1.243110 -1.043716 +v 0.484470 1.272626 -1.169582 +v -0.783846 1.243110 0.297504 +v -0.784014 1.282593 0.254387 +v -0.945283 1.324442 0.284843 +v -0.909312 1.272626 0.308033 +v 0.526936 1.262583 -1.365799 +v 0.521295 1.319324 -1.435558 +v -1.102717 1.262583 0.361874 +v -1.172686 1.319324 0.360313 +v 0.604071 1.116872 -1.400437 +v 0.645039 1.141538 -1.479930 +v -1.132796 1.116872 0.440899 +v -1.209763 1.141538 0.486435 +v 0.615296 0.916863 -1.314672 +v 0.652793 0.887193 -1.375959 +v -1.046521 0.916863 0.447101 +v -1.105517 0.887193 0.488110 +v 0.589136 0.838013 -1.092334 +v 0.592775 0.771305 -1.099641 +v -0.826089 0.838013 0.408014 +v -0.833171 0.771305 0.412073 +v 0.575531 0.862987 -0.825935 +v 0.559645 0.798800 -0.765742 +v -0.560937 0.862988 0.378890 +v -0.501774 0.798800 0.359519 +v 0.542359 0.855196 -1.147197 +v 0.548336 0.882613 -0.926765 +v -0.663182 0.882613 0.357624 +v -0.883587 0.855196 0.364518 +v 0.568659 0.919268 -1.326443 +v -1.060994 0.919268 0.401231 +v 0.564712 1.067423 -1.394604 +v -1.129269 1.067423 0.401267 +v 0.501938 1.173613 -1.367900 +v -1.106272 1.173613 0.337041 +v 0.457583 1.183618 -1.205684 +v -0.946921 1.183618 0.283298 +v 0.461502 1.168918 -1.094591 +v -0.835788 1.168918 0.280729 +v 0.462705 0.895024 -0.782005 +v 0.532702 0.949513 -0.726718 +v -0.523664 0.895024 0.263693 +v -0.464388 0.949514 0.330345 +v 0.449311 1.178923 -0.966474 +v -0.708601 1.178923 0.261084 +v 0.455175 0.870165 -0.917984 +v -0.659851 0.870165 0.264109 +v 0.469395 0.899796 -0.947529 +v 0.437483 0.949321 -0.805795 +v -0.548886 0.949321 0.239902 +v -0.688516 0.899796 0.280029 +v 0.392372 0.973873 -0.902045 +v 0.437063 0.966465 -0.945807 +v -0.647604 0.973873 0.200483 +v -0.688684 0.966465 0.247651 +v 0.427923 1.047950 -0.975908 +v 0.437007 1.097438 -0.913641 +v -0.656575 1.097438 0.245719 +v -0.719266 1.047950 0.240283 +v 0.454587 1.117102 -1.025935 +v -0.767652 1.117102 0.269820 +v 0.418672 1.092320 -1.059812 +v 0.432753 1.136728 -1.132448 +v -0.803568 1.092320 0.235943 +v -0.875258 1.136728 0.254237 +v 0.400952 1.033058 -1.012089 +v -0.756959 1.033058 0.215469 +v 0.365401 0.958981 -0.938226 +v -0.685297 0.958981 0.175669 +v 0.411897 0.944165 -0.980285 +v -0.724571 0.944165 0.224540 +v 0.442424 0.884903 -0.983710 +v -0.726209 0.884903 0.255214 +v 0.422842 0.855272 -0.948482 +v -0.692183 0.855272 0.233611 +v 0.508810 0.872647 -0.964049 +v -0.702709 0.872647 0.320340 +v 0.434194 1.151428 -1.249225 +v -0.991752 1.151428 0.262489 +v 0.483938 1.143905 -1.406357 +v -1.145715 1.143905 0.321316 +v 0.550268 1.045123 -1.440448 +v -1.175878 1.045123 0.389522 +v 0.559603 0.899450 -1.367204 +v -1.102214 0.899450 0.394568 +v 0.509999 0.837821 -1.188461 +v -0.926668 0.837821 0.334620 +v 0.479781 0.924386 -1.066609 +v 0.442172 0.971314 -1.037646 +v -0.806787 0.924386 0.297344 +v -0.780068 0.971314 0.258110 +v 0.486667 0.973719 -1.146031 +v 0.459808 1.023130 -1.117668 +v -0.885672 0.973719 0.308852 +v -0.858925 1.023130 0.280384 +v 0.498970 1.028017 -1.209603 +v 0.466722 1.074946 -1.186323 +v -0.948419 1.028017 0.324844 +v -0.927060 1.074946 0.291292 +v 0.525690 1.047758 -1.259578 +v 0.495163 1.107020 -1.256153 +v -0.996749 1.047758 0.354433 +v -0.995111 1.107020 0.323759 +v 0.426649 0.749082 -0.912672 +v 0.476001 0.733998 -1.209790 +v -0.656212 0.749082 0.235322 +v -0.949945 0.733998 0.301925 +v 0.604182 0.854927 -1.464770 +v -1.197013 0.854927 0.444764 +v 0.607290 1.094495 -1.537017 +v -1.268955 1.094495 0.452081 +v 0.454825 1.242572 -1.519736 +v -1.260599 1.242573 0.298868 +v 0.349697 1.232798 -1.307449 +v -1.054807 1.232798 0.181533 +v 0.319814 1.213211 -1.110103 +v -0.859540 1.213211 0.140187 +usemtl None +s off +f 25 26 27 +f 25 27 28 +f 29 30 31 +f 29 31 32 +f 28 27 33 +f 28 33 34 +f 35 29 32 +f 35 32 36 +f 27 37 38 +f 27 38 33 +f 39 40 29 +f 39 29 35 +f 26 41 37 +f 26 37 27 +f 40 42 30 +f 40 30 29 +f 41 43 44 +f 41 44 37 +f 45 46 42 +f 45 42 40 +f 37 44 47 +f 37 47 38 +f 48 45 40 +f 48 40 39 +f 44 49 50 +f 44 50 47 +f 51 52 45 +f 51 45 48 +f 43 53 49 +f 43 49 44 +f 52 54 46 +f 52 46 45 +f 53 55 56 +f 53 56 49 +f 57 58 54 +f 57 54 52 +f 49 56 59 +f 49 59 50 +f 60 57 52 +f 60 52 51 +f 56 61 62 +f 56 62 59 +f 63 64 57 +f 63 57 60 +f 55 65 61 +f 55 61 56 +f 64 66 58 +f 64 58 57 +f 65 67 68 +f 65 68 61 +f 69 70 66 +f 69 66 64 +f 61 68 71 +f 61 71 62 +f 72 69 64 +f 72 64 63 +f 68 28 34 +f 68 34 71 +f 36 32 69 +f 36 69 72 +f 67 25 28 +f 67 28 68 +f 32 31 70 +f 32 70 69 +f 25 67 73 +f 25 73 74 +f 75 70 31 +f 75 31 76 +f 67 65 77 +f 67 77 73 +f 78 66 70 +f 78 70 75 +f 65 55 79 +f 65 79 77 +f 80 58 66 +f 80 66 78 +f 55 53 81 +f 55 81 79 +f 82 54 58 +f 82 58 80 +f 53 43 83 +f 53 83 81 +f 84 46 54 +f 84 54 82 +f 43 41 85 +f 43 85 83 +f 86 42 46 +f 86 46 84 +f 41 26 87 +f 41 87 85 +f 88 30 42 +f 88 42 86 +f 26 25 74 +f 26 74 87 +f 76 31 30 +f 76 30 88 +f 89 87 74 +f 76 88 90 +f 85 87 89 +f 90 88 86 +f 89 83 85 +f 86 84 90 +f 89 81 83 +f 84 82 90 +f 89 79 81 +f 82 80 90 +f 89 77 79 +f 80 78 90 +f 89 73 77 +f 78 75 90 +f 89 74 73 +f 75 76 90 +f 91 92 93 +f 91 93 94 +f 93 95 96 +f 93 96 94 +f 97 98 92 +f 97 92 91 +f 95 99 100 +f 95 100 96 +f 101 102 98 +f 101 98 97 +f 99 103 104 +f 99 104 100 +f 105 106 102 +f 105 102 101 +f 103 107 108 +f 103 108 104 +f 109 110 106 +f 109 106 105 +f 107 111 112 +f 107 112 108 +f 113 114 115 +f 113 115 116 +f 117 118 119 +f 117 119 120 +f 114 121 122 +f 114 122 115 +f 123 124 118 +f 123 118 117 +f 121 125 126 +f 121 126 122 +f 127 128 124 +f 127 124 123 +f 125 129 130 +f 125 130 126 +f 131 132 128 +f 131 128 127 +f 129 133 134 +f 129 134 130 +f 135 136 132 +f 135 132 131 +f 133 137 138 +f 133 138 134 +f 139 140 136 +f 139 136 135 +f 137 141 142 +f 137 142 138 +f 143 144 140 +f 143 140 139 +f 141 145 146 +f 141 146 142 +f 147 148 144 +f 147 144 143 +f 145 149 150 +f 145 150 146 +f 151 152 148 +f 151 148 147 +f 149 153 154 +f 149 154 150 +f 154 153 152 +f 154 152 151 +f 155 156 146 +f 155 146 150 +f 147 157 158 +f 147 158 151 +f 156 159 142 +f 156 142 146 +f 143 160 157 +f 143 157 147 +f 161 138 142 +f 161 142 159 +f 143 139 162 +f 143 162 160 +f 163 134 138 +f 163 138 161 +f 139 135 164 +f 139 164 162 +f 165 130 134 +f 165 134 163 +f 135 131 166 +f 135 166 164 +f 167 126 130 +f 167 130 165 +f 131 127 168 +f 131 168 166 +f 169 122 126 +f 169 126 167 +f 127 123 170 +f 127 170 168 +f 171 115 122 +f 171 122 169 +f 123 117 172 +f 123 172 170 +f 173 116 115 +f 173 115 171 +f 117 120 174 +f 117 174 172 +f 173 175 176 +f 173 176 116 +f 176 177 174 +f 176 174 120 +f 155 150 154 +f 155 154 178 +f 154 151 158 +f 154 158 179 +f 178 154 180 +f 178 180 181 +f 180 154 179 +f 180 179 182 +f 176 175 181 +f 176 181 180 +f 182 177 176 +f 182 176 180 +f 183 184 93 +f 183 93 92 +f 93 184 185 +f 93 185 95 +f 186 183 92 +f 186 92 98 +f 95 185 187 +f 95 187 99 +f 188 186 98 +f 188 98 102 +f 99 187 189 +f 99 189 103 +f 110 190 191 +f 110 191 106 +f 192 193 111 +f 192 111 107 +f 188 102 106 +f 188 106 191 +f 107 103 189 +f 107 189 192 +f 194 195 196 +f 194 196 190 +f 196 195 197 +f 196 197 193 +f 191 190 196 +f 191 196 198 +f 196 193 192 +f 196 192 198 +f 199 188 191 +f 199 191 198 +f 192 189 199 +f 192 199 198 +f 200 201 202 +f 200 202 194 +f 203 204 205 +f 203 205 197 +f 206 207 201 +f 206 201 200 +f 204 208 209 +f 204 209 205 +f 210 211 207 +f 210 207 206 +f 208 212 210 +f 208 210 209 +f 213 214 211 +f 213 211 210 +f 212 214 213 +f 212 213 210 +f 195 194 202 +f 195 202 215 +f 203 197 195 +f 203 195 215 +f 215 202 216 +f 215 216 217 +f 218 203 215 +f 218 215 217 +f 214 219 220 +f 214 220 211 +f 221 219 214 +f 221 214 212 +f 211 220 222 +f 211 222 207 +f 223 221 212 +f 223 212 208 +f 207 222 224 +f 207 224 201 +f 225 223 208 +f 225 208 204 +f 201 224 216 +f 201 216 202 +f 218 225 204 +f 218 204 203 +f 219 224 222 +f 219 222 220 +f 223 225 219 +f 223 219 221 +f 219 217 216 +f 219 216 224 +f 218 217 219 +f 218 219 225 +f 210 206 116 +f 210 116 176 +f 120 209 210 +f 120 210 176 +f 206 200 226 +f 206 226 116 +f 227 205 209 +f 227 209 120 +f 200 194 228 +f 200 228 226 +f 229 197 205 +f 229 205 227 +f 194 190 110 +f 194 110 228 +f 111 193 197 +f 111 197 229 +f 109 230 228 +f 109 228 110 +f 229 231 112 +f 229 112 111 +f 230 232 226 +f 230 226 228 +f 227 233 231 +f 227 231 229 +f 113 116 226 +f 113 226 232 +f 227 120 119 +f 227 119 233 +f 188 199 234 +f 188 234 235 +f 234 199 189 +f 234 189 236 +f 186 188 235 +f 186 235 237 +f 236 189 187 +f 236 187 238 +f 183 186 237 +f 183 237 239 +f 238 187 185 +f 238 185 240 +f 184 183 239 +f 184 239 241 +f 240 185 184 +f 240 184 241 +f 241 239 242 +f 241 242 243 +f 244 240 241 +f 244 241 243 +f 239 237 245 +f 239 245 242 +f 246 238 240 +f 246 240 244 +f 237 235 247 +f 237 247 245 +f 248 236 238 +f 248 238 246 +f 235 234 249 +f 235 249 247 +f 249 234 236 +f 249 236 248 +f 249 243 242 +f 249 242 247 +f 244 243 249 +f 244 249 248 +f 247 242 245 +f 246 244 248 +f 181 175 250 +f 181 250 251 +f 252 177 182 +f 252 182 253 +f 178 181 251 +f 178 251 254 +f 253 182 179 +f 253 179 255 +f 155 178 254 +f 155 254 256 +f 255 179 158 +f 255 158 257 +f 175 173 258 +f 175 258 250 +f 259 174 177 +f 259 177 252 +f 173 171 260 +f 173 260 258 +f 261 172 174 +f 261 174 259 +f 171 169 262 +f 171 262 260 +f 263 170 172 +f 263 172 261 +f 169 167 264 +f 169 264 262 +f 265 168 170 +f 265 170 263 +f 167 165 266 +f 167 266 264 +f 267 166 168 +f 267 168 265 +f 165 163 268 +f 165 268 266 +f 269 164 166 +f 269 166 267 +f 163 161 270 +f 163 270 268 +f 271 162 164 +f 271 164 269 +f 161 159 272 +f 161 272 270 +f 273 160 162 +f 273 162 271 +f 159 156 274 +f 159 274 272 +f 275 157 160 +f 275 160 273 +f 156 155 256 +f 156 256 274 +f 257 158 157 +f 257 157 275 +f 274 256 276 +f 274 276 277 +f 278 257 275 +f 278 275 279 +f 272 274 277 +f 272 277 280 +f 279 275 273 +f 279 273 281 +f 270 272 280 +f 270 280 282 +f 281 273 271 +f 281 271 283 +f 268 270 282 +f 268 282 284 +f 283 271 269 +f 283 269 285 +f 266 268 284 +f 266 284 286 +f 285 269 267 +f 285 267 287 +f 264 266 286 +f 264 286 288 +f 287 267 265 +f 287 265 289 +f 262 264 288 +f 262 288 290 +f 289 265 263 +f 289 263 291 +f 260 262 290 +f 260 290 292 +f 291 263 261 +f 291 261 293 +f 258 260 292 +f 258 292 294 +f 293 261 259 +f 293 259 295 +f 250 258 294 +f 250 294 296 +f 295 259 252 +f 295 252 297 +f 256 254 298 +f 256 298 276 +f 299 255 257 +f 299 257 278 +f 254 251 300 +f 254 300 298 +f 301 253 255 +f 301 255 299 +f 251 250 296 +f 251 296 300 +f 297 252 253 +f 297 253 301 +f 153 149 302 +f 153 302 303 +f 304 152 153 +f 304 153 303 +f 149 145 305 +f 149 305 302 +f 306 148 152 +f 306 152 304 +f 145 141 307 +f 145 307 305 +f 308 144 148 +f 308 148 306 +f 141 137 309 +f 141 309 307 +f 310 140 144 +f 310 144 308 +f 137 133 311 +f 137 311 309 +f 312 136 140 +f 312 140 310 +f 133 129 313 +f 133 313 311 +f 314 132 136 +f 314 136 312 +f 129 125 315 +f 129 315 313 +f 316 128 132 +f 316 132 314 +f 125 121 317 +f 125 317 315 +f 318 124 128 +f 318 128 316 +f 121 114 319 +f 121 319 317 +f 320 118 124 +f 320 124 318 +f 321 322 323 +f 321 323 324 +f 325 322 321 +f 325 321 326 +f 327 321 324 +f 327 324 328 +f 326 321 327 +f 326 327 329 +f 330 327 328 +f 330 328 331 +f 329 327 330 +f 329 330 332 +f 91 94 330 +f 91 330 331 +f 330 94 96 +f 330 96 332 +f 97 91 331 +f 97 331 333 +f 332 96 100 +f 332 100 334 +f 101 97 333 +f 101 333 335 +f 334 100 104 +f 334 104 336 +f 105 101 335 +f 105 335 337 +f 336 104 108 +f 336 108 338 +f 335 328 324 +f 335 324 337 +f 326 329 336 +f 326 336 338 +f 335 333 331 +f 335 331 328 +f 332 334 336 +f 332 336 329 +f 339 337 324 +f 339 324 323 +f 326 338 340 +f 326 340 325 +f 109 105 337 +f 109 337 339 +f 338 108 112 +f 338 112 340 +f 230 341 342 +f 230 342 232 +f 343 344 231 +f 343 231 233 +f 109 339 341 +f 109 341 230 +f 344 340 112 +f 344 112 231 +f 113 232 342 +f 113 342 345 +f 343 233 119 +f 343 119 346 +f 113 345 319 +f 113 319 114 +f 320 346 119 +f 320 119 118 +f 347 348 349 +f 347 349 350 +f 351 352 347 +f 351 347 350 +f 350 349 353 +f 350 353 354 +f 355 351 350 +f 355 350 354 +f 354 353 356 +f 354 356 357 +f 358 355 354 +f 358 354 357 +f 357 356 323 +f 357 323 322 +f 325 358 357 +f 325 357 322 +f 339 323 356 +f 339 356 341 +f 358 325 340 +f 358 340 344 +f 315 317 359 +f 315 359 360 +f 361 318 316 +f 361 316 362 +f 363 364 348 +f 363 348 347 +f 352 365 363 +f 352 363 347 +f 366 367 368 +f 366 368 369 +f 370 371 366 +f 370 366 369 +f 369 368 372 +f 369 372 373 +f 374 370 369 +f 374 369 373 +f 373 372 364 +f 373 364 363 +f 365 374 373 +f 365 373 363 +f 311 313 375 +f 311 375 376 +f 377 314 312 +f 377 312 378 +f 376 375 379 +f 376 379 380 +f 381 377 378 +f 381 378 382 +f 380 379 383 +f 380 383 384 +f 385 381 382 +f 385 382 386 +f 384 383 387 +f 384 387 388 +f 389 385 386 +f 389 386 390 +f 391 392 388 +f 391 388 387 +f 390 393 394 +f 390 394 389 +f 364 372 388 +f 364 388 392 +f 390 374 365 +f 390 365 393 +f 372 368 384 +f 372 384 388 +f 386 370 374 +f 386 374 390 +f 368 367 380 +f 368 380 384 +f 382 371 370 +f 382 370 386 +f 367 395 376 +f 367 376 380 +f 378 396 371 +f 378 371 382 +f 309 311 376 +f 309 376 395 +f 378 312 310 +f 378 310 396 +f 397 395 367 +f 397 367 366 +f 371 396 397 +f 371 397 366 +f 302 305 307 +f 302 307 309 +f 308 306 304 +f 308 304 310 +f 302 309 395 +f 302 395 397 +f 396 310 304 +f 396 304 397 +f 303 302 397 +f 397 304 303 +f 313 315 360 +f 313 360 375 +f 362 316 314 +f 362 314 377 +f 360 398 379 +f 360 379 375 +f 381 399 362 +f 381 362 377 +f 398 400 383 +f 398 383 379 +f 385 401 399 +f 385 399 381 +f 391 387 383 +f 391 383 400 +f 385 389 394 +f 385 394 401 +f 356 353 402 +f 356 402 403 +f 404 355 358 +f 404 358 405 +f 359 403 402 +f 359 402 406 +f 404 405 361 +f 404 361 407 +f 317 319 403 +f 317 403 359 +f 405 320 318 +f 405 318 361 +f 319 342 341 +f 319 341 403 +f 344 343 320 +f 344 320 405 +f 341 356 403 +f 405 358 344 +f 319 345 342 +f 343 346 320 +f 391 408 409 +f 391 409 392 +f 410 411 394 +f 410 394 393 +f 364 392 409 +f 364 409 348 +f 410 393 365 +f 410 365 352 +f 406 402 409 +f 406 409 408 +f 410 404 407 +f 410 407 411 +f 353 349 409 +f 353 409 402 +f 410 351 355 +f 410 355 404 +f 348 409 349 +f 351 410 352 +f 412 413 414 +f 412 414 415 +f 416 417 418 +f 416 418 419 +f 412 415 420 +f 412 420 421 +f 422 419 418 +f 422 418 423 +f 421 420 424 +f 421 424 425 +f 426 422 423 +f 426 423 427 +f 425 424 428 +f 425 428 429 +f 430 426 427 +f 430 427 431 +f 429 428 432 +f 429 432 433 +f 434 430 431 +f 434 431 435 +f 433 432 436 +f 433 436 437 +f 438 434 435 +f 438 435 439 +f 432 440 441 +f 432 441 436 +f 442 443 434 +f 442 434 438 +f 428 444 440 +f 428 440 432 +f 443 445 430 +f 443 430 434 +f 424 446 444 +f 424 444 428 +f 445 447 426 +f 445 426 430 +f 420 448 446 +f 420 446 424 +f 447 449 422 +f 447 422 426 +f 415 450 448 +f 415 448 420 +f 449 451 419 +f 449 419 422 +f 415 414 452 +f 415 452 450 +f 453 416 419 +f 453 419 451 +f 359 406 454 +f 359 454 455 +f 456 407 361 +f 456 361 457 +f 406 437 436 +f 406 436 454 +f 438 439 407 +f 438 407 456 +f 360 359 455 +f 360 455 398 +f 457 361 362 +f 457 362 399 +f 400 458 414 +f 400 414 413 +f 416 459 401 +f 416 401 417 +f 436 441 460 +f 436 460 454 +f 461 442 438 +f 461 438 456 +f 462 463 454 +f 462 454 460 +f 456 464 465 +f 456 465 461 +f 466 463 462 +f 466 462 467 +f 465 464 468 +f 465 468 469 +f 470 471 463 +f 470 463 466 +f 464 472 473 +f 464 473 468 +f 458 471 470 +f 458 470 474 +f 473 472 459 +f 473 459 475 +f 414 458 474 +f 414 474 452 +f 475 459 416 +f 475 416 453 +f 398 471 458 +f 398 458 400 +f 459 472 399 +f 459 399 401 +f 398 455 463 +f 398 463 471 +f 464 457 399 +f 464 399 472 +f 455 454 463 +f 464 456 457 +f 452 474 476 +f 452 476 477 +f 478 475 453 +f 478 453 479 +f 474 470 480 +f 474 480 476 +f 481 473 475 +f 481 475 478 +f 470 466 482 +f 470 482 480 +f 483 468 473 +f 483 473 481 +f 466 467 484 +f 466 484 482 +f 485 469 468 +f 485 468 483 +f 467 462 486 +f 467 486 484 +f 487 465 469 +f 487 469 485 +f 462 460 488 +f 462 488 486 +f 489 461 465 +f 489 465 487 +f 460 441 490 +f 460 490 488 +f 491 442 461 +f 491 461 489 +f 450 452 477 +f 450 477 492 +f 479 453 451 +f 479 451 493 +f 448 450 492 +f 448 492 494 +f 493 451 449 +f 493 449 495 +f 446 448 494 +f 446 494 496 +f 495 449 447 +f 495 447 497 +f 444 446 496 +f 444 496 498 +f 497 447 445 +f 497 445 499 +f 440 444 498 +f 440 498 500 +f 499 445 443 +f 499 443 501 +f 441 440 500 +f 441 500 490 +f 501 443 442 +f 501 442 491 +f 484 486 502 +f 484 502 503 +f 504 487 485 +f 504 485 505 +f 503 502 506 +f 503 506 507 +f 508 504 505 +f 508 505 509 +f 507 506 510 +f 507 510 511 +f 512 508 509 +f 512 509 513 +f 511 510 514 +f 511 514 515 +f 516 512 513 +f 516 513 517 +f 492 477 511 +f 492 511 515 +f 513 479 493 +f 513 493 517 +f 476 507 511 +f 476 511 477 +f 513 509 478 +f 513 478 479 +f 476 480 503 +f 476 503 507 +f 505 481 478 +f 505 478 509 +f 484 503 480 +f 484 480 482 +f 481 505 485 +f 481 485 483 +f 488 490 502 +f 488 502 486 +f 504 491 489 +f 504 489 487 +f 500 506 502 +f 500 502 490 +f 504 508 501 +f 504 501 491 +f 498 510 506 +f 498 506 500 +f 508 512 499 +f 508 499 501 +f 496 514 510 +f 496 510 498 +f 512 516 497 +f 512 497 499 +f 494 515 514 +f 494 514 496 +f 516 517 495 +f 516 495 497 +f 492 515 494 +f 495 517 493 +f 433 437 518 +f 433 518 519 +f 520 439 435 +f 520 435 521 +f 429 433 519 +f 429 519 522 +f 521 435 431 +f 521 431 523 +f 425 429 522 +f 425 522 524 +f 523 431 427 +f 523 427 525 +f 421 425 524 +f 421 524 526 +f 525 427 423 +f 525 423 527 +f 412 421 526 +f 412 526 528 +f 527 423 418 +f 527 418 529 +f 413 412 528 +f 413 528 530 +f 529 418 417 +f 529 417 531 +f 528 519 518 +f 528 518 530 +f 520 521 529 +f 520 529 531 +f 528 526 522 +f 528 522 519 +f 523 527 529 +f 523 529 521 +f 526 524 522 +f 523 525 527 +f 391 400 413 +f 391 413 530 +f 417 401 394 +f 417 394 531 +f 391 530 518 +f 391 518 408 +f 520 531 394 +f 520 394 411 +f 406 408 518 +f 406 518 437 +f 520 411 407 +f 520 407 439 diff --git a/examples/raytrace/gltf-loader.cc b/examples/raytrace/gltf-loader.cc index 94dc9d0..5283c80 100644 --- a/examples/raytrace/gltf-loader.cc +++ b/examples/raytrace/gltf-loader.cc @@ -1,13 +1,11 @@ #include "gltf-loader.h" #include - +#include // c++11 #define TINYGLTF_IMPLEMENTATION -#define STB_IMAGE_IMPLEMENTATION -#include "tiny_gltf.h" +#include namespace example { - static std::string GetFilePathExtension(const std::string &FileName) { if (FileName.find_last_of(".") != std::string::npos) return FileName.substr(FileName.find_last_of(".") + 1); @@ -17,17 +15,17 @@ static std::string GetFilePathExtension(const std::string &FileName) { /// /// Loads glTF 2.0 mesh /// -bool LoadGLTF(const std::string &filename, float scale, std::vector > *meshes, std::vector *materials, std::vector *textures) -{ - - // TODO(syoyo): Implement +bool LoadGLTF(const std::string &filename, float scale, + std::vector > *meshes, + std::vector *materials, + std::vector *textures) { // TODO(syoyo): Texture // TODO(syoyo): Material tinygltf::Model model; tinygltf::TinyGLTF loader; std::string err; - std::string ext = GetFilePathExtension(filename); + const std::string ext = GetFilePathExtension(filename); bool ret = false; if (ext.compare("glb") == 0) { @@ -46,8 +44,433 @@ bool LoadGLTF(const std::string &filename, float scale, std::vector return false; } - std::cerr << "LoadGLTF() function is not yet implemented!" << std::endl; - return false; -} + std::cout << "loaded glTF file has:\n" + << model.accessors.size() << " accessors\n" + << model.animations.size() << " animations\n" + << model.buffers.size() << " buffers\n" + << model.bufferViews.size() << " bufferViews\n" + << model.materials.size() << " materials\n" + << model.meshes.size() << " meshes\n" + << model.nodes.size() << " nodes\n" + << model.textures.size() << " textures\n" + << model.images.size() << " images\n" + << model.skins.size() << " skins\n" + << model.samplers.size() << " samplers\n" + << model.cameras.size() << " cameras\n" + << model.scenes.size() << " scenes\n" + << model.lights.size() << " lights\n"; -} // namespace example + // Iterate through all the meses in the glTF file + for (const auto &gltfMesh : model.meshes) { + std::cout << "Current mesh has " << gltfMesh.primitives.size() + << " primitives:\n"; + + // Create a mesh object + Mesh loadedMesh(sizeof(float) * 3); + + // To store the min and max of the buffer (as 3D vector of floats) + v3f pMin = {}, pMax = {}; + + // Store the name of the glTF mesh (if defined) + loadedMesh.name = gltfMesh.name; + + // For each primitive + for (const auto &meshPrimitive : gltfMesh.primitives) { + // Boolean used to check if we have converted the vertex buffer format + bool convertedToTriangleList = false; + // This permit to get a type agnostic way of reading the index buffer + std::unique_ptr indicesArrayPtr = nullptr; + { + const auto &indicesAccessor = model.accessors[meshPrimitive.indices]; + const auto &bufferView = model.bufferViews[indicesAccessor.bufferView]; + const auto &buffer = model.buffers[bufferView.buffer]; + const auto dataAddress = buffer.data.data() + bufferView.byteOffset + + indicesAccessor.byteOffset; + const auto byteStride = indicesAccessor.ByteStride(bufferView); + const auto count = indicesAccessor.count; + + // Allocate the index array in the pointer-to-base declared in the + // parent scope + switch (indicesAccessor.componentType) { + case TINYGLTF_COMPONENT_TYPE_BYTE: + indicesArrayPtr = + std::unique_ptr >(new intArray( + arrayAdapter(dataAddress, count, byteStride))); + break; + + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: + indicesArrayPtr = std::unique_ptr >( + new intArray(arrayAdapter( + dataAddress, count, byteStride))); + break; + + case TINYGLTF_COMPONENT_TYPE_SHORT: + indicesArrayPtr = + std::unique_ptr >(new intArray( + arrayAdapter(dataAddress, count, byteStride))); + break; + + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + indicesArrayPtr = std::unique_ptr >( + new intArray(arrayAdapter( + dataAddress, count, byteStride))); + break; + + case TINYGLTF_COMPONENT_TYPE_INT: + indicesArrayPtr = std::unique_ptr >(new intArray( + arrayAdapter(dataAddress, count, byteStride))); + break; + + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: + indicesArrayPtr = std::unique_ptr >( + new intArray(arrayAdapter( + dataAddress, count, byteStride))); + break; + default: + break; + } + } + const auto &indices = *indicesArrayPtr; + + if (indicesArrayPtr) { + std::cout << "indices: "; + for (size_t i(0); i < indicesArrayPtr->size(); ++i) { + std::cout << indices[i] << " "; + loadedMesh.faces.push_back(indices[i]); + } + std::cout << '\n'; + } + + switch (meshPrimitive.mode) { + // We re-arrange the indices so that it describe a simple list of + // triangles + case TINYGLTF_MODE_TRIANGLE_FAN: + if (!convertedToTriangleList) { + std::cout << "TRIANGLE_FAN\n"; + // This only has to be done once per primitive + convertedToTriangleList = true; + + // We steal the guts of the vector + auto triangleFan = std::move(loadedMesh.faces); + loadedMesh.faces.clear(); + + // Push back the indices that describe just one triangle one by one + for (size_t i{2}; i < triangleFan.size(); ++i) { + loadedMesh.faces.push_back(triangleFan[0]); + loadedMesh.faces.push_back(triangleFan[i - 1]); + loadedMesh.faces.push_back(triangleFan[i]); + } + } + case TINYGLTF_MODE_TRIANGLE_STRIP: + if (!convertedToTriangleList) { + std::cout << "TRIANGLE_STRIP\n"; + // This only has to be done once per primitive + convertedToTriangleList = true; + + auto triangleStrip = std::move(loadedMesh.faces); + loadedMesh.faces.clear(); + + for (size_t i{2}; i < triangleStrip.size(); ++i) { + loadedMesh.faces.push_back(triangleStrip[i - 2]); + loadedMesh.faces.push_back(triangleStrip[i - 1]); + loadedMesh.faces.push_back(triangleStrip[i]); + } + } + case TINYGLTF_MODE_TRIANGLES: // this is the simpliest case to handle + + { + std::cout << "TRIANGLES\n"; + + for (const auto &attribute : meshPrimitive.attributes) { + const auto attribAccessor = model.accessors[attribute.second]; + const auto &bufferView = + model.bufferViews[attribAccessor.bufferView]; + const auto &buffer = model.buffers[bufferView.buffer]; + const auto dataPtr = buffer.data.data() + bufferView.byteOffset + + attribAccessor.byteOffset; + const auto byte_stride = attribAccessor.ByteStride(bufferView); + const auto count = attribAccessor.count; + + std::cout << "current attribute has count " << count + << " and stride " << byte_stride << " bytes\n"; + + std::cout << "attribute string is : " << attribute.first << '\n'; + if (attribute.first == "POSITION") { + std::cout << "found position attribute\n"; + + // get the position min/max for computing the boundingbox + pMin.x = attribAccessor.minValues[0]; + pMin.y = attribAccessor.minValues[1]; + pMin.z = attribAccessor.minValues[2]; + pMax.x = attribAccessor.maxValues[0]; + pMax.y = attribAccessor.maxValues[1]; + pMax.z = attribAccessor.maxValues[2]; + + switch (attribAccessor.type) { + case TINYGLTF_TYPE_VEC3: { + switch (attribAccessor.componentType) { + case TINYGLTF_COMPONENT_TYPE_FLOAT: + std::cout << "Type is FLOAT\n"; + // 3D vector of float + v3fArray positions( + arrayAdapter(dataPtr, count, byte_stride)); + + std::cout << "positions's size : " << positions.size() + << '\n'; + + for (size_t i{0}; i < positions.size(); ++i) { + const auto v = positions[i]; + std::cout << "positions[" << i << "]: (" << v.x << ", " + << v.y << ", " << v.z << ")\n"; + + loadedMesh.vertices.push_back(v.x * scale); + loadedMesh.vertices.push_back(v.y * scale); + loadedMesh.vertices.push_back(v.z * scale); + } + } + break; + case TINYGLTF_COMPONENT_TYPE_DOUBLE: { + std::cout << "Type is DOUBLE\n"; + switch (attribAccessor.type) { + case TINYGLTF_TYPE_VEC3: { + v3dArray positions( + arrayAdapter(dataPtr, count, byte_stride)); + for (size_t i{0}; i < positions.size(); ++i) { + const auto v = positions[i]; + std::cout << "positions[" << i << "]: (" << v.x + << ", " << v.y << ", " << v.z << ")\n"; + + loadedMesh.vertices.push_back(v.x * scale); + loadedMesh.vertices.push_back(v.y * scale); + loadedMesh.vertices.push_back(v.z * scale); + } + } break; + default: + // TODO Handle error + break; + } + break; + default: + break; + } + } break; + } + } + + if (attribute.first == "NORMAL") { + std::cout << "found normal attribute\n"; + + switch (attribAccessor.type) { + case TINYGLTF_TYPE_VEC3: { + std::cout << "Normal is VEC3\n"; + switch (attribAccessor.componentType) { + case TINYGLTF_COMPONENT_TYPE_FLOAT: { + std::cout << "Normal is FLOAT\n"; + v3fArray normals( + arrayAdapter(dataPtr, count, byte_stride)); + + // IMPORTANT: We need to reorder normals (and texture + // coordinates into "facevarying" order) for each face + + // For each triangle : + for (size_t i{0}; i < indices.size() / 3; ++i) { + // get the i'th triange's indexes + auto f0 = indices[3 * i + 0]; + auto f1 = indices[3 * i + 1]; + auto f2 = indices[3 * i + 2]; + + // get the 3 normal vectors for that face + v3f n0, n1, n2; + n0 = normals[f0]; + n1 = normals[f1]; + n2 = normals[f2]; + + // Put them in the array in the correct order + loadedMesh.facevarying_normals.push_back(n0.x); + loadedMesh.facevarying_normals.push_back(n0.y); + loadedMesh.facevarying_normals.push_back(n0.z); + + loadedMesh.facevarying_normals.push_back(n1.x); + loadedMesh.facevarying_normals.push_back(n1.y); + loadedMesh.facevarying_normals.push_back(n2.z); + + loadedMesh.facevarying_normals.push_back(n2.x); + loadedMesh.facevarying_normals.push_back(n2.y); + loadedMesh.facevarying_normals.push_back(n2.z); + } + } break; + case TINYGLTF_COMPONENT_TYPE_DOUBLE: { + std::cout << "Normal is DOUBLE\n"; + v3dArray normals( + arrayAdapter(dataPtr, count, byte_stride)); + + // IMPORTANT: We need to reorder normals (and texture + // coordinates into "facevarying" order) for each face + + // For each triangle : + for (size_t i{0}; i < indices.size() / 3; ++i) { + // get the i'th triange's indexes + auto f0 = indices[3 * i + 0]; + auto f1 = indices[3 * i + 1]; + auto f2 = indices[3 * i + 2]; + + // get the 3 normal vectors for that face + v3d n0, n1, n2; + n0 = normals[f0]; + n1 = normals[f1]; + n2 = normals[f2]; + + // Put them in the array in the correct order + loadedMesh.facevarying_normals.push_back(n0.x); + loadedMesh.facevarying_normals.push_back(n0.y); + loadedMesh.facevarying_normals.push_back(n0.z); + + loadedMesh.facevarying_normals.push_back(n1.x); + loadedMesh.facevarying_normals.push_back(n1.y); + loadedMesh.facevarying_normals.push_back(n2.z); + + loadedMesh.facevarying_normals.push_back(n2.x); + loadedMesh.facevarying_normals.push_back(n2.y); + loadedMesh.facevarying_normals.push_back(n2.z); + } + } break; + default: + std::cerr << "Unhandeled componant type for normal\n"; + } + } break; + default: + std::cerr << "Unhandeled vector type for normal\n"; + } + + // Face varying comment on the normals is also true for the UVs + if (attribute.first == "TEXCOORD_0") { + std::cout << "Found texture coordinates\n"; + + switch (attribAccessor.type) { + case TINYGLTF_TYPE_VEC2: { + std::cout << "TEXTCOORD is VEC2\n"; + switch (attribAccessor.componentType) { + case TINYGLTF_COMPONENT_TYPE_FLOAT: { + std::cout << "TEXTCOORD is FLOAT\n"; + v2fArray uvs( + arrayAdapter(dataPtr, count, byte_stride)); + + for (size_t i{0}; i < indices.size() / 3; ++i) { + // get the i'th triange's indexes + auto f0 = indices[3 * i + 0]; + auto f1 = indices[3 * i + 1]; + auto f2 = indices[3 * i + 2]; + + // get the texture coordinates for each triangle's + // vertices + v2f uv0, uv1, uv2; + uv0 = uvs[f0]; + uv1 = uvs[f1]; + uv2 = uvs[f2]; + + // push them in order into the mesh data + loadedMesh.facevarying_uvs.push_back(uv0.x); + loadedMesh.facevarying_uvs.push_back(uv0.y); + + loadedMesh.facevarying_uvs.push_back(uv1.x); + loadedMesh.facevarying_uvs.push_back(uv1.y); + + loadedMesh.facevarying_uvs.push_back(uv2.x); + loadedMesh.facevarying_uvs.push_back(uv2.y); + } + + } break; + case TINYGLTF_COMPONENT_TYPE_DOUBLE: { + std::cout << "TEXTCOORD is DOUBLE\n"; + v2dArray uvs( + arrayAdapter(dataPtr, count, byte_stride)); + + for (size_t i{0}; i < indices.size() / 3; ++i) { + // get the i'th triange's indexes + auto f0 = indices[3 * i + 0]; + auto f1 = indices[3 * i + 1]; + auto f2 = indices[3 * i + 2]; + + v2d uv0, uv1, uv2; + uv0 = uvs[f0]; + uv1 = uvs[f1]; + uv2 = uvs[f2]; + + loadedMesh.facevarying_uvs.push_back(uv0.x); + loadedMesh.facevarying_uvs.push_back(uv0.y); + + loadedMesh.facevarying_uvs.push_back(uv1.x); + loadedMesh.facevarying_uvs.push_back(uv1.y); + + loadedMesh.facevarying_uvs.push_back(uv2.x); + loadedMesh.facevarying_uvs.push_back(uv2.y); + } + } break; + default: + std::cerr << "unrecognized vector type for UV"; + } + } break; + default: + std::cerr << "unreconized componant type for UV"; + } + } + } + } + break; + + default: + std::cerr << "primitive mode not implemented"; + break; + + // These aren't triangles: + case TINYGLTF_MODE_POINTS: + case TINYGLTF_MODE_LINE: + case TINYGLTF_MODE_LINE_LOOP: + std::cerr << "primitive is not triangle based, ignoring"; + } + } + + // bbox : + v3f bCenter; + bCenter.x = 0.5f * (pMax.x - pMin.x) + pMin.x; + bCenter.y = 0.5f * (pMax.y - pMin.y) + pMin.y; + bCenter.z = 0.5f * (pMax.z - pMin.z) + pMin.z; + + for (size_t v = 0; v < loadedMesh.vertices.size() / 3; v++) { + loadedMesh.vertices[3 * v + 0] -= bCenter.x; + loadedMesh.vertices[3 * v + 1] -= bCenter.y; + loadedMesh.vertices[3 * v + 2] -= bCenter.z; + } + + loadedMesh.pivot_xform[0][0] = 1.0f; + loadedMesh.pivot_xform[0][1] = 0.0f; + loadedMesh.pivot_xform[0][2] = 0.0f; + loadedMesh.pivot_xform[0][3] = 0.0f; + + loadedMesh.pivot_xform[1][0] = 0.0f; + loadedMesh.pivot_xform[1][1] = 1.0f; + loadedMesh.pivot_xform[1][2] = 0.0f; + loadedMesh.pivot_xform[1][3] = 0.0f; + + loadedMesh.pivot_xform[2][0] = 0.0f; + loadedMesh.pivot_xform[2][1] = 0.0f; + loadedMesh.pivot_xform[2][2] = 1.0f; + loadedMesh.pivot_xform[2][3] = 0.0f; + + loadedMesh.pivot_xform[3][0] = bCenter.x; + loadedMesh.pivot_xform[3][1] = bCenter.y; + loadedMesh.pivot_xform[3][2] = bCenter.z; + loadedMesh.pivot_xform[3][3] = 1.0f; + + // TODO handle materials + for (size_t i{0}; i < loadedMesh.faces.size(); ++i) + loadedMesh.material_ids.push_back(materials->at(0).id); + + meshes->push_back(loadedMesh); + ret = true; + } + + return ret; + } +} +} // namespace example diff --git a/examples/raytrace/gltf-loader.h b/examples/raytrace/gltf-loader.h index afe6e62..6f8b890 100644 --- a/examples/raytrace/gltf-loader.h +++ b/examples/raytrace/gltf-loader.h @@ -1,19 +1,166 @@ #ifndef EXAMPLE_GLTF_LOADER_H_ #define EXAMPLE_GLTF_LOADER_H_ -#include +#include #include +#include -#include "mesh.h" #include "material.h" +#include "mesh.h" namespace example { +/// Adapts an array of bytes to an array of T. Will advace of byte_stride each +/// elements. +template +struct arrayAdapter { + /// Pointer to the bytes + const unsigned char *dataPtr; + /// Number of elements in the array + const size_t elemCount; + /// Stride in bytes between two elements + const size_t stride; + + /// Construct an array adapter. + /// \param ptr Pointer to the start of the data, with offset applied + /// \param count Number of elements in the array + /// \param byte_stride Stride betweens elements in the array + arrayAdapter(const unsigned char *ptr, size_t count, size_t byte_stride) + : dataPtr(ptr), elemCount(count), stride(byte_stride) {} + + /// Returns a *copy* of a single element. Can't be used to modify it. + T operator[](size_t pos) const { + if (pos >= elemCount) + throw std::out_of_range( + "Tried to access beyond the last element of an array adapter with " + "count " + + std::to_string(elemCount) + " while getting elemnet number " + + std::to_string(pos)); + return *(reinterpret_cast(dataPtr + pos * stride)); + } +}; + +/// Interface of any adapted array that returns ingeger data +struct intArrayBase { + virtual ~intArrayBase() = default; + virtual unsigned int operator[](size_t) const = 0; + virtual size_t size() const = 0; +}; + +/// Interface of any adapted array that returns float data +struct floatArrayBase { + virtual ~floatArrayBase() = default; + virtual float operator[](size_t) const = 0; + virtual size_t size() const = 0; +}; + +/// An array that loads interger types, returns them as int +template +struct intArray : public intArrayBase { + arrayAdapter adapter; + + intArray(const arrayAdapter &a) : adapter(a) {} + unsigned int operator[](size_t position) const override { + return static_cast(adapter[position]); + } + + size_t size() const override { return adapter.elemCount; } +}; + +template +struct floatArray : public floatArrayBase { + arrayAdapter adapter; + + floatArray(const arrayAdapter &a) : adapter(a) {} + float operator[](size_t position) const override { + return static_cast(adapter[position]); + } + + size_t size() const override { return adapter.elemCount; } +}; + +#pragma pack(push, 1) + +template +struct v2 { + T x, y; +}; +/// 3D vector of floats without padding +template +struct v3 { + T x, y, z; +}; + +/// 4D vector of floats without padding +template +struct v4 { + T x, y, z, w; +}; + +#pragma pack(pop) + +using v2f = v2; +using v3f = v3; +using v4f = v4; +using v2d = v2; +using v3d = v3; +using v4d = v4; + +struct v2fArray { + arrayAdapter adapter; + v2fArray(const arrayAdapter &a) : adapter(a) {} + + v2f operator[](size_t position) const { return adapter[position]; } + size_t size() const { return adapter.elemCount; } +}; + +struct v3fArray { + arrayAdapter adapter; + v3fArray(const arrayAdapter &a) : adapter(a) {} + + v3f operator[](size_t position) const { return adapter[position]; } + size_t size() const { return adapter.elemCount; } +}; + +struct v4fArray { + arrayAdapter adapter; + v4fArray(const arrayAdapter &a) : adapter(a) {} + + v4f operator[](size_t position) const { return adapter[position]; } + size_t size() const { return adapter.elemCount; } +}; + +struct v2dArray { + arrayAdapter adapter; + v2dArray(const arrayAdapter &a) : adapter(a) {} + + v2d operator[](size_t position) const { return adapter[position]; } + size_t size() const { return adapter.elemCount; } +}; + +struct v3dArray { + arrayAdapter adapter; + v3dArray(const arrayAdapter &a) : adapter(a) {} + + v3d operator[](size_t position) const { return adapter[position]; } + size_t size() const { return adapter.elemCount; } +}; + +struct v4dArray { + arrayAdapter adapter; + v4dArray(const arrayAdapter &a) : adapter(a) {} + + v4d operator[](size_t position) const { return adapter[position]; } + size_t size() const { return adapter.elemCount; } +}; + /// /// Loads glTF 2.0 mesh /// -bool LoadGLTF(const std::string &filename, float scale, std::vector > *meshes, std::vector *materials, std::vector *textures); +bool LoadGLTF(const std::string &filename, float scale, + std::vector > *meshes, + std::vector *materials, std::vector *textures); -} +} // namespace example -#endif // EXAMPLE_GLTF_LOADER_H_ +#endif // EXAMPLE_GLTF_LOADER_H_ diff --git a/examples/raytrace/images/nanosg-demo.png b/examples/raytrace/images/nanosg-demo.png new file mode 100644 index 0000000..5715e58 Binary files /dev/null and b/examples/raytrace/images/nanosg-demo.png differ diff --git a/examples/raytrace/main.cc b/examples/raytrace/main.cc index 968c9bc..e4ae3ec 100644 --- a/examples/raytrace/main.cc +++ b/examples/raytrace/main.cc @@ -55,10 +55,10 @@ THE SOFTWARE. #include #include #include +#include +#include #include #include -#include -#include #include // C++11 #include // C++11 @@ -72,22 +72,23 @@ THE SOFTWARE. #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable: 4201) +#pragma warning(disable : 4201) #endif -#include "glm/mat4x4.hpp" -#include "glm/gtc/quaternion.hpp" #include "glm/gtc/matrix_transform.hpp" +#include "glm/gtc/quaternion.hpp" #include "glm/gtc/type_ptr.hpp" +#include "glm/mat4x4.hpp" #if defined(_MSC_VER) #pragma warning(pop) #endif +#include "gltf-loader.h" #include "nanosg.h" +#include "obj-loader.h" #include "render-config.h" #include "render.h" -#include "gltf-loader.h" #include "trackball.h" #ifdef WIN32 @@ -96,19 +97,17 @@ THE SOFTWARE. #endif #endif -#define SHOW_BUFFER_COLOR (0) -#define SHOW_BUFFER_NORMAL (1) -#define SHOW_BUFFER_POSITION (2) -#define SHOW_BUFFER_DEPTH (3) -#define SHOW_BUFFER_TEXCOORD (4) -#define SHOW_BUFFER_VARYCOORD (5) - -b3gDefaultOpenGLWindow* window = 0; +b3gDefaultOpenGLWindow *window = 0; int gWidth = 512; int gHeight = 512; int gMousePosX = -1, gMousePosY = -1; bool gMouseLeftDown = false; + +// FIX issue when max passes is done - no modes is switched. pass must be set to +// 0 when mode is changed +int gShowBufferMode_prv = SHOW_BUFFER_COLOR; int gShowBufferMode = SHOW_BUFFER_COLOR; + bool gTabPressed = false; bool gShiftPressed = false; float gShowPositionScale = 1.0f; @@ -128,8 +127,7 @@ std::atomic gSceneDirty; example::RenderConfig gRenderConfig; std::mutex gMutex; -struct RenderLayer -{ +struct RenderLayer { std::vector displayRGBA; // Accumurated image. std::vector rgba; std::vector auxRGBA; // Auxiliary buffer @@ -143,14 +141,12 @@ struct RenderLayer RenderLayer gRenderLayer; -struct Camera -{ +struct Camera { glm::mat4 view; glm::mat4 projection; }; -struct ManipConfig -{ +struct ManipConfig { glm::vec3 snapTranslation; glm::vec3 snapRotation; glm::vec3 snapScale; @@ -201,9 +197,12 @@ void RenderThread() { // gRenderCancel may be set to true in main loop. // Render() will repeatedly check this flag inside the rendering loop. - bool ret = - example::Renderer::Render(&gRenderLayer.rgba.at(0), &gRenderLayer.auxRGBA.at(0), &gRenderLayer.sampleCounts.at(0), - gCurrQuat, gScene, gAsset, gRenderConfig, gRenderCancel); + bool ret = example::Renderer::Render( + &gRenderLayer.rgba.at(0), &gRenderLayer.auxRGBA.at(0), + &gRenderLayer.sampleCounts.at(0), gCurrQuat, gScene, gAsset, + gRenderConfig, gRenderCancel, + gShowBufferMode // added mode passing + ); if (ret) { std::lock_guard guard(gMutex); @@ -219,16 +218,18 @@ void RenderThread() { } } -void InitRender(example::RenderConfig* rc) { +void InitRender(example::RenderConfig *rc) { rc->pass = 0; rc->max_passes = 128; gRenderLayer.sampleCounts.resize(rc->width * rc->height); - std::fill(gRenderLayer.sampleCounts.begin(), gRenderLayer.sampleCounts.end(), 0.0); + std::fill(gRenderLayer.sampleCounts.begin(), gRenderLayer.sampleCounts.end(), + 0.0); gRenderLayer.displayRGBA.resize(rc->width * rc->height * 4); - std::fill(gRenderLayer.displayRGBA.begin(), gRenderLayer.displayRGBA.end(), 0.0); + std::fill(gRenderLayer.displayRGBA.begin(), gRenderLayer.displayRGBA.end(), + 0.0); gRenderLayer.rgba.resize(rc->width * rc->height * 4); std::fill(gRenderLayer.rgba.begin(), gRenderLayer.rgba.end(), 0.0); @@ -237,19 +238,23 @@ void InitRender(example::RenderConfig* rc) { std::fill(gRenderLayer.auxRGBA.begin(), gRenderLayer.auxRGBA.end(), 0.0); gRenderLayer.normalRGBA.resize(rc->width * rc->height * 4); - std::fill(gRenderLayer.normalRGBA.begin(), gRenderLayer.normalRGBA.end(), 0.0); + std::fill(gRenderLayer.normalRGBA.begin(), gRenderLayer.normalRGBA.end(), + 0.0); gRenderLayer.positionRGBA.resize(rc->width * rc->height * 4); - std::fill(gRenderLayer.positionRGBA.begin(), gRenderLayer.positionRGBA.end(), 0.0); + std::fill(gRenderLayer.positionRGBA.begin(), gRenderLayer.positionRGBA.end(), + 0.0); gRenderLayer.depthRGBA.resize(rc->width * rc->height * 4); std::fill(gRenderLayer.depthRGBA.begin(), gRenderLayer.depthRGBA.end(), 0.0); gRenderLayer.texCoordRGBA.resize(rc->width * rc->height * 4); - std::fill(gRenderLayer.texCoordRGBA.begin(), gRenderLayer.texCoordRGBA.end(), 0.0); + std::fill(gRenderLayer.texCoordRGBA.begin(), gRenderLayer.texCoordRGBA.end(), + 0.0); gRenderLayer.varyCoordRGBA.resize(rc->width * rc->height * 4); - std::fill(gRenderLayer.varyCoordRGBA.begin(), gRenderLayer.varyCoordRGBA.end(), 0.0); + std::fill(gRenderLayer.varyCoordRGBA.begin(), + gRenderLayer.varyCoordRGBA.end(), 0.0); rc->normalImage = &gRenderLayer.normalRGBA.at(0); rc->positionImage = &gRenderLayer.positionRGBA.at(0); @@ -268,19 +273,18 @@ void checkErrors(std::string desc) { } } +static int CreateDisplayTextureGL(const float *data, int width, int height, + int components) { + GLuint id; + glGenTextures(1, &id); -static int CreateDisplayTextureGL(const float *data, int width, - int height, int components) { - GLuint id; - glGenTextures(1, &id); - GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); - + glBindTexture(GL_TEXTURE_2D, id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - + GLenum format = GL_RGBA; if (components == 1) { format = GL_LUMINANCE; @@ -290,15 +294,15 @@ static int CreateDisplayTextureGL(const float *data, int width, format = GL_RGB; } else if (components == 4) { format = GL_RGBA; - } else { - assert(0); // "Invalid components" - } - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, - GL_FLOAT, data); - + } else { + assert(0); // "Invalid components" + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_FLOAT, + data); + glBindTexture(GL_TEXTURE_2D, last_texture); - + return static_cast(id); } @@ -312,8 +316,10 @@ void keyboardCallback(int keycode, int state) { // reset. trackball(gCurrQuat, 0.0f, 0.0f, 0.0f, 0.0f); // clear buffer. - memset(gRenderLayer.rgba.data(), 0, sizeof(float) * gRenderConfig.width * gRenderConfig.height * 4); - memset(gRenderLayer.sampleCounts.data(), 0, sizeof(int) * gRenderConfig.width * gRenderConfig.height); + memset(gRenderLayer.rgba.data(), 0, + sizeof(float) * gRenderConfig.width * gRenderConfig.height * 4); + memset(gRenderLayer.sampleCounts.data(), 0, + sizeof(int) * gRenderConfig.width * gRenderConfig.height); } else if (keycode == 9) { gTabPressed = (state == 1); } else if (keycode == B3G_SHIFT) { @@ -330,7 +336,6 @@ void keyboardCallback(int keycode, int state) { } void mouseMoveCallback(float x, float y) { - if (gMouseLeftDown) { if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) { } else { @@ -371,7 +376,7 @@ void mouseButtonCallback(int button, int state, float x, float y) { (void)y; ImGui_ImplBtGui_SetMouseButtonState(button, (state == 1)); - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); if (io.WantCaptureMouse || io.WantCaptureKeyboard) { return; } @@ -395,7 +400,7 @@ void mouseButtonCallback(int button, int state, float x, float y) { } void resizeCallback(float width, float height) { - //GLfloat h = (GLfloat)height / (GLfloat)width; + // GLfloat h = (GLfloat)height / (GLfloat)width; GLfloat xmax, znear, zfar; znear = 1.0f; @@ -406,7 +411,7 @@ void resizeCallback(float width, float height) { gHeight = static_cast(height); } -inline float pesudoColor(float v, int ch) { +inline float pseudoColor(float v, int ch) { if (ch == 0) { // red if (v <= 0.5f) return 0.f; @@ -471,7 +476,7 @@ void UpdateDisplayTextureGL(GLint tex_id, int width, int height) { for (size_t i = 0; i < buf.size(); i++) { float v = (gRenderLayer.depthRGBA[i] - d_min) / d_diff; if (gShowDepthPeseudoColor) { - buf[i] = pesudoColor(v, i % 4); + buf[i] = pseudoColor(v, i % 4); } else { buf[i] = v; } @@ -491,31 +496,31 @@ void UpdateDisplayTextureGL(GLint tex_id, int width, int height) { disp.resize(width * height * 4); { for (size_t y = 0; y < height; y++) { - memcpy(&disp[4 * (y * width)], &buf[4 * ((height - y - 1) * width)], sizeof(float) * 4 * width); + memcpy(&disp[4 * (y * width)], &buf[4 * ((height - y - 1) * width)], + sizeof(float) * 4 * width); } - } glBindTexture(GL_TEXTURE_2D, tex_id); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, disp.data()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, + disp.data()); glBindTexture(GL_TEXTURE_2D, 0); - //glRasterPos2i(-1, -1); - //glDrawPixels(width, height, GL_RGBA, GL_FLOAT, + // glRasterPos2i(-1, -1); + // glDrawPixels(width, height, GL_RGBA, GL_FLOAT, // static_cast(&buf.at(0))); } -void EditTransform(const ManipConfig &config, const Camera& camera, glm::mat4& matrix) -{ +void EditTransform(const ManipConfig &config, const Camera &camera, + glm::mat4 &matrix) { static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE); static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD); - if (ImGui::IsKeyPressed(90)) - mCurrentGizmoOperation = ImGuizmo::TRANSLATE; - if (ImGui::IsKeyPressed(69)) - mCurrentGizmoOperation = ImGuizmo::ROTATE; - if (ImGui::IsKeyPressed(82)) // r Key + if (ImGui::IsKeyPressed(90)) mCurrentGizmoOperation = ImGuizmo::TRANSLATE; + if (ImGui::IsKeyPressed(69)) mCurrentGizmoOperation = ImGuizmo::ROTATE; + if (ImGui::IsKeyPressed(82)) // r Key mCurrentGizmoOperation = ImGuizmo::SCALE; - if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE)) + if (ImGui::RadioButton("Translate", + mCurrentGizmoOperation == ImGuizmo::TRANSLATE)) mCurrentGizmoOperation = ImGuizmo::TRANSLATE; ImGui::SameLine(); if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE)) @@ -524,14 +529,15 @@ void EditTransform(const ManipConfig &config, const Camera& camera, glm::mat4& m if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE)) mCurrentGizmoOperation = ImGuizmo::SCALE; float matrixTranslation[3], matrixRotation[3], matrixScale[3]; - ImGuizmo::DecomposeMatrixToComponents(&matrix[0][0], matrixTranslation, matrixRotation, matrixScale); + ImGuizmo::DecomposeMatrixToComponents(&matrix[0][0], matrixTranslation, + matrixRotation, matrixScale); ImGui::InputFloat3("Tr", matrixTranslation, 3); ImGui::InputFloat3("Rt", matrixRotation, 3); ImGui::InputFloat3("Sc", matrixScale, 3); - ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, &matrix[0][0]); + ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, + matrixScale, &matrix[0][0]); - if (mCurrentGizmoOperation != ImGuizmo::SCALE) - { + if (mCurrentGizmoOperation != ImGuizmo::SCALE) { if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL)) mCurrentGizmoMode = ImGuizmo::LOCAL; ImGui::SameLine(); @@ -539,33 +545,32 @@ void EditTransform(const ManipConfig &config, const Camera& camera, glm::mat4& m mCurrentGizmoMode = ImGuizmo::WORLD; } static bool useSnap(false); - if (ImGui::IsKeyPressed(83)) - useSnap = !useSnap; + if (ImGui::IsKeyPressed(83)) useSnap = !useSnap; ImGui::Checkbox("", &useSnap); ImGui::SameLine(); glm::vec3 snap; - switch (mCurrentGizmoOperation) - { - case ImGuizmo::TRANSLATE: - snap = config.snapTranslation; - ImGui::InputFloat3("Snap", &snap.x); - break; - case ImGuizmo::ROTATE: - snap = config.snapRotation; - ImGui::InputFloat("Angle Snap", &snap.x); - break; - case ImGuizmo::SCALE: - snap = config.snapScale; - ImGui::InputFloat("Scale Snap", &snap.x); - break; + switch (mCurrentGizmoOperation) { + case ImGuizmo::TRANSLATE: + snap = config.snapTranslation; + ImGui::InputFloat3("Snap", &snap.x); + break; + case ImGuizmo::ROTATE: + snap = config.snapRotation; + ImGui::InputFloat("Angle Snap", &snap.x); + break; + case ImGuizmo::SCALE: + snap = config.snapScale; + ImGui::InputFloat("Scale Snap", &snap.x); + break; } - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); - ImGuizmo::Manipulate(&camera.view[0][0], &camera.projection[0][0], mCurrentGizmoOperation, mCurrentGizmoMode, &matrix[0][0], NULL, useSnap ? &snap.x : NULL); + ImGuizmo::Manipulate(&camera.view[0][0], &camera.projection[0][0], + mCurrentGizmoOperation, mCurrentGizmoMode, &matrix[0][0], + NULL, useSnap ? &snap.x : NULL); } -void DrawMesh(const example::Mesh *mesh) -{ +void DrawMesh(const example::Mesh *mesh) { // TODO(LTE): Use vertex array or use display list. glBegin(GL_TRIANGLES); @@ -579,20 +584,17 @@ void DrawMesh(const example::Mesh *mesh) glNormal3f(mesh->facevarying_normals[9 * i + 0], mesh->facevarying_normals[9 * i + 1], mesh->facevarying_normals[9 * i + 2]); - glVertex3f(mesh->vertices[3 * f0 + 0], - mesh->vertices[3 * f0 + 1], + glVertex3f(mesh->vertices[3 * f0 + 0], mesh->vertices[3 * f0 + 1], mesh->vertices[3 * f0 + 2]); glNormal3f(mesh->facevarying_normals[9 * i + 3], mesh->facevarying_normals[9 * i + 4], mesh->facevarying_normals[9 * i + 5]); - glVertex3f(mesh->vertices[3 * f1 + 0], - mesh->vertices[3 * f1 + 1], + glVertex3f(mesh->vertices[3 * f1 + 0], mesh->vertices[3 * f1 + 1], mesh->vertices[3 * f1 + 2]); glNormal3f(mesh->facevarying_normals[9 * i + 6], mesh->facevarying_normals[9 * i + 7], mesh->facevarying_normals[9 * i + 8]); - glVertex3f(mesh->vertices[3 * f2 + 0], - mesh->vertices[3 * f2 + 1], + glVertex3f(mesh->vertices[3 * f2 + 0], mesh->vertices[3 * f2 + 1], mesh->vertices[3 * f2 + 2]); } @@ -602,23 +604,19 @@ void DrawMesh(const example::Mesh *mesh) unsigned int f1 = mesh->faces[3 * i + 1]; unsigned int f2 = mesh->faces[3 * i + 2]; - glVertex3f(mesh->vertices[3 * f0 + 0], - mesh->vertices[3 * f0 + 1], + glVertex3f(mesh->vertices[3 * f0 + 0], mesh->vertices[3 * f0 + 1], mesh->vertices[3 * f0 + 2]); - glVertex3f(mesh->vertices[3 * f1 + 0], - mesh->vertices[3 * f1 + 1], + glVertex3f(mesh->vertices[3 * f1 + 0], mesh->vertices[3 * f1 + 1], mesh->vertices[3 * f1 + 2]); - glVertex3f(mesh->vertices[3 * f2 + 0], - mesh->vertices[3 * f2 + 1], + glVertex3f(mesh->vertices[3 * f2 + 0], mesh->vertices[3 * f2 + 1], mesh->vertices[3 * f2 + 2]); } } - glEnd(); + glEnd(); } -void DrawNode(const nanosg::Node > &node) -{ +void DrawNode(const nanosg::Node > &node) { glPushMatrix(); glMultMatrixf(node.GetLocalXformPtr()); @@ -634,8 +632,8 @@ void DrawNode(const nanosg::Node > &node) } // Draw scene with OpenGL -void DrawScene(const nanosg::Scene > &scene, const Camera &camera) -{ +void DrawScene(const nanosg::Scene > &scene, + const Camera &camera) { glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); @@ -649,11 +647,12 @@ void DrawScene(const nanosg::Scene > &scene, const C const float light_diffuse[4] = {0.5f, 0.5f, 0.5f, 1.0f}; glLightfv(GL_LIGHT0, GL_POSITION, &light0_pos[0]); - glLightfv(GL_LIGHT0, GL_DIFFUSE, &light_diffuse[0]); + glLightfv(GL_LIGHT0, GL_DIFFUSE, &light_diffuse[0]); glLightfv(GL_LIGHT1, GL_POSITION, &light1_pos[0]); - glLightfv(GL_LIGHT1, GL_DIFFUSE, &light_diffuse[0]); + glLightfv(GL_LIGHT1, GL_DIFFUSE, &light_diffuse[0]); - const std::vector > > &root_nodes = scene.GetNodes(); + const std::vector > > &root_nodes = + scene.GetNodes(); glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -675,15 +674,12 @@ void DrawScene(const nanosg::Scene > &scene, const C glDisable(GL_LIGHT1); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); - } -void BuildSceneItems( - std::vector *display_names, - std::vector *names, - const nanosg::Node > &node, - int indent) -{ +void BuildSceneItems(std::vector *display_names, + std::vector *names, + const nanosg::Node > &node, + int indent) { if (node.GetName().empty()) { // Skip a node with empty name. return; @@ -699,14 +695,16 @@ void BuildSceneItems( display_names->push_back(display_name); names->push_back(node.GetName()); - + for (size_t i = 0; i < node.GetChildren().size(); i++) { BuildSceneItems(display_names, names, node.GetChildren()[i], indent + 1); } - } -int main(int argc, char** argv) { +// tigra: add default material +example::Material default_material; + +int main(int argc, char **argv) { std::string config_filename = "config.json"; if (argc > 1) { @@ -729,13 +727,43 @@ int main(int argc, char** argv) { std::vector materials; std::vector textures; - bool ret = LoadGLTF(gRenderConfig.gltf_filename, gRenderConfig.scene_scale, &meshes, &materials, &textures); - if (!ret) { - std::cerr << "Failed to load glTF [ " << gRenderConfig.gltf_filename << " ]" << std::endl; - return -1; + // tigra: set default material to 95% white diffuse + default_material.diffuse[0] = 0.95f; + default_material.diffuse[1] = 0.95f; + default_material.diffuse[2] = 0.95f; + + default_material.specular[0] = 0; + default_material.specular[1] = 0; + default_material.specular[2] = 0; + + // Material pushed as first material on the list + materials.push_back(default_material); + + if (!gRenderConfig.obj_filename.empty()) { + bool ret = LoadObj(gRenderConfig.obj_filename, gRenderConfig.scene_scale, + &meshes, &materials, &textures); + if (!ret) { + std::cerr << "Failed to load .obj [ " << gRenderConfig.obj_filename + << " ]" << std::endl; + return -1; + } + } + + if (!gRenderConfig.gltf_filename.empty()) { + std::cout << "Found gltf file : " << gRenderConfig.gltf_filename << "\n"; + + bool ret = + LoadGLTF(gRenderConfig.gltf_filename, gRenderConfig.scene_scale, + &meshes, &materials, &textures); + if (!ret) { + std::cerr << "Failed to load glTF file [ " + << gRenderConfig.gltf_filename << " ]" << std::endl; + return -1; + } } gAsset.materials = materials; + gAsset.default_material = default_material; gAsset.textures = textures; for (size_t n = 0; n < meshes.size(); n++) { @@ -744,12 +772,20 @@ int main(int argc, char** argv) { } for (size_t n = 0; n < gAsset.meshes.size(); n++) { - nanosg::Node > node(&gAsset.meshes[n]); + + // case where the name of a mesh isn't defined in the loaded file + if (gAsset.meshes[n].name.empty()) { + std::string generatedName = "unnamed_" + std::to_string(n); + gAsset.meshes[n].name = generatedName; + meshes[n].name = generatedName; + } + node.SetName(meshes[n].name); - node.SetLocalXform(meshes[n].pivot_xform); // Use mesh's pivot transform as node's local transform. + node.SetLocalXform(meshes[n].pivot_xform); // Use mesh's pivot transform + // as node's local transform. gNodes.push_back(node); - + gScene.AddNode(node); } @@ -761,11 +797,12 @@ int main(int argc, char** argv) { float bmin[3], bmax[3]; gScene.GetBoundingBox(bmin, bmax); printf(" # of nodes : %d\n", int(gNodes.size())); - printf(" Scene Bmin : %f, %f, %f\n", bmin[0], bmin[1], bmin[2]); - printf(" Scene Bmax : %f, %f, %f\n", bmax[0], bmax[1], bmax[2]); - + printf(" Scene Bmin : %f, %f, %f\n", bmin[0], bmin[1], + bmin[2]); + printf(" Scene Bmax : %f, %f, %f\n", bmax[0], bmax[1], + bmax[2]); } - + std::vector imgui_node_names; std::vector display_node_names; std::vector node_names; @@ -773,13 +810,14 @@ int main(int argc, char** argv) { { for (size_t i = 0; i < gScene.GetNodes().size(); i++) { - BuildSceneItems(&display_node_names, &node_names, gScene.GetNodes()[i], /* indent */0); + BuildSceneItems(&display_node_names, &node_names, gScene.GetNodes()[i], + /* indent */ 0); } // List of strings for imgui. // Assume nodes in the scene does not change. for (size_t i = 0; i < display_node_names.size(); i++) { - //std::cout << "name : " << display_node_names[i] << std::endl; + // std::cout << "name : " << display_node_names[i] << std::endl; imgui_node_names.push_back(display_node_names[i].c_str()); } @@ -788,13 +826,13 @@ int main(int argc, char** argv) { nanosg::Node > *node; if (gScene.FindNode(node_names[i], &node)) { - //std::cout << "id : " << i << ", name : " << node_names[i] << std::endl; + // std::cout << "id : " << i << ", name : " << node_names[i] << + // std::endl; node_map[i] = node; } } } - window = new b3gDefaultOpenGLWindow; b3gWindowConstructionInfo ci; #ifdef USE_OPENGL2 @@ -836,9 +874,9 @@ int main(int argc, char** argv) { ImGui_ImplBtGui_Init(window); - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("./DroidSans.ttf", 15.0f); + // io.Fonts->AddFontFromFileTTF("./DroidSans.ttf", 15.0f); glm::mat4 projection(1.0f); glm::mat4 view(1.0f); @@ -861,7 +899,7 @@ int main(int argc, char** argv) { ImGuizmo::BeginFrame(); ImGuizmo::Enable(true); - //ImGuiIO &io = ImGui::GetIO(); + // ImGuiIO &io = ImGui::GetIO(); ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y); ImGui::Begin("UI"); @@ -897,7 +935,7 @@ int main(int argc, char** argv) { ImGui::InputFloat("show pos scale", &gShowPositionScale); ImGui::InputFloat2("show depth range", gShowDepthRange); - ImGui::Checkbox("show depth pesudo color", &gShowDepthPeseudoColor); + ImGui::Checkbox("show depth pseudo color", &gShowDepthPeseudoColor); } ImGui::End(); @@ -908,38 +946,47 @@ int main(int argc, char** argv) { checkErrors("clear"); + // fix max passes issue + if (gShowBufferMode_prv != gShowBufferMode) { + gRenderConfig.pass = 0; + gShowBufferMode_prv = gShowBufferMode; + } // Render display window { static GLint gl_texid = -1; if (gl_texid < 0) { - gl_texid = CreateDisplayTextureGL(NULL, gRenderConfig.width, gRenderConfig.height, 4); + gl_texid = CreateDisplayTextureGL(NULL, gRenderConfig.width, + gRenderConfig.height, 4); } // Refresh texture until rendering finishes. if (gRenderConfig.pass < gRenderConfig.max_passes) { // FIXME(LTE): Do not update GL texture frequently. - UpdateDisplayTextureGL(gl_texid, gRenderConfig.width, gRenderConfig.height); + UpdateDisplayTextureGL(gl_texid, gRenderConfig.width, + gRenderConfig.height); } ImGui::Begin("Render"); - ImTextureID tex_id = reinterpret_cast( - static_cast(gl_texid)); + ImTextureID tex_id = + reinterpret_cast(static_cast(gl_texid)); ImGui::Image(tex_id, ImVec2(256, 256), ImVec2(0, 0), - ImVec2(1, 1));// Setup camera and draw imguizomo + ImVec2(1, 1)); // Setup camera and draw imguizomo ImGui::End(); - } // scene graph tree glm::mat4 node_matrix; - static int node_selected = 0; + static int node_selected_index = 0; { ImGui::Begin("Scene"); - ImGui::ListBox("Node list", &node_selected, imgui_node_names.data(), imgui_node_names.size(), 16); - node_matrix = glm::make_mat4(node_map[node_selected]->GetLocalXformPtr()); + ImGui::ListBox("Node list", &node_selected_index, imgui_node_names.data(), + imgui_node_names.size(), 16); + + auto node_selected = node_map.at(node_selected_index); + node_matrix = glm::make_mat4(node_selected->GetLocalXformPtr()); ImGui::End(); } @@ -964,11 +1011,14 @@ int main(int argc, char** argv) { up[2] = gRenderConfig.up[2]; // NOTE(LTE): w, then (x,y,z) for glm::quat. - glm::quat rot = glm::quat(gCurrQuat[3], gCurrQuat[0], gCurrQuat[1], gCurrQuat[2]); + glm::quat rot = + glm::quat(gCurrQuat[3], gCurrQuat[0], gCurrQuat[1], gCurrQuat[2]); glm::mat4 rm = glm::mat4_cast(rot); view = glm::lookAt(eye, lookat, up) * glm::inverse(glm::mat4_cast(rot)); - projection = glm::perspective (45.0f, float(window->getWidth()) / float(window->getHeight()), 0.01f, 1000.0f); + projection = glm::perspective( + 45.0f, float(window->getWidth()) / float(window->getHeight()), 0.01f, + 1000.0f); camera.view = view; camera.projection = projection; @@ -978,10 +1028,10 @@ int main(int argc, char** argv) { float mat[4][4]; memcpy(mat, &node_matrix[0][0], sizeof(float) * 16); - node_map[node_selected]->SetLocalXform(mat); + node_map[node_selected_index]->SetLocalXform(mat); checkErrors("edit_transform"); - + ImGui::End(); } diff --git a/examples/raytrace/material.h b/examples/raytrace/material.h index ec3a330..c11b953 100644 --- a/examples/raytrace/material.h +++ b/examples/raytrace/material.h @@ -3,9 +3,14 @@ #include -namespace example { +#ifdef __clang__ +#pragma clang diagnostic push +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#endif -// TODO(syoyo): Support PBR material. +namespace example { struct Material { // float ambient[3]; @@ -53,6 +58,7 @@ struct Texture { int width; int height; int components; + int _pad_; unsigned char* image; Texture() { diff --git a/examples/raytrace/mesh.h b/examples/raytrace/mesh.h index 90b1087..4261673 100644 --- a/examples/raytrace/mesh.h +++ b/examples/raytrace/mesh.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace example { @@ -69,9 +70,13 @@ inline void calculate_normal(T Nn[3], const T v0[3], const T v1[3], const T v2[3 template class Mesh { public: + explicit Mesh(const size_t vertex_stride) : + stride(vertex_stride) { + } + std::string name; - std::vector vertices; /// [xyz] * num_vertices + std::vector vertices; /// stride * num_vertices std::vector facevarying_normals; /// [xyz] * 3(triangle) * num_faces std::vector facevarying_tangents; /// [xyz] * 3(triangle) * num_faces std::vector facevarying_binormals; /// [xyz] * 3(triangle) * num_faces @@ -82,6 +87,7 @@ class Mesh { std::vector material_ids; /// index x num_faces T pivot_xform[4][4]; + size_t stride; /// stride for vertex data. // --- Required methods in Scene::Traversal. --- diff --git a/examples/raytrace/nanort.cc b/examples/raytrace/nanort.cc new file mode 100644 index 0000000..0877ad6 --- /dev/null +++ b/examples/raytrace/nanort.cc @@ -0,0 +1 @@ +#include "nanort.h" diff --git a/examples/raytrace/nanort.h b/examples/raytrace/nanort.h index 10f486c..169e464 100644 --- a/examples/raytrace/nanort.h +++ b/examples/raytrace/nanort.h @@ -44,6 +44,13 @@ THE SOFTWARE. namespace nanort { +#ifdef __clang__ +#pragma clang diagnostic push +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#endif + // Parallelized BVH build is not yet fully tested, // thus turn off if you face a problem when building BVH. #define NANORT_ENABLE_PARALLEL_BUILD (1) @@ -301,9 +308,7 @@ class real3 { real3 operator/(const real3 &f2) const { return real3(x() / f2.x(), y() / f2.y(), z() / f2.z()); } - real3 operator-() const { - return real3(-x(), -y(), -z()); - } + real3 operator-() const { return real3(-x(), -y(), -z()); } T operator[](int i) const { return v[i]; } T &operator[](int i) { return v[i]; } @@ -330,8 +335,8 @@ template inline real3 vnormalize(const real3 &rhs) { real3 v = rhs; T len = vlength(rhs); - if (fabs(len) > 1.0e-6f) { - float inv_len = 1.0f / len; + if (std::fabs(len) > static_cast(1.0e-6)) { + T inv_len = static_cast(1.0) / len; v.v[0] *= inv_len; v.v[1] *= inv_len; v.v[2] *= inv_len; @@ -363,9 +368,7 @@ inline const real *get_vertex_addr(const real *p, const size_t idx, template class Ray { public: - Ray() - : min_t(static_cast(0.0)) - , max_t(std::numeric_limits::max()) { + Ray() : min_t(static_cast(0.0)), max_t(std::numeric_limits::max()) { org[0] = static_cast(0.0); org[1] = static_cast(0.0); org[2] = static_cast(0.0); @@ -374,11 +377,11 @@ class Ray { dir[2] = static_cast(-1.0); } - T org[3]; // must set - T dir[3]; // must set - T min_t; // minium ray hit distance. - T max_t; // maximum ray hit distance. - T inv_dir[3]; // filled internally + T org[3]; // must set + T dir[3]; // must set + T min_t; // minimum ray hit distance. + T max_t; // maximum ray hit distance. + T inv_dir[3]; // filled internally int dir_sign[3]; // filled internally }; @@ -386,6 +389,38 @@ template class BVHNode { public: BVHNode() {} + BVHNode(const BVHNode &rhs) { + bmin[0] = rhs.bmin[0]; + bmin[1] = rhs.bmin[1]; + bmin[2] = rhs.bmin[2]; + flag = rhs.flag; + + bmax[0] = rhs.bmax[0]; + bmax[1] = rhs.bmax[1]; + bmax[2] = rhs.bmax[2]; + axis = rhs.axis; + + data[0] = rhs.data[0]; + data[1] = rhs.data[1]; + } + + BVHNode &operator=(const BVHNode &rhs) { + bmin[0] = rhs.bmin[0]; + bmin[1] = rhs.bmin[1]; + bmin[2] = rhs.bmin[2]; + flag = rhs.flag; + + bmax[0] = rhs.bmax[0]; + bmax[1] = rhs.bmax[1]; + bmax[2] = rhs.bmax[2]; + axis = rhs.axis; + + data[0] = rhs.data[0]; + data[1] = rhs.data[1]; + + return (*this); + } + ~BVHNode() {} T bmin[3]; @@ -480,14 +515,26 @@ class BBox { } }; -template -class NodeHit -{ +template +class NodeHit { public: NodeHit() - : t_min(std::numeric_limits::max()) - , t_max(-std::numeric_limits::max()) - , node_id(static_cast(-1)) { + : t_min(std::numeric_limits::max()), + t_max(-std::numeric_limits::max()), + node_id(static_cast(-1)) {} + + NodeHit(const NodeHit &rhs) { + t_min = rhs.t_min; + t_max = rhs.t_max; + node_id = rhs.node_id; + } + + NodeHit &operator=(const NodeHit &rhs) { + t_min = rhs.t_min; + t_max = rhs.t_max; + node_id = rhs.node_id; + + return (*this); } ~NodeHit() {} @@ -497,9 +544,8 @@ class NodeHit unsigned int node_id; }; -template -class NodeHitComparator -{ +template +class NodeHitComparator { public: inline bool operator()(const NodeHit &a, const NodeHit &b) { return a.t_min < b.t_min; @@ -512,29 +558,37 @@ class BVHAccel { BVHAccel() : pad0_(0) { (void)pad0_; } ~BVHAccel() {} + /// /// Build BVH for input primitives. - template - bool Build(const unsigned int num_primitives, - const P &p, const Pred &pred, const BVHBuildOptions &options = BVHBuildOptions()); + /// + template + bool Build(const unsigned int num_primitives, const P &p, const Pred &pred, + const BVHBuildOptions &options = BVHBuildOptions()); + /// /// Get statistics of built BVH tree. Valid after Build() + /// BVHBuildStatistics GetStatistics() const { return stats_; } + /// /// Dump built BVH to the file. + /// bool Dump(const char *filename); + /// /// Load BVH binary + /// bool Load(const char *filename); void Debug(); + /// /// Traverse into BVH along ray and find closest hit point & primitive if /// found - template - bool Traverse(const Ray &ray, - const I &intersector, - H *isect, - const BVHTraceOptions& options = BVHTraceOptions()) const; + /// + template + bool Traverse(const Ray &ray, const I &intersector, H *isect, + const BVHTraceOptions &options = BVHTraceOptions()) const; #if 0 /// Multi-hit ray traversal @@ -551,16 +605,17 @@ class BVHAccel { /// List up nodes which intersects along the ray. /// This function is useful for two-level BVH traversal. /// - template - bool ListNodeIntersections(const Ray &ray, - int max_intersections, + template + bool ListNodeIntersections(const Ray &ray, int max_intersections, const I &intersector, StackVector, 128> *hits) const; const std::vector > &GetNodes() const { return nodes_; } const std::vector &GetIndices() const { return indices_; } + /// /// Returns bounding box of built BVH. + /// void BoundingBox(T bmin[3], T bmax[3]) const { if (nodes_.empty()) { bmin[0] = bmin[1] = bmin[2] = std::numeric_limits::max(); @@ -589,7 +644,7 @@ class BVHAccel { std::vector shallow_node_infos_; /// Builds shallow BVH tree recursively. - template + template unsigned int BuildShallowTree(std::vector > *out_nodes, unsigned int left_idx, unsigned int right_idx, unsigned int depth, @@ -598,22 +653,22 @@ class BVHAccel { #endif /// Builds BVH tree recursively. - template + template unsigned int BuildTree(BVHBuildStatistics *out_stat, std::vector > *out_nodes, unsigned int left_idx, unsigned int right_idx, unsigned int depth, const P &p, const Pred &pred); - template + template bool TestLeafNode(const BVHNode &node, const Ray &ray, const I &intersector) const; - template - bool TestLeafNodeIntersections(const BVHNode &node, - const Ray &ray, - const int max_intersections, - const I &intersector, - std::priority_queue, std::vector >, NodeHitComparator > *isect_pq) const; + template + bool TestLeafNodeIntersections( + const BVHNode &node, const Ray &ray, const int max_intersections, + const I &intersector, + std::priority_queue, std::vector >, + NodeHitComparator > *isect_pq) const; #if 0 template @@ -663,7 +718,7 @@ class TriangleSAHPred { T center = p0[axis] + p1[axis] + p2[axis]; - return (center < pos * 3.0); + return (center < pos * static_cast(3.0)); } private: @@ -762,7 +817,7 @@ class TriangleIntersector { /// distance `t`, /// varycentric coordinate `u` and `v`. /// Returns true if there's intersection. - bool Intersect(T *t_inout, unsigned int prim_index) const { + bool Intersect(T *t_inout, const unsigned int prim_index) const { if ((prim_index < trace_options_.prim_ids_range[0]) || (prim_index >= trace_options_.prim_ids_range[1])) { return false; @@ -791,8 +846,13 @@ class TriangleIntersector { T V = Ax * Cy - Ay * Cx; T W = Bx * Ay - By * Ax; +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfloat-equal" +#endif + // Fall back to test against edges using double precision. - if (U == 0.0 || V == 0.0 || W == 0.0) { + if (U == static_cast(0.0) || V == static_cast(0.0) || W == static_cast(0.0)) { double CxBy = static_cast(Cx) * static_cast(By); double CyBx = static_cast(Cy) * static_cast(Bx); U = static_cast(CxBy - CyBx); @@ -807,15 +867,19 @@ class TriangleIntersector { } if (trace_options_.cull_back_face) { - if (U < 0.0 || V < 0.0 || W < 0.0) return false; + if (U < static_cast(0.0) || V < static_cast(0.0) || W < static_cast(0.0)) return false; } else { - if ((U < 0.0 || V < 0.0 || W < 0.0) && (U > 0.0 || V > 0.0 || W > 0.0)) { + if ((U < static_cast(0.0) || V < static_cast(0.0) || W < static_cast(0.0)) && (U > static_cast(0.0) || V > static_cast(0.0) || W > static_cast(0.0))) { return false; } } T det = U + V + W; - if (det == 0.0) return false; + if (det == static_cast(0.0)) return false; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif const T Az = ray_coeff_.Sz * A[ray_coeff_.kz]; const T Bz = ray_coeff_.Sz * B[ray_coeff_.kz]; @@ -829,6 +893,10 @@ class TriangleIntersector { return false; } + if (tt < t_min_) { + return false; + } + (*t_inout) = tt; // Use Thomas-Mueller style barycentric coord. // U + V + W = 1.0 and interp(p) = U * p0 + V * p1 + W * p2 @@ -884,6 +952,8 @@ class TriangleIntersector { trace_options_ = trace_options; + t_min_ = ray.min_t; + u_ = 0.0f; v_ = 0.0f; } @@ -901,19 +971,20 @@ class TriangleIntersector { } private: - const T *vertices_; const unsigned int *faces_; const size_t vertex_stride_bytes_; - + mutable real3 ray_org_; mutable RayCoeff ray_coeff_; mutable BVHTraceOptions trace_options_; + mutable T t_min_; - mutable T t_; - mutable T u_; - mutable T v_; + mutable T t_; + mutable T u_; + mutable T v_; mutable unsigned int prim_id_; + int _pad_; }; // @@ -950,7 +1021,8 @@ struct BinBuffer { template inline T CalculateSurfaceArea(const real3 &min, const real3 &max) { real3 box = max - min; - return static_cast(2.0) * (box[0] * box[1] + box[1] * box[2] + box[2] * box[0]); + return static_cast(2.0) * + (box[0] * box[1] + box[1] * box[2] + box[2] * box[0]); } template @@ -994,12 +1066,12 @@ inline void ContributeBinBuffer(BinBuffer *bins, // [out] real3 scene_size, scene_inv_size; scene_size = scene_max - scene_min; for (int i = 0; i < 3; ++i) { - assert(scene_size[i] >= 0.0); + assert(scene_size[i] >= static_cast(0.0)); - if (scene_size[i] > 0.0) { + if (scene_size[i] > static_cast(0.0)) { scene_inv_size[i] = bin_size / scene_size[i]; } else { - scene_inv_size[i] = 0.0; + scene_inv_size[i] = static_cast(0.0); } } @@ -1057,7 +1129,8 @@ inline T SAH(size_t ns1, T leftArea, size_t ns2, T rightArea, T invS, T Taabb, T Ttri) { T sah; - sah = static_cast(2.0) * Taabb + (leftArea * invS) * static_cast(ns1) * Ttri + + sah = static_cast(2.0) * Taabb + + (leftArea * invS) * static_cast(ns1) * Ttri + (rightArea * invS) * static_cast(ns2) * Ttri; return sah; @@ -1079,22 +1152,22 @@ inline bool FindCutFromBinBuffer(T *cut_pos, // [out] xyz T pos; T minCost[3]; - T costTtri = 1.0f - costTaabb; + T costTtri = static_cast(1.0) - costTaabb; (*minCostAxis) = 0; bsize = bmax - bmin; - bstep = bsize * (1.0f / bins->bin_size); + bstep = bsize * (static_cast(1.0) / bins->bin_size); saTotal = CalculateSurfaceArea(bmin, bmax); - T invSaTotal = 0.0f; + T invSaTotal = static_cast(0.0); if (saTotal > kEPS) { - invSaTotal = 1.0f / saTotal; + invSaTotal = static_cast(1.0) / saTotal; } for (int j = 0; j < 3; ++j) { // - // Compute SAH cost for right side of each cell of the bbox. + // Compute SAH cost for the right side of each cell of the bbox. // Exclude both extreme side of the bbox. // // i: 0 1 2 3 @@ -1103,7 +1176,7 @@ inline bool FindCutFromBinBuffer(T *cut_pos, // [out] xyz // +----+----+----+----+----+ // - T minCostPos = bmin[j] + 0.5f * bstep[j]; + T minCostPos = bmin[j] + static_cast(1.0) * bstep[j]; minCost[j] = std::numeric_limits::max(); left = 0; @@ -1127,7 +1200,7 @@ inline bool FindCutFromBinBuffer(T *cut_pos, // [out] xyz // +1 for i since we want a position on right side of the cell. // - pos = bmin[j] + (i + 0.5f) * bstep[j]; + pos = bmin[j] + (i + static_cast(1.0)) * bstep[j]; bmaxLeft[j] = pos; bminRight[j] = pos; @@ -1280,11 +1353,14 @@ inline void GetBoundingBox(real3 *bmin, real3 *bmax, // #if NANORT_ENABLE_PARALLEL_BUILD -template template -unsigned int BVHAccel::BuildShallowTree( - std::vector > *out_nodes, unsigned int left_idx, - unsigned int right_idx, unsigned int depth, unsigned int max_shallow_depth, - const P &p, const Pred &pred) { +template +template +unsigned int BVHAccel::BuildShallowTree(std::vector > *out_nodes, + unsigned int left_idx, + unsigned int right_idx, + unsigned int depth, + unsigned int max_shallow_depth, + const P &p, const Pred &pred) { assert(left_idx <= right_idx); unsigned int offset = static_cast(out_nodes->size()); @@ -1424,11 +1500,13 @@ unsigned int BVHAccel::BuildShallowTree( } #endif -template template -unsigned int BVHAccel::BuildTree( - BVHBuildStatistics *out_stat, std::vector > *out_nodes, - unsigned int left_idx, unsigned int right_idx, unsigned int depth, - const P &p, const Pred &pred) { +template +template +unsigned int BVHAccel::BuildTree(BVHBuildStatistics *out_stat, + std::vector > *out_nodes, + unsigned int left_idx, + unsigned int right_idx, unsigned int depth, + const P &p, const Pred &pred) { assert(left_idx <= right_idx); unsigned int offset = static_cast(out_nodes->size()); @@ -1554,10 +1632,10 @@ unsigned int BVHAccel::BuildTree( return offset; } -template template -bool BVHAccel::Build(unsigned int num_primitives, - const P &p, const Pred &pred, - const BVHBuildOptions &options) { +template +template +bool BVHAccel::Build(unsigned int num_primitives, const P &p, + const Pred &pred, const BVHBuildOptions &options) { options_ = options; stats_ = BVHBuildStatistics(); @@ -1566,6 +1644,10 @@ bool BVHAccel::Build(unsigned int num_primitives, assert(options_.bin_size > 1); + if (num_primitives == 0) { + return false; + } + unsigned int n = num_primitives; // @@ -1697,15 +1779,9 @@ void BVHAccel::Debug() { } for (size_t i = 0; i < nodes_.size(); i++) { - printf("node[%d] : bmin %f, %f, %f, bmax %f, %f, %f\n", - int(i), - nodes_[i].bmin[0], - nodes_[i].bmin[1], - nodes_[i].bmin[1], - nodes_[i].bmax[0], - nodes_[i].bmax[1], - nodes_[i].bmax[1]); - + printf("node[%d] : bmin %f, %f, %f, bmax %f, %f, %f\n", int(i), + nodes_[i].bmin[0], nodes_[i].bmin[1], nodes_[i].bmin[1], + nodes_[i].bmax[0], nodes_[i].bmax[1], nodes_[i].bmax[1]); } } @@ -1713,7 +1789,7 @@ template bool BVHAccel::Dump(const char *filename) { FILE *fp = fopen(filename, "wb"); if (!fp) { - //fprintf(stderr, "[BVHAccel] Cannot write a file: %s\n", filename); + // fprintf(stderr, "[BVHAccel] Cannot write a file: %s\n", filename); return false; } @@ -1744,7 +1820,7 @@ template bool BVHAccel::Load(const char *filename) { FILE *fp = fopen(filename, "rb"); if (!fp) { - //fprintf(stderr, "Cannot open file: %s\n", filename); + // fprintf(stderr, "Cannot open file: %s\n", filename); return false; } @@ -1815,10 +1891,10 @@ inline bool IntersectRayAABB(T *tminOut, // [out] return false; // no hit } -template template -inline bool BVHAccel::TestLeafNode(const BVHNode &node, - const Ray &ray, - const I &intersector) const { +template +template +inline bool BVHAccel::TestLeafNode(const BVHNode &node, const Ray &ray, + const I &intersector) const { bool hit = false; unsigned int num_primitives = node.data[0]; @@ -1841,20 +1917,18 @@ inline bool BVHAccel::TestLeafNode(const BVHNode &node, T local_t = t; if (intersector.Intersect(&local_t, prim_idx)) { - if (local_t > ray.min_t) { - // Update isect state - t = local_t; + // Update isect state + t = local_t; - intersector.Update(t, prim_idx); - hit = true; - } + intersector.Update(t, prim_idx); + hit = true; } } return hit; } -#if 0 // TODO(LTE): Implement +#if 0 // TODO(LTE): Implement template template bool BVHAccel::MultiHitTestLeafNode( std::priority_queue, Comp> *isect_pq, @@ -1928,11 +2002,10 @@ bool BVHAccel::MultiHitTestLeafNode( } #endif -template template -bool BVHAccel::Traverse(const Ray &ray, - const I &intersector, - H *isect, - const BVHTraceOptions &options) const { +template +template +bool BVHAccel::Traverse(const Ray &ray, const I &intersector, H *isect, + const BVHTraceOptions &options) const { const int kMaxStackDepth = 512; T hit_t = ray.max_t; @@ -1999,13 +2072,14 @@ bool BVHAccel::Traverse(const Ray &ray, return hit; } - -template template -inline bool BVHAccel::TestLeafNodeIntersections(const BVHNode &node, - const Ray &ray, - const int max_intersections, - const I &intersector, - std::priority_queue, std::vector >, NodeHitComparator > *isect_pq) const { + +template +template +inline bool BVHAccel::TestLeafNodeIntersections( + const BVHNode &node, const Ray &ray, const int max_intersections, + const I &intersector, + std::priority_queue, std::vector >, + NodeHitComparator > *isect_pq) const { bool hit = false; unsigned int num_primitives = node.data[0]; @@ -2043,7 +2117,6 @@ inline bool BVHAccel::TestLeafNodeIntersections(const BVHNode &node, isect_pq->pop(); isect_pq->push(isect); - } } } @@ -2052,11 +2125,11 @@ inline bool BVHAccel::TestLeafNodeIntersections(const BVHNode &node, return hit; } -template template -bool BVHAccel::ListNodeIntersections(const Ray &ray, - int max_intersections, - const I &intersector, - StackVector, 128> *hits) const { +template +template +bool BVHAccel::ListNodeIntersections( + const Ray &ray, int max_intersections, const I &intersector, + StackVector, 128> *hits) const { const int kMaxStackDepth = 512; T hit_t = ray.max_t; @@ -2066,14 +2139,19 @@ bool BVHAccel::ListNodeIntersections(const Ray &ray, node_stack[0] = 0; // Stores furthest intersection at top - std::priority_queue, std::vector >, NodeHitComparator > isect_pq; + std::priority_queue, std::vector >, + NodeHitComparator > + isect_pq; (*hits)->clear(); int dir_sign[3]; - dir_sign[0] = ray.dir[0] < static_cast(0.0) ? static_cast(1) : static_cast(0); - dir_sign[1] = ray.dir[1] < static_cast(0.0) ? static_cast(1) : static_cast(0); - dir_sign[2] = ray.dir[2] < static_cast(0.0) ? static_cast(1) : static_cast(0); + dir_sign[0] = + ray.dir[0] < static_cast(0.0) ? 1 : 0; + dir_sign[1] = + ray.dir[1] < static_cast(0.0) ? 1 : 0; + dir_sign[2] = + ray.dir[2] < static_cast(0.0) ? 1 : 0; // @fixme { Check edge case; i.e., 1/0 } real3 ray_inv_dir; @@ -2108,7 +2186,8 @@ bool BVHAccel::ListNodeIntersections(const Ray &ray, } else { // leaf node if (hit) { - TestLeafNodeIntersections(node, ray, max_intersections, intersector, &isect_pq); + TestLeafNodeIntersections(node, ray, max_intersections, intersector, + &isect_pq); } } } @@ -2132,7 +2211,7 @@ bool BVHAccel::ListNodeIntersections(const Ray &ray, return false; } -#if 0 // TODO(LTE): Implement +#if 0 // TODO(LTE): Implement template template bool BVHAccel::MultiHitTraverse(const Ray &ray, int max_intersections, @@ -2225,6 +2304,10 @@ bool BVHAccel::MultiHitTraverse(const Ray &ray, } #endif +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } // namespace nanort #endif // NANORT_H_ diff --git a/examples/raytrace/nanosg.h b/examples/raytrace/nanosg.h index 9020fa8..7b47c3b 100644 --- a/examples/raytrace/nanosg.h +++ b/examples/raytrace/nanosg.h @@ -31,35 +31,36 @@ THE SOFTWARE. #endif #endif +#include #include #include -#include #include "nanort.h" namespace nanosg { -template +template class PrimitiveInterface; -template -class PrimitiveInterface{ -public: - void print(){ static_cast(this)->print(); } +template +class PrimitiveInterface { + public: + void print() { static_cast(this)->print(); } }; class SpherePrimitive : PrimitiveInterface { -public: - void print(){ std::cout << "Sphere" << std::endl; } + public: + void print() { std::cout << "Sphere" << std::endl; } }; // 4x4 matrix -template class Matrix { -public: +template +class Matrix { + public: Matrix(); ~Matrix(); - static void Print(T m[4][4]) { + static void Print(const T m[4][4]) { for (int i = 0; i < 4; i++) { printf("m[%d] = %f, %f, %f, %f\n", i, m[i][0], m[i][1], m[i][2], m[i][3]); } @@ -232,18 +233,15 @@ public: dst[1] = tmp[1]; dst[2] = tmp[2]; } - }; -//typedef Matrix Matrixf; -//typedef Matrix Matrixd; - -template -static void XformBoundingBox(T xbmin[3], // out - T xbmax[3], // out - T bmin[3], T bmax[3], - T m[4][4]) { +// typedef Matrix Matrixf; +// typedef Matrix Matrixd; +template +static void XformBoundingBox(T xbmin[3], // out + T xbmax[3], // out + T bmin[3], T bmax[3], T m[4][4]) { // create bounding vertex from (bmin, bmax) T b[8][3]; @@ -286,7 +284,6 @@ static void XformBoundingBox(T xbmin[3], // out xbmax[2] = xb[0][2]; for (int i = 1; i < 8; i++) { - xbmin[0] = std::min(xb[i][0], xbmin[0]); xbmin[1] = std::min(xb[i][1], xbmin[1]); xbmin[2] = std::min(xb[i][2], xbmin[2]); @@ -297,48 +294,45 @@ static void XformBoundingBox(T xbmin[3], // out } } -template -struct Intersection -{ +template +struct Intersection { // required fields. - T t; // hit distance - unsigned int prim_id; // primitive ID of the hit - float u; - float v; + T t; // hit distance + unsigned int prim_id; // primitive ID of the hit + float u; + float v; - unsigned int node_id; // node ID of the hit. - nanort::real3 P; // intersection point - nanort::real3 Ns; // shading normal - nanort::real3 Ng; // geometric normal + unsigned int node_id; // node ID of the hit. + nanort::real3 P; // intersection point + nanort::real3 Ns; // shading normal + nanort::real3 Ng; // geometric normal }; /// /// Renderable node /// -template -class Node -{ +template +class Node { public: typedef Node type; - explicit Node(const M *mesh) - : mesh_(mesh) - { - xbmin_[0] = xbmin_[1] = xbmin_[2] = std::numeric_limits::max(); - xbmax_[0] = xbmax_[1] = xbmax_[2] = -std::numeric_limits::max(); + explicit Node(const M *mesh) : mesh_(mesh) { + xbmin_[0] = xbmin_[1] = xbmin_[2] = std::numeric_limits::max(); + xbmax_[0] = xbmax_[1] = xbmax_[2] = -std::numeric_limits::max(); - lbmin_[0] = lbmin_[1] = lbmin_[2] = std::numeric_limits::max(); - lbmax_[0] = lbmax_[1] = lbmax_[2] = -std::numeric_limits::max(); + lbmin_[0] = lbmin_[1] = lbmin_[2] = std::numeric_limits::max(); + lbmax_[0] = lbmax_[1] = lbmax_[2] = -std::numeric_limits::max(); Matrix::Identity(local_xform_); Matrix::Identity(xform_); Matrix::Identity(inv_xform_); - Matrix::Identity(inv_xform33_); inv_xform33_[3][3] = static_cast(0.0); - Matrix::Identity(inv_transpose_xform33_); inv_transpose_xform33_[3][3] = static_cast(0.0); + Matrix::Identity(inv_xform33_); + inv_xform33_[3][3] = static_cast(0.0); + Matrix::Identity(inv_transpose_xform33_); + inv_transpose_xform33_[3][3] = static_cast(0.0); + } - } - - ~Node() {} + ~Node() {} void Copy(const type &rhs) { Matrix::Copy(local_xform_, rhs.local_xform_); @@ -369,53 +363,44 @@ class Node children_ = rhs.children_; } - Node(const type &rhs) { - Copy(rhs); - } + Node(const type &rhs) { Copy(rhs); } const type &operator=(const type &rhs) { Copy(rhs); return (*this); } - void SetName(const std::string &name) { - name_ = name; - } + void SetName(const std::string &name) { name_ = name; } - const std::string &GetName() const { - return name_; - } + const std::string &GetName() const { return name_; } /// /// Add child node. /// - void AddChild(const type &child) { - children_.push_back(child); - } + void AddChild(const type &child) { children_.push_back(child); } /// /// Get chidren /// - const std::vector &GetChildren() const { - return children_; - } + const std::vector &GetChildren() const { return children_; } - std::vector &GetChildren() { - return children_; - } - - /// - /// Update internal state. - /// - void Update(const T parent_xform[4][4]) { - - if (!accel_.IsValid() && mesh_ && (mesh_->vertices.size() > 3) && (mesh_->faces.size() >= 3)) { + std::vector &GetChildren() { return children_; } + /// + /// Update internal state. + /// + void Update(const T parent_xform[4][4]) { + if (!accel_.IsValid() && mesh_ && (mesh_->vertices.size() > 3) && + (mesh_->faces.size() >= 3)) { // Assume mesh is composed of triangle faces only. - nanort::TriangleMesh triangle_mesh(mesh_->vertices.data(), mesh_->faces.data(), sizeof(float) * 3); - nanort::TriangleSAHPred triangle_pred(mesh_->vertices.data(), mesh_->faces.data(), sizeof(float) * 3); + nanort::TriangleMesh triangle_mesh( + mesh_->vertices.data(), mesh_->faces.data(), mesh_->stride); + nanort::TriangleSAHPred triangle_pred( + mesh_->vertices.data(), mesh_->faces.data(), mesh_->stride); - bool ret = accel_.Build(int(mesh_->faces.size()) / 3, triangle_mesh, triangle_pred); + bool ret = + accel_.Build(static_cast(mesh_->faces.size()) / 3, + triangle_mesh, triangle_pred); // Update local bbox. if (ret) { @@ -433,7 +418,7 @@ class Node Matrix::Copy(inv_xform_, xform_); Matrix::Inverse(inv_xform_); - // Clear translation, then inverse(xform) + // Clear translation, then inverse(xform) Matrix::Copy(inv_xform33_, xform_); inv_xform33_[3][0] = static_cast(0.0); inv_xform33_[3][1] = static_cast(0.0); @@ -448,67 +433,61 @@ class Node for (size_t i = 0; i < children_.size(); i++) { children_[i].Update(xform_); } - } + } - /// - /// Set local transformation. - /// + /// + /// Set local transformation. + /// void SetLocalXform(const T xform[4][4]) { memcpy(local_xform_, xform, sizeof(float) * 16); } - const T *GetLocalXformPtr() const { - return &local_xform_[0][0]; + const T *GetLocalXformPtr() const { return &local_xform_[0][0]; } + + const T *GetXformPtr() const { return &xform_[0][0]; } + + const M *GetMesh() const { return mesh_; } + + const nanort::BVHAccel &GetAccel() const { return accel_; } + + inline void GetWorldBoundingBox(T bmin[3], T bmax[3]) const { + bmin[0] = xbmin_[0]; + bmin[1] = xbmin_[1]; + bmin[2] = xbmin_[2]; + + bmax[0] = xbmax_[0]; + bmax[1] = xbmax_[1]; + bmax[2] = xbmax_[2]; } - const T *GetXformPtr() const { - return &xform_[0][0]; + inline void GetLocalBoundingBox(T bmin[3], T bmax[3]) const { + bmin[0] = lbmin_[0]; + bmin[1] = lbmin_[1]; + bmin[2] = lbmin_[2]; + + bmax[0] = lbmax_[0]; + bmax[1] = lbmax_[1]; + bmax[2] = lbmax_[2]; } - const M *GetMesh() const { - return mesh_; - } - - const nanort::BVHAccel &GetAccel() const { - return accel_; - } - - inline void GetWorldBoundingBox(T bmin[3], T bmax[3]) const { - bmin[0] = xbmin_[0]; - bmin[1] = xbmin_[1]; - bmin[2] = xbmin_[2]; - - bmax[0] = xbmax_[0]; - bmax[1] = xbmax_[1]; - bmax[2] = xbmax_[2]; - } - - inline void GetLocalBoundingBox(T bmin[3], T bmax[3]) const { - bmin[0] = lbmin_[0]; - bmin[1] = lbmin_[1]; - bmin[2] = lbmin_[2]; - - bmax[0] = lbmax_[0]; - bmax[1] = lbmax_[1]; - bmax[2] = lbmax_[2]; - } - - T local_xform_[4][4]; // Node's local transformation matrix. - T xform_[4][4]; // Parent xform x local_xform. - T inv_xform_[4][4]; // inverse(xform). world -> local - T inv_xform33_[4][4]; // inverse(xform0 with upper-left 3x3 elemets only(for transforming direction vector) - T inv_transpose_xform33_[4][4]; // inverse(transpose(xform)) with upper-left 3x3 elements only(for transforming normal vector) + T local_xform_[4][4]; // Node's local transformation matrix. + T xform_[4][4]; // Parent xform x local_xform. + T inv_xform_[4][4]; // inverse(xform). world -> local + T inv_xform33_[4][4]; // inverse(xform0 with upper-left 3x3 elemets only(for + // transforming direction vector) + T inv_transpose_xform33_[4][4]; // inverse(transpose(xform)) with upper-left + // 3x3 elements only(for transforming normal + // vector) private: + // bounding box(local space) + T lbmin_[3]; + T lbmax_[3]; - // bounding box(local space) - T lbmin_[3]; - T lbmax_[3]; + // bounding box after xform(world space) + T xbmin_[3]; + T xbmax_[3]; - // bounding box after xform(world space) - T xbmin_[3]; - T xbmax_[3]; - nanort::BVHAccel accel_; std::string name_; @@ -516,16 +495,16 @@ class Node const M *mesh_; std::vector children_; - }; // ------------------------------------------------- // Predefined SAH predicator for cube. -template +template class NodeBBoxPred { public: - NodeBBoxPred(const std::vector >* nodes) : axis_(0), pos_(0.0f), nodes_(nodes) {} + NodeBBoxPred(const std::vector > *nodes) + : axis_(0), pos_(0.0f), nodes_(nodes) {} void Set(int axis, float pos) const { axis_ = axis; @@ -538,8 +517,8 @@ class NodeBBoxPred { T bmin[3], bmax[3]; - (*nodes_)[i].GetWorldBoundingBox(bmin, bmax); - + (*nodes_)[i].GetWorldBoundingBox(bmin, bmax); + T center = bmax[axis] - bmin[axis]; return (center < pos); @@ -551,15 +530,15 @@ class NodeBBoxPred { const std::vector > *nodes_; }; -template +template class NodeBBoxGeometry { public: - NodeBBoxGeometry(const std::vector >* nodes) - : nodes_(nodes) {} + NodeBBoxGeometry(const std::vector > *nodes) : nodes_(nodes) {} /// Compute bounding box for `prim_index`th cube. /// This function is called for each primitive in BVH build. - void BoundingBox(nanort::real3* bmin, nanort::real3* bmax, unsigned int prim_index) const { + void BoundingBox(nanort::real3 *bmin, nanort::real3 *bmax, + unsigned int prim_index) const { T a[3], b[3]; (*nodes_)[prim_index].GetWorldBoundingBox(a, b); (*bmin)[0] = a[0]; @@ -570,10 +549,11 @@ class NodeBBoxGeometry { (*bmax)[2] = b[2]; } - const std::vector >* nodes_; + const std::vector > *nodes_; mutable nanort::real3 ray_org_; mutable nanort::real3 ray_dir_; mutable nanort::BVHTraceOptions trace_options_; + int _pad_; }; class NodeBBoxIntersection { @@ -587,14 +567,13 @@ class NodeBBoxIntersection { unsigned int prim_id; }; -template +template class NodeBBoxIntersector { public: - NodeBBoxIntersector(const std::vector >* nodes) - : nodes_(nodes) {} - - bool Intersect(float* out_t_min, float *out_t_max, unsigned int prim_index) const { + NodeBBoxIntersector(const std::vector > *nodes) : nodes_(nodes) {} + bool Intersect(float *out_t_min, float *out_t_max, + unsigned int prim_index) const { T bmin[3], bmax[3]; (*nodes_)[prim_index].GetWorldBoundingBox(bmin, bmax); @@ -634,7 +613,7 @@ class NodeBBoxIntersector { /// Prepare BVH traversal(e.g. compute inverse ray direction) /// This function is called only once in BVH traversal. - void PrepareTraversal(const nanort::Ray& ray) const { + void PrepareTraversal(const nanort::Ray &ray) const { ray_org_[0] = ray.org[0]; ray_org_[1] = ray.org[1]; ray_org_[2] = ray.org[2]; @@ -648,40 +627,37 @@ class NodeBBoxIntersector { ray_inv_dir_[1] = static_cast(1.0) / ray.dir[1]; ray_inv_dir_[2] = static_cast(1.0) / ray.dir[2]; - ray_dir_sign_[0] = ray.dir[0] < static_cast(0.0) ? static_cast(1) : static_cast(0); - ray_dir_sign_[1] = ray.dir[1] < static_cast(0.0) ? static_cast(1) : static_cast(0); - ray_dir_sign_[2] = ray.dir[2] < static_cast(0.0) ? static_cast(1) : static_cast(0); + ray_dir_sign_[0] = ray.dir[0] < static_cast(0.0) ? 1 : 0; + ray_dir_sign_[1] = ray.dir[1] < static_cast(0.0) ? 1 : 0; + ray_dir_sign_[2] = ray.dir[2] < static_cast(0.0) ? 1 : 0; } - const std::vector >* nodes_; + const std::vector > *nodes_; mutable nanort::real3 ray_org_; mutable nanort::real3 ray_dir_; mutable nanort::real3 ray_inv_dir_; mutable int ray_dir_sign_[3]; }; -template -class Scene -{ +template +class Scene { public: - Scene() { + Scene() { bmin_[0] = bmin_[1] = bmin_[2] = std::numeric_limits::max(); bmax_[0] = bmax_[1] = bmax_[2] = -std::numeric_limits::max(); } - ~Scene() {}; + ~Scene() {} /// /// Add intersectable node to the scene. /// - bool AddNode(const Node &node) { + bool AddNode(const Node &node) { nodes_.push_back(node); return true; } - const std::vector > &GetNodes() const { - return nodes_; - } + const std::vector > &GetNodes() const { return nodes_; } bool FindNode(const std::string &name, Node **found_node) { if (!found_node) { @@ -702,11 +678,15 @@ class Scene return false; } - /// /// Commit the scene. Must be called before tracing rays into the scene. /// bool Commit() { + // the scene should contains something + if (nodes_.size() == 0) { + std::cerr << "You are attempting to commit an empty scene!\n"; + return false; + } // Update nodes. for (size_t i = 0; i < nodes_.size(); i++) { @@ -719,21 +699,26 @@ class Scene // Build toplevel BVH. NodeBBoxGeometry geom(&nodes_); NodeBBoxPred pred(&nodes_); - - // FIXME(LTE): Limit one leaf contains one node bbox primitive. This would work, but would be inefficient. - // e.g. will miss some node when constructed BVH depth is larger than the value of BVHBuildOptions. - // Implement more better and efficient BVH build and traverse for Toplevel BVH. + + // FIXME(LTE): Limit one leaf contains one node bbox primitive. This would + // work, but would be inefficient. + // e.g. will miss some node when constructed BVH depth is larger than the + // value of BVHBuildOptions. + // Implement more better and efficient BVH build and traverse for Toplevel + // BVH. nanort::BVHBuildOptions build_options; build_options.min_leaf_primitives = 1; - - bool ret = toplevel_accel_.Build(static_cast(nodes_.size()), geom, pred, build_options); + + bool ret = toplevel_accel_.Build(static_cast(nodes_.size()), + geom, pred, build_options); nanort::BVHBuildStatistics stats = toplevel_accel_.GetStatistics(); + (void)stats; - //toplevel_accel_.Debug(); + // toplevel_accel_.Debug(); if (ret) { - toplevel_accel_.BoundingBox(bmin_, bmax_); + toplevel_accel_.BoundingBox(bmin_, bmax_); } else { // Set invalid bbox value. bmin_[0] = std::numeric_limits::max(); @@ -766,51 +751,54 @@ class Scene /// First find the intersection of nodes' bounding box using toplevel BVH. /// Then, trace into the hit node to find the intersection of the primitive. /// - template - bool Traverse(nanort::Ray &ray, H *isect, const bool cull_back_face = false) const { - + template + bool Traverse(nanort::Ray &ray, H *isect, + const bool cull_back_face = false) const { if (!toplevel_accel_.IsValid()) { return false; } - const int kMaxIntersections = 64; + const int kMaxIntersections = 64; bool has_hit = false; - + NodeBBoxIntersector isector(&nodes_); nanort::StackVector, 128> node_hits; - bool may_hit = toplevel_accel_.ListNodeIntersections(ray, kMaxIntersections, isector, &node_hits); + bool may_hit = toplevel_accel_.ListNodeIntersections(ray, kMaxIntersections, + isector, &node_hits); - if (may_hit) { - - T t_max = std::numeric_limits::max(); - T t_nearest = t_max; + if (may_hit) { + T t_max = std::numeric_limits::max(); + T t_nearest = t_max; nanort::BVHTraceOptions trace_options; trace_options.cull_back_face = cull_back_face; - // Find actual intersection point. - for (size_t i = 0; i < node_hits->size(); i++) { - - // Early cull test. + // Find actual intersection point. + for (size_t i = 0; i < node_hits->size(); i++) { + // Early cull test. if (t_nearest < node_hits[i].t_min) { - //printf("near: %f, t_min: %f, t_max: %f\n", t_nearest, node_hits[i].t_min, node_hits[i].t_max); + // printf("near: %f, t_min: %f, t_max: %f\n", t_nearest, + // node_hits[i].t_min, node_hits[i].t_max); continue; } assert(node_hits[i].node_id < nodes_.size()); const Node &node = nodes_[node_hits[i].node_id]; - // Transform ray into node's local space + // Transform ray into node's local space // TODO(LTE): Set ray tmin and tmax nanort::Ray local_ray; Matrix::MultV(local_ray.org, node.inv_xform_, ray.org); Matrix::MultV(local_ray.dir, node.inv_xform33_, ray.dir); - nanort::TriangleIntersector triangle_intersector(node.GetMesh()->vertices.data(), node.GetMesh()->faces.data(), sizeof(T) * 3); + nanort::TriangleIntersector triangle_intersector( + node.GetMesh()->vertices.data(), node.GetMesh()->faces.data(), + node.GetMesh()->stride); H local_isect; - bool hit = node.GetAccel().Traverse(local_ray, triangle_intersector, &local_isect); + bool hit = node.GetAccel().Traverse(local_ray, triangle_intersector, + &local_isect); if (hit) { // Calulcate hit distance in world coordiante. @@ -828,6 +816,7 @@ class Scene po[2] = world_P[2] - ray.org[2]; float t_world = vlength(po); + // printf("tworld %f, tnear %f\n", t_world, t_nearest); if (t_world < t_nearest) { t_nearest = t_world; @@ -839,36 +828,30 @@ class Scene isect->v = local_isect.v; // TODO(LTE): Implement - T Ng[3], Ns[3]; // geometric normal, shading normal. + T Ng[3], Ns[3]; // geometric normal, shading normal. + + node.GetMesh()->GetNormal(Ng, Ns, isect->prim_id, isect->u, + isect->v); - node.GetMesh()->GetNormal(Ng, Ns, isect->prim_id, isect->u, isect->v); - // Convert position and normal into world coordinate. isect->t = t_world; Matrix::MultV(isect->P, node.xform_, local_P); - Matrix::MultV(isect->Ng, node.inv_transpose_xform33_, - Ng); - Matrix::MultV(isect->Ns, node.inv_transpose_xform33_, - Ns); - } - + Matrix::MultV(isect->Ng, node.inv_transpose_xform33_, Ng); + Matrix::MultV(isect->Ns, node.inv_transpose_xform33_, Ns); + } } - - } - - } + } + } return has_hit; - } private: - /// /// Find a node by name. - /// - bool FindNodeRecursive(const std::string &name, Node *root, Node **found_node) { - + /// + bool FindNodeRecursive(const std::string &name, Node *root, + Node **found_node) { if (root->GetName().compare(name) == 0) { (*found_node) = root; return true; @@ -882,19 +865,18 @@ class Scene } return false; - } // Scene bounding box. // Valid after calling `Commit()`. T bmin_[3]; T bmax_[3]; - + // Toplevel BVH accel. nanort::BVHAccel toplevel_accel_; - std::vector > nodes_; + std::vector > nodes_; }; -} // namespace nanosg +} // namespace nanosg -#endif // NANOSG_H_ +#endif // NANOSG_H_ diff --git a/examples/raytrace/obj-loader.cc b/examples/raytrace/obj-loader.cc new file mode 100644 index 0000000..d55fb45 --- /dev/null +++ b/examples/raytrace/obj-loader.cc @@ -0,0 +1,458 @@ +#include "obj-loader.h" +#include "nanort.h" // for float3 + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#pragma clang diagnostic ignored "-Wcast-align" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wvariadic-macros" +#pragma clang diagnostic ignored "-Wc++11-extensions" +#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +#pragma clang diagnostic ignored "-Wimplicit-fallthrough" +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" +#endif +#if __has_warning("-Wcomma") +#pragma clang diagnostic ignored "-Wcomma" +#endif +#if __has_warning("-Wcast-qual") +#pragma clang diagnostic ignored "-Wcast-qual" +#endif +#endif + +#include "stb_image.h" + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include + +#ifdef NANOSG_USE_CXX11 +#include +#else +#include +#endif + +#define USE_TEX_CACHE 1 + +namespace example { + +typedef nanort::real3 float3; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wglobal-constructors" +#endif + +// TODO(LTE): Remove global static definition. +#ifdef NANOSG_USE_CXX11 +static std::unordered_map hashed_tex; +#else +static std::map hashed_tex; +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +inline void CalcNormal(float3 &N, float3 v0, float3 v1, float3 v2) { + float3 v10 = v1 - v0; + float3 v20 = v2 - v0; + + N = vcross(v20, v10); + N = vnormalize(N); +} + +static std::string GetBaseDir(const std::string &filepath) { + if (filepath.find_last_of("/\\") != std::string::npos) + return filepath.substr(0, filepath.find_last_of("/\\")); + return ""; +} + +static int LoadTexture(const std::string &filename, + std::vector *textures) { + int idx; + + if (filename.empty()) return -1; + + std::cout << " Loading texture : " << filename << std::endl; + Texture texture; + + // tigra: find in cache. get index + if (USE_TEX_CACHE) { + if (hashed_tex.find(filename) != hashed_tex.end()) { + puts("from cache"); + return hashed_tex[filename]; + } + } + + int w, h, n; + unsigned char *data = stbi_load(filename.c_str(), &w, &h, &n, 0); + if (data) { + texture.width = w; + texture.height = h; + texture.components = n; + + size_t n_elem = size_t(w * h * n); + texture.image = new unsigned char[n_elem]; + for (size_t i = 0; i < n_elem; i++) { + texture.image[i] = data[i]; + } + + free(data); + + textures->push_back(texture); + + idx = int(textures->size()) - 1; + + // tigra: store index to cache + if (USE_TEX_CACHE) { + hashed_tex[filename] = idx; + } + + return idx; + } + + std::cout << " Failed to load : " << filename << std::endl; + return -1; +} + +static void ComputeBoundingBoxOfMesh(float bmin[3], float bmax[3], + const example::Mesh &mesh) { + bmin[0] = bmin[1] = bmin[2] = std::numeric_limits::max(); + bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits::max(); + + for (size_t i = 0; i < mesh.vertices.size() / 3; i++) { + bmin[0] = std::min(bmin[0], mesh.vertices[3 * i + 0]); + bmin[1] = std::min(bmin[1], mesh.vertices[3 * i + 1]); + bmin[2] = std::min(bmin[1], mesh.vertices[3 * i + 2]); + + bmax[0] = std::max(bmax[0], mesh.vertices[3 * i + 0]); + bmax[1] = std::max(bmax[1], mesh.vertices[3 * i + 1]); + bmax[2] = std::max(bmax[2], mesh.vertices[3 * i + 2]); + } +} + +bool LoadObj(const std::string &filename, float scale, + std::vector > *meshes, + std::vector *out_materials, + std::vector *out_textures) { + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; + std::string err; + + std::string basedir = GetBaseDir(filename) + "/"; + const char *basepath = (basedir.compare("/") == 0) ? NULL : basedir.c_str(); + + // auto t_start = std::chrono::system_clock::now(); + + bool ret = + tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename.c_str(), + basepath, /* triangulate */ true); + + // auto t_end = std::chrono::system_clock::now(); + // std::chrono::duration ms = t_end - t_start; + + if (!err.empty()) { + std::cerr << err << std::endl; + } + + if (!ret) { + return false; + } + + // std::cout << "[LoadOBJ] Parse time : " << ms.count() << " [msecs]" + // << std::endl; + + std::cout << "[LoadOBJ] # of shapes in .obj : " << shapes.size() << std::endl; + std::cout << "[LoadOBJ] # of materials in .obj : " << materials.size() + << std::endl; + + { + size_t total_num_vertices = 0; + size_t total_num_faces = 0; + + total_num_vertices = attrib.vertices.size() / 3; + std::cout << " vertices : " << attrib.vertices.size() / 3 << std::endl; + + for (size_t i = 0; i < shapes.size(); i++) { + std::cout << " shape[" << i << "].name : " << shapes[i].name + << std::endl; + std::cout << " shape[" << i + << "].indices : " << shapes[i].mesh.indices.size() << std::endl; + assert((shapes[i].mesh.indices.size() % 3) == 0); + + total_num_faces += shapes[i].mesh.indices.size() / 3; + + // tigra: empty name convert to _id + if (shapes[i].name.length() == 0) { +#ifdef NANOSG_USE_CXX11 + shapes[i].name = "_" + std::to_string(i); +#else + std::stringstream ss; + ss << i; + shapes[i].name = "_" + ss.str(); +#endif + std::cout << " EMPTY shape[" << i << "].name, new : " << shapes[i].name + << std::endl; + } + } + std::cout << "[LoadOBJ] # of faces: " << total_num_faces << std::endl; + std::cout << "[LoadOBJ] # of vertices: " << total_num_vertices << std::endl; + } + + // TODO(LTE): Implement tangents and binormals + + for (size_t i = 0; i < shapes.size(); i++) { + Mesh mesh(/* stride */ sizeof(float) * 3); + + mesh.name = shapes[i].name; + + const size_t num_faces = shapes[i].mesh.indices.size() / 3; + mesh.faces.resize(num_faces * 3); + mesh.material_ids.resize(num_faces); + mesh.facevarying_normals.resize(num_faces * 3 * 3); + mesh.facevarying_uvs.resize(num_faces * 3 * 2); + mesh.vertices.resize(num_faces * 3 * 3); + + for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) { + // reorder vertices. may create duplicated vertices. + size_t f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index); + size_t f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index); + size_t f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index); + + mesh.vertices[9 * f + 0] = scale * attrib.vertices[3 * f0 + 0]; + mesh.vertices[9 * f + 1] = scale * attrib.vertices[3 * f0 + 1]; + mesh.vertices[9 * f + 2] = scale * attrib.vertices[3 * f0 + 2]; + + mesh.vertices[9 * f + 3] = scale * attrib.vertices[3 * f1 + 0]; + mesh.vertices[9 * f + 4] = scale * attrib.vertices[3 * f1 + 1]; + mesh.vertices[9 * f + 5] = scale * attrib.vertices[3 * f1 + 2]; + + mesh.vertices[9 * f + 6] = scale * attrib.vertices[3 * f2 + 0]; + mesh.vertices[9 * f + 7] = scale * attrib.vertices[3 * f2 + 1]; + mesh.vertices[9 * f + 8] = scale * attrib.vertices[3 * f2 + 2]; + + mesh.faces[3 * f + 0] = static_cast(3 * f + 0); + mesh.faces[3 * f + 1] = static_cast(3 * f + 1); + mesh.faces[3 * f + 2] = static_cast(3 * f + 2); + + mesh.material_ids[f] = + static_cast(shapes[i].mesh.material_ids[f]); + } + + if (attrib.normals.size() > 0) { + for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) { + size_t f0, f1, f2; + + f0 = size_t(shapes[i].mesh.indices[3 * f + 0].normal_index); + f1 = size_t(shapes[i].mesh.indices[3 * f + 1].normal_index); + f2 = size_t(shapes[i].mesh.indices[3 * f + 2].normal_index); + + if (f0 > 0 && f1 > 0 && f2 > 0) { + float n0[3], n1[3], n2[3]; + + n0[0] = attrib.normals[3 * f0 + 0]; + n0[1] = attrib.normals[3 * f0 + 1]; + n0[2] = attrib.normals[3 * f0 + 2]; + + n1[0] = attrib.normals[3 * f1 + 0]; + n1[1] = attrib.normals[3 * f1 + 1]; + n1[2] = attrib.normals[3 * f1 + 2]; + + n2[0] = attrib.normals[3 * f2 + 0]; + n2[1] = attrib.normals[3 * f2 + 1]; + n2[2] = attrib.normals[3 * f2 + 2]; + + mesh.facevarying_normals[3 * (3 * f + 0) + 0] = n0[0]; + mesh.facevarying_normals[3 * (3 * f + 0) + 1] = n0[1]; + mesh.facevarying_normals[3 * (3 * f + 0) + 2] = n0[2]; + + mesh.facevarying_normals[3 * (3 * f + 1) + 0] = n1[0]; + mesh.facevarying_normals[3 * (3 * f + 1) + 1] = n1[1]; + mesh.facevarying_normals[3 * (3 * f + 1) + 2] = n1[2]; + + mesh.facevarying_normals[3 * (3 * f + 2) + 0] = n2[0]; + mesh.facevarying_normals[3 * (3 * f + 2) + 1] = n2[1]; + mesh.facevarying_normals[3 * (3 * f + 2) + 2] = n2[2]; + } else { // face contains invalid normal index. calc geometric normal. + f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index); + f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index); + f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index); + + float3 v0, v1, v2; + + v0[0] = attrib.vertices[3 * f0 + 0]; + v0[1] = attrib.vertices[3 * f0 + 1]; + v0[2] = attrib.vertices[3 * f0 + 2]; + + v1[0] = attrib.vertices[3 * f1 + 0]; + v1[1] = attrib.vertices[3 * f1 + 1]; + v1[2] = attrib.vertices[3 * f1 + 2]; + + v2[0] = attrib.vertices[3 * f2 + 0]; + v2[1] = attrib.vertices[3 * f2 + 1]; + v2[2] = attrib.vertices[3 * f2 + 2]; + + float3 N; + CalcNormal(N, v0, v1, v2); + + mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0]; + mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1]; + mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2]; + + mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0]; + mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1]; + mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2]; + + mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0]; + mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1]; + mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2]; + } + } + } else { + // calc geometric normal + for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) { + size_t f0, f1, f2; + + f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index); + f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index); + f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index); + + float3 v0, v1, v2; + + v0[0] = attrib.vertices[3 * f0 + 0]; + v0[1] = attrib.vertices[3 * f0 + 1]; + v0[2] = attrib.vertices[3 * f0 + 2]; + + v1[0] = attrib.vertices[3 * f1 + 0]; + v1[1] = attrib.vertices[3 * f1 + 1]; + v1[2] = attrib.vertices[3 * f1 + 2]; + + v2[0] = attrib.vertices[3 * f2 + 0]; + v2[1] = attrib.vertices[3 * f2 + 1]; + v2[2] = attrib.vertices[3 * f2 + 2]; + + float3 N; + CalcNormal(N, v0, v1, v2); + + mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0]; + mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1]; + mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2]; + + mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0]; + mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1]; + mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2]; + + mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0]; + mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1]; + mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2]; + } + } + + if (attrib.texcoords.size() > 0) { + for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) { + size_t f0, f1, f2; + + f0 = size_t(shapes[i].mesh.indices[3 * f + 0].texcoord_index); + f1 = size_t(shapes[i].mesh.indices[3 * f + 1].texcoord_index); + f2 = size_t(shapes[i].mesh.indices[3 * f + 2].texcoord_index); + + if (f0 > 0 && f1 > 0 && f2 > 0) { + float3 n0, n1, n2; + + n0[0] = attrib.texcoords[2 * f0 + 0]; + n0[1] = attrib.texcoords[2 * f0 + 1]; + + n1[0] = attrib.texcoords[2 * f1 + 0]; + n1[1] = attrib.texcoords[2 * f1 + 1]; + + n2[0] = attrib.texcoords[2 * f2 + 0]; + n2[1] = attrib.texcoords[2 * f2 + 1]; + + mesh.facevarying_uvs[2 * (3 * f + 0) + 0] = n0[0]; + mesh.facevarying_uvs[2 * (3 * f + 0) + 1] = n0[1]; + + mesh.facevarying_uvs[2 * (3 * f + 1) + 0] = n1[0]; + mesh.facevarying_uvs[2 * (3 * f + 1) + 1] = n1[1]; + + mesh.facevarying_uvs[2 * (3 * f + 2) + 0] = n2[0]; + mesh.facevarying_uvs[2 * (3 * f + 2) + 1] = n2[1]; + } + } + } + + // Compute pivot translation and add offset to the vertices. + float bmin[3], bmax[3]; + ComputeBoundingBoxOfMesh(bmin, bmax, mesh); + + float bcenter[3]; + bcenter[0] = 0.5f * (bmax[0] - bmin[0]) + bmin[0]; + bcenter[1] = 0.5f * (bmax[1] - bmin[1]) + bmin[1]; + bcenter[2] = 0.5f * (bmax[2] - bmin[2]) + bmin[2]; + + for (size_t v = 0; v < mesh.vertices.size() / 3; v++) { + mesh.vertices[3 * v + 0] -= bcenter[0]; + mesh.vertices[3 * v + 1] -= bcenter[1]; + mesh.vertices[3 * v + 2] -= bcenter[2]; + } + + mesh.pivot_xform[0][0] = 1.0f; + mesh.pivot_xform[0][1] = 0.0f; + mesh.pivot_xform[0][2] = 0.0f; + mesh.pivot_xform[0][3] = 0.0f; + + mesh.pivot_xform[1][0] = 0.0f; + mesh.pivot_xform[1][1] = 1.0f; + mesh.pivot_xform[1][2] = 0.0f; + mesh.pivot_xform[1][3] = 0.0f; + + mesh.pivot_xform[2][0] = 0.0f; + mesh.pivot_xform[2][1] = 0.0f; + mesh.pivot_xform[2][2] = 1.0f; + mesh.pivot_xform[2][3] = 0.0f; + + mesh.pivot_xform[3][0] = bcenter[0]; + mesh.pivot_xform[3][1] = bcenter[1]; + mesh.pivot_xform[3][2] = bcenter[2]; + mesh.pivot_xform[3][3] = 1.0f; + + meshes->push_back(mesh); + } + + // material_t -> Material and Texture + out_materials->resize(materials.size()); + out_textures->resize(0); + for (size_t i = 0; i < materials.size(); i++) { + (*out_materials)[i].diffuse[0] = materials[i].diffuse[0]; + (*out_materials)[i].diffuse[1] = materials[i].diffuse[1]; + (*out_materials)[i].diffuse[2] = materials[i].diffuse[2]; + (*out_materials)[i].specular[0] = materials[i].specular[0]; + (*out_materials)[i].specular[1] = materials[i].specular[1]; + (*out_materials)[i].specular[2] = materials[i].specular[2]; + + (*out_materials)[i].id = int(i); + + // map_Kd + (*out_materials)[i].diffuse_texid = + LoadTexture(materials[i].diffuse_texname, out_textures); + // map_Ks + (*out_materials)[i].specular_texid = + LoadTexture(materials[i].specular_texname, out_textures); + } + + return true; +} + +} // namespace example diff --git a/examples/raytrace/obj-loader.h b/examples/raytrace/obj-loader.h new file mode 100644 index 0000000..9827791 --- /dev/null +++ b/examples/raytrace/obj-loader.h @@ -0,0 +1,19 @@ +#ifndef EXAMPLE_OBJ_LOADER_H_ +#define EXAMPLE_OBJ_LOADER_H_ + +#include +#include + +#include "mesh.h" +#include "material.h" + +namespace example { + +/// +/// Loads wavefront .obj mesh +/// +bool LoadObj(const std::string &filename, float scale, std::vector > *meshes, std::vector *materials, std::vector *textures); + +} + +#endif // EXAMPLE_OBJ_LOADER_H_ diff --git a/examples/raytrace/premake5.lua b/examples/raytrace/premake5.lua index cd802cc..d035674 100644 --- a/examples/raytrace/premake5.lua +++ b/examples/raytrace/premake5.lua @@ -1,12 +1,19 @@ +newoption { + trigger = "with-gtk3nfd", + description = "Build with native file dialog support(GTK3 required. Linux only)" +} + newoption { trigger = "asan", description = "Enable Address Sanitizer(gcc5+ ang clang only)" } sources = { + "stbi-impl.cc", "main.cc", "render.cc", "render-config.cc", + "obj-loader.cc", "gltf-loader.cc", "matrix.cc", "../common/trackball.cc", @@ -16,7 +23,7 @@ sources = { "../common/imgui/ImGuizmo.cpp", } -solution "RaytraceSolution" +solution "NanoSGSolution" configurations { "Release", "Debug" } if os.is("Windows") then @@ -53,7 +60,6 @@ solution "RaytraceSolution" end if os.is("Windows") then - flags { "FatalCompileWarnings" } warnings "Extra" -- /W4 defines { "NOMINMAX" } diff --git a/examples/raytrace/render-config.cc b/examples/raytrace/render-config.cc index 1322edd..2a30b61 100644 --- a/examples/raytrace/render-config.cc +++ b/examples/raytrace/render-config.cc @@ -29,12 +29,24 @@ bool LoadRenderConfig(example::RenderConfig* config, const char* filename) { picojson::object o = v.get(); + if (o.find("obj_filename") != o.end()) { + if (o["obj_filename"].is()) { + config->obj_filename = o["obj_filename"].get(); + } + } + if (o.find("gltf_filename") != o.end()) { if (o["gltf_filename"].is()) { config->gltf_filename = o["gltf_filename"].get(); } } + if (o.find("eson_filename") != o.end()) { + if (o["eson_filename"].is()) { + config->eson_filename = o["eson_filename"].get(); + } + } + config->scene_scale = 1.0f; if (o.find("scene_scale") != o.end()) { if (o["scene_scale"].is()) { @@ -107,4 +119,4 @@ bool LoadRenderConfig(example::RenderConfig* config, const char* filename) { return true; } -} +} // namespace example diff --git a/examples/raytrace/render-config.h b/examples/raytrace/render-config.h index 7eb7537..c3ffe4e 100644 --- a/examples/raytrace/render-config.h +++ b/examples/raytrace/render-config.h @@ -28,7 +28,9 @@ typedef struct { float *varycoordImage; // Scene input info + std::string obj_filename; std::string gltf_filename; + std::string eson_filename; float scene_scale; } RenderConfig; diff --git a/examples/raytrace/render.cc b/examples/raytrace/render.cc index f8de8ee..de1c1f2 100644 --- a/examples/raytrace/render.cc +++ b/examples/raytrace/render.cc @@ -200,6 +200,7 @@ void BuildCameraFrame(float3* origin, float3* corner, float3* u, float3* v, } } +#if 0 // TODO(LTE): Not used method. Delete. nanort::Ray GenerateRay(const float3& origin, const float3& corner, const float3& du, const float3& dv, float u, float v) { @@ -217,9 +218,12 @@ nanort::Ray GenerateRay(const float3& origin, const float3& corner, ray.org[1] = origin[1]; ray.org[2] = origin[2]; ray.dir[0] = dir[0]; + ray.dir[1] = dir[1]; + ray.dir[2] = dir[2]; return ray; } +#endif void FetchTexture(const Texture &texture, float u, float v, float* col) { int tx = u * texture.width; @@ -235,10 +239,15 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts, const nanosg::Scene> &scene, const example::Asset &asset, const RenderConfig& config, - std::atomic& cancelFlag) { + std::atomic& cancelFlag, + int &_showBufferMode + ) { //if (!gAccel.IsValid()) { // return false; //} + + + int width = config.width; int height = config.height; @@ -300,6 +309,19 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts, float u1 = pcg32_random(&rng); float3 dir; + + //for modes not a "color" + if(_showBufferMode != SHOW_BUFFER_COLOR) + { + //only one pass + if(config.pass > 0) + continue; + + //to the center of pixel + u0 = 0.5f; + u1 = 0.5f; + } + dir = corner + (float(x) + u0) * u + (float(config.height - y - 1) + u1) * v; dir = vnormalize(dir); @@ -320,6 +342,9 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts, const std::vector &materials = asset.materials; const std::vector &textures = asset.textures; const Mesh &mesh = asset.meshes[isect.node_id]; + + //tigra: add default material + const Material &default_material = asset.default_material; float3 p; p[0] = @@ -410,26 +435,49 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts, // Fetch texture unsigned int material_id = mesh.material_ids[isect.prim_id]; + + //printf("material_id=%d materials=%lld\n", material_id, materials.size()); float diffuse_col[3]; - int diffuse_texid = materials[material_id].diffuse_texid; - if (diffuse_texid >= 0) { - FetchTexture(textures[diffuse_texid], UV[0], UV[1], diffuse_col); - } else { - diffuse_col[0] = materials[material_id].diffuse[0]; - diffuse_col[1] = materials[material_id].diffuse[1]; - diffuse_col[2] = materials[material_id].diffuse[2]; - } float specular_col[3]; - int specular_texid = materials[material_id].specular_texid; - if (specular_texid >= 0) { - FetchTexture(textures[specular_texid], UV[0], UV[1], specular_col); - } else { - specular_col[0] = materials[material_id].specular[0]; - specular_col[1] = materials[material_id].specular[1]; - specular_col[2] = materials[material_id].specular[2]; - } + + //tigra: material_id is ok + if(material_id>=0 && material_id= 0) { + FetchTexture(textures[diffuse_texid], UV[0], UV[1], diffuse_col); + } else { + diffuse_col[0] = materials[material_id].diffuse[0]; + diffuse_col[1] = materials[material_id].diffuse[1]; + diffuse_col[2] = materials[material_id].diffuse[2]; + } + + int specular_texid = materials[material_id].specular_texid; + if (specular_texid >= 0) { + FetchTexture(textures[specular_texid], UV[0], UV[1], specular_col); + } else { + specular_col[0] = materials[material_id].specular[0]; + specular_col[1] = materials[material_id].specular[1]; + specular_col[2] = materials[material_id].specular[2]; + } + } + else + //tigra: wrong material_id, use default_material + { + + //printf("default_material\n"); + + diffuse_col[0] = default_material.diffuse[0]; + diffuse_col[1] = default_material.diffuse[1]; + diffuse_col[2] = default_material.diffuse[2]; + specular_col[0] = default_material.specular[0]; + specular_col[1] = default_material.specular[1]; + specular_col[2] = default_material.specular[2]; + } // Simple shading float NdotV = fabsf(vdot(N, dir)); diff --git a/examples/raytrace/render.h b/examples/raytrace/render.h index 8c24164..ccd2f2d 100644 --- a/examples/raytrace/render.h +++ b/examples/raytrace/render.h @@ -3,6 +3,15 @@ #include // C++11 +//mode definitions now here + +#define SHOW_BUFFER_COLOR (0) +#define SHOW_BUFFER_NORMAL (1) +#define SHOW_BUFFER_POSITION (2) +#define SHOW_BUFFER_DEPTH (3) +#define SHOW_BUFFER_TEXCOORD (4) +#define SHOW_BUFFER_VARYCOORD (5) + #include "render-config.h" #include "nanosg.h" #include "mesh.h" @@ -13,6 +22,9 @@ namespace example { struct Asset { std::vector > meshes; std::vector materials; + + //tigra: add default material + Material default_material; std::vector textures; }; @@ -23,7 +35,10 @@ class Renderer { /// Returns false when the rendering was canceled. static bool Render(float* rgba, float* aux_rgba, int *sample_counts, float quat[4], - const nanosg::Scene> &scene, const Asset &asset, const RenderConfig& config, std::atomic& cancel_flag); + const nanosg::Scene> &scene, const Asset &asset, const RenderConfig& config, + std::atomic& cancel_flag, + int& _showBufferMode + ); }; }; diff --git a/examples/raytrace/stbi-impl.cc b/examples/raytrace/stbi-impl.cc new file mode 100644 index 0000000..0375a5a --- /dev/null +++ b/examples/raytrace/stbi-impl.cc @@ -0,0 +1,3 @@ + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" diff --git a/examples/raytrace/viwewer.make b/examples/raytrace/viwewer.make new file mode 100644 index 0000000..3d35b1b --- /dev/null +++ b/examples/raytrace/viwewer.make @@ -0,0 +1,357 @@ +# GNU Make project makefile autogenerated by Premake + +ifndef config + config=release_native +endif + +ifndef verbose + SILENT = @ +endif + +.PHONY: clean prebuild prelink + +ifeq ($(config),release_native) + RESCOMP = windres + TARGETDIR = bin/native/Release + TARGET = $(TARGETDIR)/view + OBJDIR = obj/native/Release + DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 + INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm + FORCE_INCLUDE += + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -O2 -g + ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -O2 -g -std=c++11 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + LIBS += -lX11 -lpthread -ldl + LDDEPS += + ALL_LDFLAGS += $(LDFLAGS) + LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +all: prebuild prelink $(TARGET) + @: + +endif + +ifeq ($(config),release_x64) + RESCOMP = windres + TARGETDIR = bin/x64/Release + TARGET = $(TARGETDIR)/view + OBJDIR = obj/x64/Release + DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 + INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm + FORCE_INCLUDE += + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -g + ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -g -std=c++11 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + LIBS += -lX11 -lpthread -ldl + LDDEPS += + ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64 + LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +all: prebuild prelink $(TARGET) + @: + +endif + +ifeq ($(config),release_x32) + RESCOMP = windres + TARGETDIR = bin/x32/Release + TARGET = $(TARGETDIR)/view + OBJDIR = obj/x32/Release + DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 + INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm + FORCE_INCLUDE += + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -O2 -g + ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m32 -O2 -g -std=c++11 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + LIBS += -lX11 -lpthread -ldl + LDDEPS += + ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32 + LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +all: prebuild prelink $(TARGET) + @: + +endif + +ifeq ($(config),debug_native) + RESCOMP = windres + TARGETDIR = bin/native/Debug + TARGET = $(TARGETDIR)/view_debug + OBJDIR = obj/native/Debug + DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG + INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm + FORCE_INCLUDE += + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g + ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g -std=c++11 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + LIBS += -lX11 -lpthread -ldl + LDDEPS += + ALL_LDFLAGS += $(LDFLAGS) + LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +all: prebuild prelink $(TARGET) + @: + +endif + +ifeq ($(config),debug_x64) + RESCOMP = windres + TARGETDIR = bin/x64/Debug + TARGET = $(TARGETDIR)/view_debug + OBJDIR = obj/x64/Debug + DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG + INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm + FORCE_INCLUDE += + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -g + ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -g -std=c++11 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + LIBS += -lX11 -lpthread -ldl + LDDEPS += + ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64 + LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +all: prebuild prelink $(TARGET) + @: + +endif + +ifeq ($(config),debug_x32) + RESCOMP = windres + TARGETDIR = bin/x32/Debug + TARGET = $(TARGETDIR)/view_debug + OBJDIR = obj/x32/Debug + DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG + INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm + FORCE_INCLUDE += + ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES) + ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -g + ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m32 -g -std=c++11 + ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES) + LIBS += -lX11 -lpthread -ldl + LDDEPS += + ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32 + LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS) + define PREBUILDCMDS + endef + define PRELINKCMDS + endef + define POSTBUILDCMDS + endef +all: prebuild prelink $(TARGET) + @: + +endif + +OBJECTS := \ + $(OBJDIR)/X11OpenGLWindow.o \ + $(OBJDIR)/glew.o \ + $(OBJDIR)/ImGuizmo.o \ + $(OBJDIR)/imgui.o \ + $(OBJDIR)/imgui_draw.o \ + $(OBJDIR)/imgui_impl_btgui.o \ + $(OBJDIR)/trackball.o \ + $(OBJDIR)/gltf-loader.o \ + $(OBJDIR)/main.o \ + $(OBJDIR)/matrix.o \ + $(OBJDIR)/obj-loader.o \ + $(OBJDIR)/render-config.o \ + $(OBJDIR)/render.o \ + $(OBJDIR)/stbi-impl.o \ + +RESOURCES := \ + +CUSTOMFILES := \ + +SHELLTYPE := msdos +ifeq (,$(ComSpec)$(COMSPEC)) + SHELLTYPE := posix +endif +ifeq (/bin,$(findstring /bin,$(SHELL))) + SHELLTYPE := posix +endif + +$(TARGET): $(GCH) ${CUSTOMFILES} $(OBJECTS) $(LDDEPS) $(RESOURCES) + @echo Linking viwewer +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(TARGETDIR) +else + $(SILENT) mkdir $(subst /,\\,$(TARGETDIR)) +endif + $(SILENT) $(LINKCMD) + $(POSTBUILDCMDS) + +clean: + @echo Cleaning viwewer +ifeq (posix,$(SHELLTYPE)) + $(SILENT) rm -f $(TARGET) + $(SILENT) rm -rf $(OBJDIR) +else + $(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) + $(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR)) +endif + +prebuild: + $(PREBUILDCMDS) + +prelink: + $(PRELINKCMDS) + +ifneq (,$(PCH)) +$(OBJECTS): $(GCH) $(PCH) +$(GCH): $(PCH) + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<" +endif + +$(OBJDIR)/X11OpenGLWindow.o: ../common/OpenGLWindow/X11OpenGLWindow.cpp + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/glew.o: ../common/ThirdPartyLibs/Glew/glew.c + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/ImGuizmo.o: ../common/imgui/ImGuizmo.cpp + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/imgui.o: ../common/imgui/imgui.cpp + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/imgui_draw.o: ../common/imgui/imgui_draw.cpp + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/imgui_impl_btgui.o: ../common/imgui/imgui_impl_btgui.cpp + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/trackball.o: ../common/trackball.cc + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/gltf-loader.o: gltf-loader.cc + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/main.o: main.cc + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/matrix.o: matrix.cc + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/obj-loader.o: obj-loader.cc + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/render-config.o: render-config.cc + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/render.o: render.cc + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" +$(OBJDIR)/stbi-impl.o: stbi-impl.cc + @echo $(notdir $<) +ifeq (posix,$(SHELLTYPE)) + $(SILENT) mkdir -p $(OBJDIR) +else + $(SILENT) mkdir $(subst /,\\,$(OBJDIR)) +endif + $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" + +-include $(OBJECTS:%.o=%.d) +ifneq (,$(PCH)) + -include $(OBJDIR)/$(notdir $(PCH)).d +endif \ No newline at end of file