|
| 1 | +#include <vsg/all.h> |
| 2 | + |
| 3 | +#ifdef Tracy_FOUND |
| 4 | +# include <vsg/utils/TracyInstrumentation.h> |
| 5 | +#endif |
| 6 | + |
| 7 | +#include <iostream> |
| 8 | + |
| 9 | +struct ModelSettings |
| 10 | +{ |
| 11 | + vsg::ref_ptr<vsg::Options> options; |
| 12 | + double lodMinScreenRatio = 0.01; |
| 13 | +}; |
| 14 | + |
| 15 | +vsg::ref_ptr<vsg::Node> createTestScene(const ModelSettings& settings) |
| 16 | +{ |
| 17 | + auto builder = vsg::Builder::create(); |
| 18 | + builder->options = settings.options; |
| 19 | + |
| 20 | + auto scene = vsg::Group::create(); |
| 21 | + |
| 22 | + vsg::GeometryInfo geomInfo; |
| 23 | + geomInfo.color.set(1.0f, 1.0f, 0.5f, 1.0f); |
| 24 | + vsg::StateInfo stateInfo; |
| 25 | + |
| 26 | + auto group = vsg::Group::create(); |
| 27 | + auto node = builder->createCone(geomInfo, stateInfo); |
| 28 | + |
| 29 | + auto lod = vsg::LOD::create(); |
| 30 | + auto bb = vsg::visit<vsg::ComputeBounds>(node).bounds; |
| 31 | + lod->bound = vsg::dsphere((bb.min + bb.max) * 0.5, vsg::length(bb.max - bb.min)); |
| 32 | + lod->addChild(vsg::LOD::Child{settings.lodMinScreenRatio+1, node}); |
| 33 | + group->addChild(lod); |
| 34 | + |
| 35 | + geomInfo.position += geomInfo.dx * 1.5f; |
| 36 | + auto node2 = builder->createCylinder(geomInfo, stateInfo); |
| 37 | + |
| 38 | + auto lod2 = vsg::LOD::create(); |
| 39 | + auto bb2 = vsg::visit<vsg::ComputeBounds>(node2).bounds; |
| 40 | + lod2->bound = vsg::dsphere((bb2.min + bb2.max) * 0.5, vsg::length(bb2.max - bb2.min)); |
| 41 | + lod2->addChild(vsg::LOD::Child{settings.lodMinScreenRatio, node2}); |
| 42 | + group->addChild(lod2); |
| 43 | + |
| 44 | + scene->addChild(group); |
| 45 | + |
| 46 | + auto bounds = vsg::visit<vsg::ComputeBounds>(scene).bounds; |
| 47 | + vsg::info("createTestScene() extents = ", bounds); |
| 48 | + |
| 49 | + return scene; |
| 50 | +} |
| 51 | + |
| 52 | +int main(int argc, char** argv) |
| 53 | +{ |
| 54 | + // set up defaults and read command line arguments to override them |
| 55 | + auto options = vsg::Options::create(); |
| 56 | + options->paths = vsg::getEnvPaths("VSG_FILE_PATH"); |
| 57 | + options->sharedObjects = vsg::SharedObjects::create(); |
| 58 | + |
| 59 | + auto windowTraits = vsg::WindowTraits::create(); |
| 60 | + windowTraits->windowTitle = "vsglod"; |
| 61 | + |
| 62 | + // set up defaults and read command line arguments to override them |
| 63 | + vsg::CommandLine arguments(&argc, argv); |
| 64 | + windowTraits->debugLayer = arguments.read({"--debug", "-d"}); |
| 65 | + windowTraits->apiDumpLayer = arguments.read({"--api", "-a"}); |
| 66 | + windowTraits->synchronizationLayer = arguments.read("--sync"); |
| 67 | + |
| 68 | + bool reportAverageFrameRate = arguments.read("--fps"); |
| 69 | + arguments.read("--screen", windowTraits->screenNum); |
| 70 | + arguments.read("--display", windowTraits->display); |
| 71 | + auto numFrames = arguments.value(-1, "-f"); |
| 72 | + if (arguments.read({"--fullscreen", "--fs"})) windowTraits->fullscreen = true; |
| 73 | + if (arguments.read({"--window", "-w"}, windowTraits->width, windowTraits->height)) { windowTraits->fullscreen = false; } |
| 74 | + if (arguments.read("--IMMEDIATE")) windowTraits->swapchainPreferences.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; |
| 75 | + if (arguments.read("--d32")) windowTraits->depthFormat = VK_FORMAT_D32_SFLOAT; |
| 76 | + arguments.read("--samples", windowTraits->samples); |
| 77 | + if (arguments.read({"-t", "--test"})) |
| 78 | + { |
| 79 | + windowTraits->swapchainPreferences.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; |
| 80 | + windowTraits->fullscreen = true; |
| 81 | + reportAverageFrameRate = true; |
| 82 | + } |
| 83 | + if (arguments.read("--st")) |
| 84 | + { |
| 85 | + windowTraits->swapchainPreferences.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; |
| 86 | + windowTraits->width = 192, windowTraits->height = 108; |
| 87 | + windowTraits->decoration = false; |
| 88 | + reportAverageFrameRate = true; |
| 89 | + } |
| 90 | + |
| 91 | + const double invalid_time = std::numeric_limits<double>::max(); |
| 92 | + auto duration = arguments.value(invalid_time, "--duration"); |
| 93 | + |
| 94 | + vsg::ref_ptr<vsg::Instrumentation> instrumentation; |
| 95 | + if (arguments.read({"--gpu-annotation", "--ga"}) && vsg::isExtensionSupported(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) |
| 96 | + { |
| 97 | + windowTraits->debugUtils = true; |
| 98 | + |
| 99 | + auto gpu_instrumentation = vsg::GpuAnnotation::create(); |
| 100 | + if (arguments.read("--func")) gpu_instrumentation->labelType = vsg::GpuAnnotation::SourceLocation_function; |
| 101 | + |
| 102 | + instrumentation = gpu_instrumentation; |
| 103 | + } |
| 104 | + else if (arguments.read({"--profiler", "--pr"})) |
| 105 | + { |
| 106 | + // set Profiler options |
| 107 | + auto settings = vsg::Profiler::Settings::create(); |
| 108 | + arguments.read("--cpu", settings->cpu_instrumentation_level); |
| 109 | + arguments.read("--gpu", settings->gpu_instrumentation_level); |
| 110 | + arguments.read("--log-size", settings->log_size); |
| 111 | + arguments.read("--gpu-size", settings->gpu_timestamp_size); |
| 112 | + |
| 113 | + // create the profiler |
| 114 | + instrumentation = vsg::Profiler::create(settings); |
| 115 | + } |
| 116 | +#ifdef Tracy_FOUND |
| 117 | + else if (arguments.read("--tracy")) |
| 118 | + { |
| 119 | + windowTraits->deviceExtensionNames.push_back(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME); |
| 120 | + |
| 121 | + auto tracy_instrumentation = vsg::TracyInstrumentation::create(); |
| 122 | + arguments.read("--cpu", tracy_instrumentation->settings->cpu_instrumentation_level); |
| 123 | + arguments.read("--gpu", tracy_instrumentation->settings->gpu_instrumentation_level); |
| 124 | + instrumentation = tracy_instrumentation; |
| 125 | + } |
| 126 | +#endif |
| 127 | + |
| 128 | + double nearFarRatio = arguments.value<double>(0.001, "--nf"); |
| 129 | + ModelSettings settings; |
| 130 | + settings.options = options; |
| 131 | + |
| 132 | + vsg::ref_ptr<vsg::ResourceHints> resourceHints; |
| 133 | + if (auto resourceHintsFilename = arguments.value<vsg::Path>("", "--rh")) |
| 134 | + { |
| 135 | + resourceHints = vsg::read_cast<vsg::ResourceHints>(resourceHintsFilename, options); |
| 136 | + } |
| 137 | + |
| 138 | + if (!resourceHints) resourceHints = vsg::ResourceHints::create(); |
| 139 | + |
| 140 | + if (auto outputResourceHintsFilename = arguments.value<vsg::Path>("", "--orh")) |
| 141 | + { |
| 142 | + if (!resourceHints) resourceHints = vsg::ResourceHints::create(); |
| 143 | + vsg::write(resourceHints, outputResourceHintsFilename, options); |
| 144 | + return 0; |
| 145 | + } |
| 146 | + |
| 147 | + auto shaderHints = vsg::ShaderCompileSettings::create(); |
| 148 | + vsg::ref_ptr<vsg::ShadowSettings> shadowSettings; |
| 149 | + |
| 150 | + auto pathFilename = arguments.value<vsg::Path>("", "-p"); |
| 151 | + auto outputFilename = arguments.value<vsg::Path>("", "-o"); |
| 152 | + |
| 153 | + auto inherit = arguments.read("--inherit"); |
| 154 | + auto direction = arguments.value(vsg::dvec3(0.0, 0.0, -1.0), "--direction"); |
| 155 | + auto angleSubtended = arguments.value<float>(0.0090f, "--angleSubtended"); |
| 156 | + |
| 157 | + vsg::ref_ptr<vsg::StateGroup> stateGroup; |
| 158 | + if (inherit) |
| 159 | + { |
| 160 | + auto shaderSet = vsg::createPhongShaderSet(options); |
| 161 | + auto layout = shaderSet->createPipelineLayout({}, {0, 1}); |
| 162 | + |
| 163 | + stateGroup = vsg::StateGroup::create(); |
| 164 | + |
| 165 | + uint32_t vds_set = 0; |
| 166 | + stateGroup->add(vsg::BindViewDescriptorSets::create(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, vds_set)); |
| 167 | + |
| 168 | + vsg::info("Added state to inherit "); |
| 169 | + options->inheritedState = stateGroup->stateCommands; |
| 170 | + } |
| 171 | + |
| 172 | + vsg::ref_ptr<vsg::Node> scene; |
| 173 | + scene = createTestScene(settings); |
| 174 | + |
| 175 | + if (stateGroup) |
| 176 | + { |
| 177 | + // if setup place the StateGroup at the root of the scene graph |
| 178 | + stateGroup->addChild(scene); |
| 179 | + scene = stateGroup; |
| 180 | + } |
| 181 | + |
| 182 | + // compute the bounds of the scene graph to help position camera |
| 183 | + auto bounds = vsg::visit<vsg::ComputeBounds>(scene).bounds; |
| 184 | + auto viewingDistance = vsg::length(bounds.max - bounds.min) * 2.0; |
| 185 | + |
| 186 | + vsg::ref_ptr<vsg::LookAt> lookAt; |
| 187 | + |
| 188 | + { |
| 189 | + vsg::dvec3 centre = (bounds.min + bounds.max) * 0.5; |
| 190 | + |
| 191 | + // set up the camera |
| 192 | + lookAt = vsg::LookAt::create(centre + vsg::dvec3(0.0, -viewingDistance, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0)); |
| 193 | + } |
| 194 | + |
| 195 | + //auto span = vsg::length(bounds.max - bounds.min); |
| 196 | + auto group = vsg::Group::create(); |
| 197 | + group->addChild(scene); |
| 198 | + |
| 199 | + vsg::ref_ptr<vsg::DirectionalLight> directionalLight; |
| 200 | + directionalLight = vsg::DirectionalLight::create(); |
| 201 | + directionalLight->name = "directional"; |
| 202 | + directionalLight->color.set(1.0f, 1.0f, 1.0f); |
| 203 | + directionalLight->intensity = 0.95f; |
| 204 | + directionalLight->direction = direction; |
| 205 | + directionalLight->angleSubtended = angleSubtended; |
| 206 | + directionalLight->shadowSettings = shadowSettings; |
| 207 | + |
| 208 | + group->addChild(directionalLight); |
| 209 | + |
| 210 | + scene = group; |
| 211 | + |
| 212 | + // write out scene if required |
| 213 | + if (!outputFilename.empty()) |
| 214 | + { |
| 215 | + vsg::write(scene, outputFilename, options); |
| 216 | + return 0; |
| 217 | + } |
| 218 | + |
| 219 | + // create the viewer and assign window(s) to it |
| 220 | + auto viewer = vsg::Viewer::create(); |
| 221 | + |
| 222 | + auto window = vsg::Window::create(windowTraits); |
| 223 | + if (!window) |
| 224 | + { |
| 225 | + std::cout << "Could not create windows." << std::endl; |
| 226 | + return 1; |
| 227 | + } |
| 228 | + |
| 229 | + viewer->addWindow(window); |
| 230 | + |
| 231 | + vsg::ref_ptr<vsg::ProjectionMatrix> perspective; |
| 232 | + perspective = vsg::Perspective::create(30.0, static_cast<double>(window->extent2D().width) / static_cast<double>(window->extent2D().height), nearFarRatio * viewingDistance, viewingDistance * 1.3); |
| 233 | + |
| 234 | + auto camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(window->extent2D())); |
| 235 | + |
| 236 | + // add the camera and scene graph to View |
| 237 | + auto view = vsg::View::create(); |
| 238 | + view->camera = camera; |
| 239 | + view->addChild(scene); |
| 240 | + |
| 241 | + // add close handler to respond the close window button and pressing escape |
| 242 | + viewer->addEventHandler(vsg::CloseHandler::create(viewer)); |
| 243 | + |
| 244 | + auto cameraAnimation = vsg::CameraAnimationHandler::create(camera, pathFilename, options); |
| 245 | + viewer->addEventHandler(cameraAnimation); |
| 246 | + if (cameraAnimation->animation) |
| 247 | + { |
| 248 | + cameraAnimation->play(); |
| 249 | + if (reportAverageFrameRate && duration == invalid_time) duration = cameraAnimation->animation->maxTime(); |
| 250 | + } |
| 251 | + |
| 252 | + viewer->addEventHandler(vsg::Trackball::create(camera)); |
| 253 | + |
| 254 | + auto renderGraph = vsg::RenderGraph::create(window, view); |
| 255 | + auto commandGraph = vsg::CommandGraph::create(window, renderGraph); |
| 256 | + viewer->assignRecordAndSubmitTaskAndPresentation({commandGraph}); |
| 257 | + |
| 258 | + if (instrumentation) viewer->assignInstrumentation(instrumentation); |
| 259 | + |
| 260 | + viewer->compile(resourceHints); |
| 261 | + |
| 262 | + auto startTime = vsg::clock::now(); |
| 263 | + double numFramesCompleted = 0.0; |
| 264 | + |
| 265 | + // rendering main loop |
| 266 | + while (viewer->advanceToNextFrame() && (numFrames < 0 || (numFrames--) > 0) && (viewer->getFrameStamp()->simulationTime < duration)) |
| 267 | + { |
| 268 | + // pass any events into EventHandlers assigned to the Viewer |
| 269 | + viewer->handleEvents(); |
| 270 | + viewer->update(); |
| 271 | + |
| 272 | + viewer->recordAndSubmit(); |
| 273 | + |
| 274 | + viewer->present(); |
| 275 | + |
| 276 | + numFramesCompleted += 1.0; |
| 277 | + } |
| 278 | + |
| 279 | + if (reportAverageFrameRate) |
| 280 | + { |
| 281 | + auto elapesedTime = std::chrono::duration<double, std::chrono::seconds::period>(vsg::clock::now() - startTime).count(); |
| 282 | + if (numFramesCompleted > 0.0) |
| 283 | + { |
| 284 | + std::cout << "Average frame rate = " << (numFramesCompleted / elapesedTime) << std::endl; |
| 285 | + } |
| 286 | + } |
| 287 | + |
| 288 | + if (auto profiler = instrumentation.cast<vsg::Profiler>()) |
| 289 | + { |
| 290 | + instrumentation->finish(); |
| 291 | + profiler->log->report(std::cout); |
| 292 | + } |
| 293 | + |
| 294 | + return 0; |
| 295 | +} |
0 commit comments