initial setup
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use_flake
|
||||||
178
.gitignore
vendored
|
|
@ -2,3 +2,181 @@
|
||||||
/build/*
|
/build/*
|
||||||
/out/build/x64-Debug
|
/out/build/x64-Debug
|
||||||
/.vs
|
/.vs
|
||||||
|
|
||||||
|
# cmake
|
||||||
|
cmake-build-debug
|
||||||
|
|
||||||
|
# direnv
|
||||||
|
.direnv
|
||||||
|
|
||||||
|
#binarys
|
||||||
|
bin_x64
|
||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/clion,cmake,c++
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=clion,cmake,c++
|
||||||
|
|
||||||
|
### C++ ###
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
### CLion ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### CLion Patch ###
|
||||||
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
|
# *.iml
|
||||||
|
# modules.xml
|
||||||
|
# .idea/misc.xml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||||
|
.idea/**/sonarlint/
|
||||||
|
|
||||||
|
# SonarQube Plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||||
|
.idea/**/sonarIssues.xml
|
||||||
|
|
||||||
|
# Markdown Navigator plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||||
|
.idea/**/markdown-navigator.xml
|
||||||
|
.idea/**/markdown-navigator-enh.xml
|
||||||
|
.idea/**/markdown-navigator/
|
||||||
|
|
||||||
|
# Cache file creation bug
|
||||||
|
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||||
|
.idea/$CACHE_FILE$
|
||||||
|
|
||||||
|
# CodeStream plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||||
|
.idea/codestream.xml
|
||||||
|
|
||||||
|
# Azure Toolkit for IntelliJ plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
|
||||||
|
.idea/**/azureSettings.xml
|
||||||
|
|
||||||
|
### CMake ###
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
|
||||||
|
### CMake Patch ###
|
||||||
|
# External projects
|
||||||
|
*-prefix/
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/clion,cmake,c++
|
||||||
|
|
|
||||||
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "nvpro_core"]
|
||||||
|
path = nvpro_core
|
||||||
|
url = git@github.com:nvpro-samples/nvpro_core.git
|
||||||
8
.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
1
.idea/.name
generated
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
vk_raytracing_tutorial
|
||||||
19
.idea/codeStyles/Project.xml
generated
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<Objective-C>
|
||||||
|
<option name="INDENT_NAMESPACE_MEMBERS" value="2" />
|
||||||
|
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
|
||||||
|
<option name="INDENT_CLASS_MEMBERS" value="2" />
|
||||||
|
<option name="INDENT_INSIDE_CODE_BLOCK" value="2" />
|
||||||
|
</Objective-C>
|
||||||
|
<clangFormatSettings>
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</clangFormatSettings>
|
||||||
|
<codeStyleSettings language="ObjectiveC">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
||||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
7
.idea/misc.xml
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakePythonSetting">
|
||||||
|
<option name="pythonIntegrationState" value="YES" />
|
||||||
|
</component>
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/vk_raytracing_tutorial_KHR.iml" filepath="$PROJECT_DIR$/.idea/vk_raytracing_tutorial_KHR.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
7
.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/nvpro_core" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
2
.idea/vk_raytracing_tutorial_KHR.iml
generated
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||||
|
|
@ -41,25 +41,7 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/media DESTINATION ${OUTPUT_PATH})
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
# Sub examples
|
# Sub examples
|
||||||
add_subdirectory(ray_tracing__advance)
|
|
||||||
add_subdirectory(ray_tracing__before)
|
|
||||||
add_subdirectory(ray_tracing__simple)
|
|
||||||
|
|
||||||
add_subdirectory(ray_tracing_animation)
|
|
||||||
add_subdirectory(ray_tracing_anyhit)
|
|
||||||
add_subdirectory(ray_tracing_callable)
|
|
||||||
add_subdirectory(ray_tracing_gltf)
|
add_subdirectory(ray_tracing_gltf)
|
||||||
add_subdirectory(ray_tracing_instances)
|
|
||||||
add_subdirectory(ray_tracing_intersection)
|
|
||||||
add_subdirectory(ray_tracing_jitter_cam)
|
|
||||||
add_subdirectory(ray_tracing_manyhits)
|
|
||||||
add_subdirectory(ray_tracing_rayquery)
|
|
||||||
add_subdirectory(ray_tracing_reflections)
|
|
||||||
add_subdirectory(ray_tracing_ao)
|
|
||||||
add_subdirectory(ray_tracing_indirect_scissor)
|
|
||||||
add_subdirectory(ray_tracing_specialization)
|
|
||||||
add_subdirectory(ray_tracing_advanced_compilation)
|
|
||||||
add_subdirectory(ray_tracing_motionblur)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
#--------------------------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
27
flake.lock
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1715266358,
|
||||||
|
"narHash": "sha256-doPgfj+7FFe9rfzWo1siAV2mVCasW+Bh8I1cToAXEE4=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "f1010e0469db743d14519a1efd37e23f8513d714",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
66
flake.nix
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
description = "Nix flake for developing with vulkan and cpp";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs }:
|
||||||
|
let
|
||||||
|
allSystems = [
|
||||||
|
"x86_64-linux" # 64bit AMD/Intel x86
|
||||||
|
];
|
||||||
|
|
||||||
|
forAllSystems = fn:
|
||||||
|
nixpkgs.lib.genAttrs allSystems
|
||||||
|
(system: fn { pkgs = import nixpkgs { inherit system; }; });
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells = forAllSystems ({ pkgs }: {
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
name = "vulkan CPP dev shell";
|
||||||
|
# gcc appears to be broken
|
||||||
|
nativeBuildInputs = with pkgs ;[
|
||||||
|
(hiPrio clang-tools.override {
|
||||||
|
llvmPackages = llvmPackages_16;
|
||||||
|
enableLibcxx = false;
|
||||||
|
})
|
||||||
|
# CPP deps
|
||||||
|
clang-tools
|
||||||
|
glm
|
||||||
|
cmake
|
||||||
|
# Vulkan Deps
|
||||||
|
vulkan-tools
|
||||||
|
vulkan-headers
|
||||||
|
vulkan-loader
|
||||||
|
vulkan-validation-layers
|
||||||
|
shaderc
|
||||||
|
shaderc.dev
|
||||||
|
shaderc.lib
|
||||||
|
shaderc.bin
|
||||||
|
shaderc.static
|
||||||
|
glslang
|
||||||
|
# X11 Deps
|
||||||
|
xorg.libX11
|
||||||
|
xorg.libXi
|
||||||
|
xorg.libXxf86vm
|
||||||
|
xorg.libXrandr
|
||||||
|
xorg.libXinerama
|
||||||
|
xorg.libXcursor
|
||||||
|
glfw
|
||||||
|
# Wayland deps
|
||||||
|
glfw-wayland
|
||||||
|
waylandpp
|
||||||
|
wayland
|
||||||
|
# dev tools
|
||||||
|
valgrind
|
||||||
|
# general deps
|
||||||
|
imgui
|
||||||
|
];
|
||||||
|
# TODO: include deps depending on XDG_SESSION_TYPE here (wayland vs X11)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
1
nvpro_core
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit c98df794436fed19c17d3eb12f6ff8e5002ce2c4
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
#*****************************************************************************
|
|
||||||
# Copyright 2020 NVIDIA Corporation. All rights reserved.
|
|
||||||
#*****************************************************************************
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Project setting
|
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
|
||||||
message(STATUS "-------------------------------")
|
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# C++ target and defines
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
add_executable(${PROJNAME})
|
|
||||||
_add_project_definitions(${PROJNAME})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Source files for this project
|
|
||||||
#
|
|
||||||
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
|
|
||||||
file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
|
|
||||||
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
|
||||||
include_directories(${TUTO_KHR_DIR}/common)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# GLSL to SPIR-V custom build
|
|
||||||
compile_glsl_directory(
|
|
||||||
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
|
|
||||||
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
|
|
||||||
VULKAN_TARGET "vulkan1.2"
|
|
||||||
DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sources
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sub-folders in Visual Studio
|
|
||||||
#
|
|
||||||
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
|
|
||||||
source_group("Sources" FILES ${SOURCE_FILES})
|
|
||||||
source_group("Headers" FILES ${HEADER_FILES})
|
|
||||||
source_group("Shader Sources" FILES ${GLSL_SOURCES})
|
|
||||||
source_group("Shader Headers" FILES ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Linkage
|
|
||||||
#
|
|
||||||
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core)
|
|
||||||
|
|
||||||
foreach(DEBUGLIB ${LIBRARIES_DEBUG})
|
|
||||||
target_link_libraries(${PROJNAME} debug ${DEBUGLIB})
|
|
||||||
endforeach(DEBUGLIB)
|
|
||||||
|
|
||||||
foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
|
|
||||||
target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
|
|
||||||
endforeach(RELEASELIB)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# copies binaries that need to be put next to the exe files (ZLib, etc.)
|
|
||||||
#
|
|
||||||
_finalize_target( ${PROJNAME} )
|
|
||||||
|
|
||||||
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
# NVIDIA Vulkan Ray Tracing Tutorial
|
|
||||||
|
|
||||||
This example is the combination of all tutorials.
|
|
||||||
|
|
||||||
If you haven't done the tutorials, you can start [here](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
@ -1,568 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
|
|
||||||
#define VMA_IMPLEMENTATION
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include "obj_loader.h"
|
|
||||||
#include "stb_image.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
|
||||||
#include "nvh/cameramanipulator.hpp"
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
#include "nvvk/images_vk.hpp"
|
|
||||||
#include "nvvk/pipeline_vk.hpp"
|
|
||||||
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/renderpasses_vk.hpp"
|
|
||||||
|
|
||||||
#include "nvvk/buffers_vk.hpp"
|
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Keep the handle on the device
|
|
||||||
// Initialize the tool to do all our allocations: buffers, images
|
|
||||||
//
|
|
||||||
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
|
||||||
{
|
|
||||||
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
|
||||||
m_alloc.init(instance, device, physicalDevice);
|
|
||||||
m_debug.setup(m_device);
|
|
||||||
|
|
||||||
|
|
||||||
m_offscreen.setup(device, physicalDevice, &m_alloc, queueFamily);
|
|
||||||
m_raytrace.setup(device, physicalDevice, &m_alloc, queueFamily);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Called at each frame to update the camera matrix
|
|
||||||
//
|
|
||||||
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
|
||||||
{
|
|
||||||
// Prepare new UBO contents on host.
|
|
||||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
|
||||||
GlobalUniforms hostUBO = {};
|
|
||||||
const auto& view = CameraManip.getMatrix();
|
|
||||||
glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f);
|
|
||||||
proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
|
||||||
|
|
||||||
hostUBO.viewProj = proj * view;
|
|
||||||
hostUBO.viewInverse = glm::inverse(view);
|
|
||||||
hostUBO.projInverse = glm::inverse(proj);
|
|
||||||
|
|
||||||
// UBO on the device, and what stages access it.
|
|
||||||
VkBuffer deviceUBO = m_bGlobals.buffer;
|
|
||||||
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
|
||||||
|
|
||||||
// Ensure that the modified UBO is not visible to previous frames.
|
|
||||||
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
|
||||||
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
beforeBarrier.buffer = deviceUBO;
|
|
||||||
beforeBarrier.offset = 0;
|
|
||||||
beforeBarrier.size = sizeof(hostUBO);
|
|
||||||
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
|
||||||
nullptr, 1, &beforeBarrier, 0, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
|
||||||
// buffer so it is okay to deallocate when the function returns).
|
|
||||||
vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
|
|
||||||
|
|
||||||
// Making sure the updated UBO will be visible.
|
|
||||||
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
|
||||||
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
afterBarrier.buffer = deviceUBO;
|
|
||||||
afterBarrier.offset = 0;
|
|
||||||
afterBarrier.size = sizeof(hostUBO);
|
|
||||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
|
||||||
nullptr, 1, &afterBarrier, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Describing the layout pushed when rendering
|
|
||||||
//
|
|
||||||
void HelloVulkan::createDescriptorSetLayout()
|
|
||||||
{
|
|
||||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
|
||||||
|
|
||||||
// Camera matrices
|
|
||||||
m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
|
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
|
|
||||||
// Obj descriptions
|
|
||||||
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
|
|
||||||
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
|
||||||
// Textures
|
|
||||||
m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
|
|
||||||
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
|
||||||
|
|
||||||
// Storing implicit obj (binding = 3)
|
|
||||||
m_descSetLayoutBind.addBinding(eImplicits, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
|
||||||
VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR
|
|
||||||
| VK_SHADER_STAGE_ANY_HIT_BIT_KHR);
|
|
||||||
|
|
||||||
|
|
||||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
|
||||||
m_descPool = m_descSetLayoutBind.createPool(m_device, 1);
|
|
||||||
m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Setting up the buffers in the descriptor set
|
|
||||||
//
|
|
||||||
void HelloVulkan::updateDescriptorSet()
|
|
||||||
{
|
|
||||||
std::vector<VkWriteDescriptorSet> writes;
|
|
||||||
|
|
||||||
// Camera matrices and scene description
|
|
||||||
VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
|
|
||||||
|
|
||||||
VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
|
|
||||||
|
|
||||||
// All texture samplers
|
|
||||||
std::vector<VkDescriptorImageInfo> diit;
|
|
||||||
for(auto& texture : m_textures)
|
|
||||||
{
|
|
||||||
diit.emplace_back(texture.descriptor);
|
|
||||||
}
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
|
|
||||||
|
|
||||||
VkDescriptorBufferInfo dbiImplDesc{m_implObjects.implBuf.buffer, 0, VK_WHOLE_SIZE};
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, 3, &dbiImplDesc));
|
|
||||||
|
|
||||||
// Writing the information
|
|
||||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating the pipeline layout
|
|
||||||
//
|
|
||||||
void HelloVulkan::createGraphicsPipeline()
|
|
||||||
{
|
|
||||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
|
|
||||||
|
|
||||||
// Creating the Pipeline Layout
|
|
||||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
||||||
createInfo.setLayoutCount = 1;
|
|
||||||
createInfo.pSetLayouts = &m_descSetLayout;
|
|
||||||
createInfo.pushConstantRangeCount = 1;
|
|
||||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
|
||||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
|
||||||
|
|
||||||
|
|
||||||
// Creating the Pipeline
|
|
||||||
std::vector<std::string> paths = defaultSearchPaths;
|
|
||||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreen.renderPass());
|
|
||||||
gpb.depthStencilState.depthTestEnable = true;
|
|
||||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
|
||||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
||||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
|
||||||
gpb.addAttributeDescriptions({
|
|
||||||
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
|
||||||
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
|
||||||
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
|
||||||
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
|
||||||
});
|
|
||||||
|
|
||||||
m_graphicsPipeline = gpb.createPipeline();
|
|
||||||
m_debug.setObjectName(m_graphicsPipeline, "Graphics");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Loading the OBJ file and setting up all buffers
|
|
||||||
//
|
|
||||||
void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform)
|
|
||||||
{
|
|
||||||
LOGI("Loading File: %s \n", filename.c_str());
|
|
||||||
ObjLoader loader;
|
|
||||||
loader.loadModel(filename);
|
|
||||||
|
|
||||||
// Converting from Srgb to linear
|
|
||||||
for(auto& m : loader.m_materials)
|
|
||||||
{
|
|
||||||
m.ambient = glm::pow(m.ambient, glm::vec3(2.2f));
|
|
||||||
m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f));
|
|
||||||
m.specular = glm::pow(m.specular, glm::vec3(2.2f));
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjModel model;
|
|
||||||
model.nbIndices = static_cast<uint32_t>(loader.m_indices.size());
|
|
||||||
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
|
||||||
|
|
||||||
// Create the buffers on Device and copy vertices, indices and materials
|
|
||||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
|
||||||
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
|
||||||
VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
|
||||||
VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures
|
|
||||||
flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
|
||||||
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags);
|
|
||||||
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags);
|
|
||||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
|
|
||||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
|
|
||||||
// Creates all textures found and find the offset for this model
|
|
||||||
auto txtOffset = static_cast<uint32_t>(m_textures.size());
|
|
||||||
createTextureImages(cmdBuf, loader.m_textures);
|
|
||||||
cmdBufGet.submitAndWait(cmdBuf);
|
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
|
||||||
|
|
||||||
std::string objNb = std::to_string(m_objModel.size());
|
|
||||||
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
|
|
||||||
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
|
|
||||||
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
|
|
||||||
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
|
|
||||||
|
|
||||||
// Keeping transformation matrix of the instance
|
|
||||||
ObjInstance instance;
|
|
||||||
instance.transform = transform;
|
|
||||||
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
|
|
||||||
m_instances.push_back(instance);
|
|
||||||
|
|
||||||
// Creating information for device access
|
|
||||||
ObjDesc desc;
|
|
||||||
desc.txtOffset = txtOffset;
|
|
||||||
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
|
|
||||||
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
|
|
||||||
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
|
|
||||||
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
|
|
||||||
|
|
||||||
// Keeping the obj host model and device description
|
|
||||||
m_objModel.emplace_back(model);
|
|
||||||
m_objDesc.emplace_back(desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating the uniform buffer holding the camera matrices
|
|
||||||
// - Buffer is host visible
|
|
||||||
//
|
|
||||||
void HelloVulkan::createUniformBuffer()
|
|
||||||
{
|
|
||||||
m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
m_debug.setObjectName(m_bGlobals.buffer, "Globals");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Create a storage buffer containing the description of the scene elements
|
|
||||||
// - Which geometry is used by which instance
|
|
||||||
// - Transformation
|
|
||||||
// - Offset for texture
|
|
||||||
//
|
|
||||||
void HelloVulkan::createObjDescriptionBuffer()
|
|
||||||
{
|
|
||||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
|
||||||
|
|
||||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
|
||||||
m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
|
||||||
cmdGen.submitAndWait(cmdBuf);
|
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
|
||||||
m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating all textures and samplers
|
|
||||||
//
|
|
||||||
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
|
|
||||||
{
|
|
||||||
VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
|
||||||
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
samplerCreateInfo.maxLod = FLT_MAX;
|
|
||||||
|
|
||||||
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
|
||||||
|
|
||||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
|
||||||
if(textures.empty() && m_textures.empty())
|
|
||||||
{
|
|
||||||
nvvk::Texture texture;
|
|
||||||
|
|
||||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
|
||||||
VkDeviceSize bufferSize = sizeof(color);
|
|
||||||
auto imgSize = VkExtent2D{1, 1};
|
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
|
||||||
|
|
||||||
// Creating the dummy texture
|
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
|
||||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
|
||||||
|
|
||||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
m_textures.push_back(texture);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Uploading all images
|
|
||||||
for(const auto& texture : textures)
|
|
||||||
{
|
|
||||||
std::stringstream o;
|
|
||||||
int texWidth, texHeight, texChannels;
|
|
||||||
o << "media/textures/" << texture;
|
|
||||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
|
||||||
|
|
||||||
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
|
||||||
|
|
||||||
stbi_uc* pixels = stbi_pixels;
|
|
||||||
// Handle failure
|
|
||||||
if(!stbi_pixels)
|
|
||||||
{
|
|
||||||
texWidth = texHeight = 1;
|
|
||||||
texChannels = 4;
|
|
||||||
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
|
||||||
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
|
||||||
|
|
||||||
{
|
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
|
||||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
|
||||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
|
||||||
|
|
||||||
m_textures.push_back(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
stbi_image_free(stbi_pixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Destroying all allocations
|
|
||||||
//
|
|
||||||
void HelloVulkan::destroyResources()
|
|
||||||
{
|
|
||||||
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
|
||||||
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
|
||||||
|
|
||||||
m_alloc.destroy(m_bGlobals);
|
|
||||||
m_alloc.destroy(m_bObjDesc);
|
|
||||||
m_alloc.destroy(m_implObjects.implBuf);
|
|
||||||
m_alloc.destroy(m_implObjects.implMatBuf);
|
|
||||||
|
|
||||||
for(auto& m : m_objModel)
|
|
||||||
{
|
|
||||||
m_alloc.destroy(m.vertexBuffer);
|
|
||||||
m_alloc.destroy(m.indexBuffer);
|
|
||||||
m_alloc.destroy(m.matColorBuffer);
|
|
||||||
m_alloc.destroy(m.matIndexBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& t : m_textures)
|
|
||||||
{
|
|
||||||
m_alloc.destroy(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#Post
|
|
||||||
m_offscreen.destroy();
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
m_raytrace.destroy();
|
|
||||||
|
|
||||||
m_alloc.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Drawing the scene in raster mode
|
|
||||||
//
|
|
||||||
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
|
||||||
{
|
|
||||||
VkDeviceSize offset{0};
|
|
||||||
|
|
||||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
|
||||||
|
|
||||||
// Dynamic Viewport
|
|
||||||
setViewport(cmdBuf);
|
|
||||||
|
|
||||||
// Drawing all triangles
|
|
||||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
|
||||||
|
|
||||||
auto nbInst = static_cast<uint32_t>(m_instances.size() - 1); // Remove the implicit object
|
|
||||||
for(uint32_t i = 0; i < nbInst; ++i)
|
|
||||||
{
|
|
||||||
auto& inst = m_instances[i];
|
|
||||||
auto& model = m_objModel[inst.objIndex];
|
|
||||||
m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
|
||||||
m_pcRaster.modelMatrix = inst.transform;
|
|
||||||
|
|
||||||
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
|
||||||
sizeof(PushConstantRaster), &m_pcRaster);
|
|
||||||
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
|
||||||
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
|
||||||
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
|
||||||
}
|
|
||||||
m_debug.endLabel(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Handling resize of the window
|
|
||||||
//
|
|
||||||
void HelloVulkan::onResize(int /*w*/, int /*h*/)
|
|
||||||
{
|
|
||||||
m_offscreen.createFramebuffer(m_size);
|
|
||||||
m_offscreen.updateDescriptorSet();
|
|
||||||
m_raytrace.updateRtDescriptorSet(m_offscreen.colorTexture().descriptor.imageView);
|
|
||||||
resetFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Initialize offscreen rendering
|
|
||||||
//
|
|
||||||
void HelloVulkan::initOffscreen()
|
|
||||||
{
|
|
||||||
m_offscreen.createFramebuffer(m_size);
|
|
||||||
m_offscreen.createDescriptor();
|
|
||||||
m_offscreen.createPipeline(m_renderPass);
|
|
||||||
m_offscreen.updateDescriptorSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Initialize Vulkan ray tracing
|
|
||||||
//
|
|
||||||
void HelloVulkan::initRayTracing()
|
|
||||||
{
|
|
||||||
m_raytrace.createBottomLevelAS(m_objModel, m_implObjects);
|
|
||||||
m_raytrace.createTopLevelAS(m_instances, m_implObjects);
|
|
||||||
m_raytrace.createRtDescriptorSet(m_offscreen.colorTexture().descriptor.imageView);
|
|
||||||
m_raytrace.createRtPipeline(m_descSetLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Ray trace the scene
|
|
||||||
//
|
|
||||||
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor)
|
|
||||||
{
|
|
||||||
updateFrame();
|
|
||||||
if(m_pcRaster.frame >= m_maxFrames)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_raytrace.raytrace(cmdBuf, clearColor, m_descSet, m_size, m_pcRaster);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// If the camera matrix has changed, resets the frame.
|
|
||||||
// otherwise, increments frame.
|
|
||||||
//
|
|
||||||
void HelloVulkan::updateFrame()
|
|
||||||
{
|
|
||||||
static glm::mat4 refCamMatrix;
|
|
||||||
static float refFov{CameraManip.getFov()};
|
|
||||||
|
|
||||||
const auto& m = CameraManip.getMatrix();
|
|
||||||
const auto fov = CameraManip.getFov();
|
|
||||||
|
|
||||||
if(refCamMatrix != m || refFov != fov)
|
|
||||||
{
|
|
||||||
resetFrame();
|
|
||||||
refCamMatrix = m;
|
|
||||||
refFov = fov;
|
|
||||||
}
|
|
||||||
m_pcRaster.frame++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HelloVulkan::resetFrame()
|
|
||||||
{
|
|
||||||
m_pcRaster.frame = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void HelloVulkan::addImplSphere(glm::vec3 center, float radius, int matId)
|
|
||||||
{
|
|
||||||
ObjImplicit impl;
|
|
||||||
impl.minimum = center - radius;
|
|
||||||
impl.maximum = center + radius;
|
|
||||||
impl.objType = EObjType::eSphere;
|
|
||||||
impl.matId = matId;
|
|
||||||
m_implObjects.objImpl.push_back(impl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HelloVulkan::addImplCube(glm::vec3 minumum, glm::vec3 maximum, int matId)
|
|
||||||
{
|
|
||||||
ObjImplicit impl;
|
|
||||||
impl.minimum = minumum;
|
|
||||||
impl.maximum = maximum;
|
|
||||||
impl.objType = EObjType::eCube;
|
|
||||||
impl.matId = matId;
|
|
||||||
m_implObjects.objImpl.push_back(impl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HelloVulkan::addImplMaterial(const MaterialObj& mat)
|
|
||||||
{
|
|
||||||
m_implObjects.implMat.push_back(mat);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Create a storage buffer containing the description of the scene elements
|
|
||||||
// - Which geometry is used by which instance
|
|
||||||
// - Transformation
|
|
||||||
// - Offset for texture
|
|
||||||
//
|
|
||||||
void HelloVulkan::createImplictBuffers()
|
|
||||||
{
|
|
||||||
using vkBU = VkBufferUsageFlagBits;
|
|
||||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
|
||||||
|
|
||||||
// Not allowing empty buffers
|
|
||||||
if(m_implObjects.objImpl.empty())
|
|
||||||
m_implObjects.objImpl.push_back({});
|
|
||||||
if(m_implObjects.implMat.empty())
|
|
||||||
m_implObjects.implMat.push_back({});
|
|
||||||
|
|
||||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
|
||||||
m_implObjects.implBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.objImpl,
|
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR
|
|
||||||
| VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
|
||||||
| VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR);
|
|
||||||
m_implObjects.implMatBuf = m_alloc.createBuffer(cmdBuf, m_implObjects.implMat,
|
|
||||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
|
|
||||||
cmdGen.submitAndWait(cmdBuf);
|
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
|
||||||
m_debug.setObjectName(m_implObjects.implBuf.buffer, "implicitObj");
|
|
||||||
m_debug.setObjectName(m_implObjects.implMatBuf.buffer, "implicitMat");
|
|
||||||
|
|
||||||
|
|
||||||
// Adding an extra instance to get access to the material buffers
|
|
||||||
ObjDesc objDesc{};
|
|
||||||
objDesc.materialAddress = nvvk::getBufferDeviceAddress(m_device, m_implObjects.implMatBuf.buffer);
|
|
||||||
m_objDesc.emplace_back(objDesc);
|
|
||||||
|
|
||||||
ObjInstance instance{};
|
|
||||||
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
|
|
||||||
m_instances.emplace_back(instance);
|
|
||||||
}
|
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "nvvkhl/appbase_vk.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
|
||||||
#include "nvvk/resourceallocator_vk.hpp"
|
|
||||||
#include "shaders/host_device.h"
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
|
||||||
#include "offscreen.hpp"
|
|
||||||
|
|
||||||
#include "obj.hpp"
|
|
||||||
#include "raytrace.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
// Choosing the allocator to use
|
|
||||||
#define ALLOC_DMA
|
|
||||||
//#define ALLOC_DEDICATED
|
|
||||||
//#define ALLOC_VMA
|
|
||||||
#include <nvvk/resourceallocator_vk.hpp>
|
|
||||||
|
|
||||||
#if defined(ALLOC_DMA)
|
|
||||||
#include <nvvk/memallocator_dma_vk.hpp>
|
|
||||||
using Allocator = nvvk::ResourceAllocatorDma;
|
|
||||||
#elif defined(ALLOC_VMA)
|
|
||||||
#include <nvvk/memallocator_vma_vk.hpp>
|
|
||||||
using Allocator = nvvk::ResourceAllocatorVma;
|
|
||||||
#else
|
|
||||||
using Allocator = nvvk::ResourceAllocatorDedicated;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Simple rasterizer of OBJ objects
|
|
||||||
// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance`
|
|
||||||
// - It is possible to have many `ObjInstance` referencing the same `ObjModel`
|
|
||||||
// - Rendering is done in an offscreen framebuffer
|
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
|
||||||
//
|
|
||||||
class HelloVulkan : public nvvkhl::AppBaseVk
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
|
||||||
void createGraphicsPipeline();
|
|
||||||
void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1));
|
|
||||||
void updateDescriptorSet();
|
|
||||||
void createUniformBuffer();
|
|
||||||
void createObjDescriptionBuffer();
|
|
||||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
|
||||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
|
||||||
void destroyResources();
|
|
||||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
|
||||||
|
|
||||||
Offscreen& offscreen() { return m_offscreen; }
|
|
||||||
Raytracer& raytracer() { return m_raytrace; }
|
|
||||||
|
|
||||||
|
|
||||||
// Information pushed at each draw call
|
|
||||||
PushConstantRaster m_pcRaster{
|
|
||||||
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix
|
|
||||||
{10.f, 15.f, 8.f}, // light position
|
|
||||||
0, // instance Id
|
|
||||||
{-1.f, -1.f, -.4f}, // lightDirection;
|
|
||||||
0.939692621f, // {cos(glm::radians(20.0f))}, // lightSpotCutoff;
|
|
||||||
0.866025404f, // {cos(glm::radians(30.0f))}, // lightSpotOuterCutoff;
|
|
||||||
100.f, // light intensity
|
|
||||||
0 // light type
|
|
||||||
};
|
|
||||||
|
|
||||||
// Array of objects and instances in the scene
|
|
||||||
std::vector<ObjModel> m_objModel; // Model on host
|
|
||||||
std::vector<ObjDesc> m_objDesc; // Model description for device access
|
|
||||||
std::vector<ObjInstance> m_instances; // Scene model instances
|
|
||||||
|
|
||||||
|
|
||||||
// Graphic pipeline
|
|
||||||
VkPipelineLayout m_pipelineLayout;
|
|
||||||
VkPipeline m_graphicsPipeline;
|
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
|
||||||
VkDescriptorPool m_descPool;
|
|
||||||
VkDescriptorSetLayout m_descSetLayout;
|
|
||||||
VkDescriptorSet m_descSet;
|
|
||||||
|
|
||||||
int m_maxFrames{500};
|
|
||||||
void resetFrame();
|
|
||||||
void updateFrame();
|
|
||||||
|
|
||||||
nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
|
|
||||||
nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
|
|
||||||
|
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
|
||||||
|
|
||||||
|
|
||||||
Allocator m_alloc; // Allocator for buffer, images, acceleration structures
|
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
|
||||||
|
|
||||||
// #Post
|
|
||||||
Offscreen m_offscreen;
|
|
||||||
void initOffscreen();
|
|
||||||
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
Raytracer m_raytrace;
|
|
||||||
|
|
||||||
void initRayTracing();
|
|
||||||
void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor);
|
|
||||||
|
|
||||||
// Implicit
|
|
||||||
ImplInst m_implObjects;
|
|
||||||
|
|
||||||
void addImplSphere(glm::vec3 center, float radius, int matId);
|
|
||||||
void addImplCube(glm::vec3 minumum, glm::vec3 maximum, int matId);
|
|
||||||
void addImplMaterial(const MaterialObj& mat);
|
|
||||||
void createImplictBuffers();
|
|
||||||
};
|
|
||||||
|
Before Width: | Height: | Size: 366 KiB |
|
|
@ -1,365 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// ImGui - standalone example application for Glfw + Vulkan, using programmable
|
|
||||||
// pipeline If you are new to ImGui, see examples/README.txt and documentation
|
|
||||||
// at the top of imgui.cpp.
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
|
||||||
#include "backends/imgui_impl_vulkan.h"
|
|
||||||
#include "imgui.h"
|
|
||||||
#include "imgui/imgui_helper.h"
|
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
|
||||||
#include "imgui/imgui_camera_widget.h"
|
|
||||||
#include "nvh/cameramanipulator.hpp"
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvpsystem.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/context_vk.hpp"
|
|
||||||
|
|
||||||
#include <random>
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
#define UNUSED(x) (void)(x)
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default search path for shaders
|
|
||||||
std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
|
||||||
static void onErrorCallback(int error, const char* description)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extra UI
|
|
||||||
void renderUI(HelloVulkan& helloVk)
|
|
||||||
{
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
changed |= ImGuiH::CameraWidget();
|
|
||||||
if(ImGui::CollapsingHeader("Light"))
|
|
||||||
{
|
|
||||||
auto& pc = helloVk.m_pcRaster;
|
|
||||||
|
|
||||||
changed |= ImGui::RadioButton("Point", &pc.lightType, 0);
|
|
||||||
ImGui::SameLine();
|
|
||||||
changed |= ImGui::RadioButton("Spot", &pc.lightType, 1);
|
|
||||||
ImGui::SameLine();
|
|
||||||
changed |= ImGui::RadioButton("Infinite", &pc.lightType, 2);
|
|
||||||
|
|
||||||
|
|
||||||
if(pc.lightType < 2)
|
|
||||||
{
|
|
||||||
changed |= ImGui::SliderFloat3("Light Position", &pc.lightPosition.x, -20.f, 20.f);
|
|
||||||
}
|
|
||||||
if(pc.lightType > 0)
|
|
||||||
{
|
|
||||||
changed |= ImGui::SliderFloat3("Light Direction", &pc.lightDirection.x, -1.f, 1.f);
|
|
||||||
}
|
|
||||||
if(pc.lightType < 2)
|
|
||||||
{
|
|
||||||
changed |= ImGui::SliderFloat("Light Intensity", &pc.lightIntensity, 0.f, 500.f);
|
|
||||||
}
|
|
||||||
if(pc.lightType == 1)
|
|
||||||
{
|
|
||||||
float dCutoff = glm::degrees(acos(pc.lightSpotCutoff));
|
|
||||||
float dOutCutoff = glm::degrees(acos(pc.lightSpotOuterCutoff));
|
|
||||||
changed |= ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f);
|
|
||||||
changed |= ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f);
|
|
||||||
dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff;
|
|
||||||
|
|
||||||
pc.lightSpotCutoff = cos(glm::radians(dCutoff));
|
|
||||||
pc.lightSpotOuterCutoff = cos(glm::radians(dOutCutoff));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 1000);
|
|
||||||
if(changed)
|
|
||||||
helloVk.resetFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Application Entry
|
|
||||||
//
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
UNUSED(argc);
|
|
||||||
|
|
||||||
// Setup GLFW window
|
|
||||||
glfwSetErrorCallback(onErrorCallback);
|
|
||||||
if(!glfwInit())
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
||||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
||||||
CameraManip.setLookat({8.440, 9.041, -8.973}, {-2.462, 3.661, -0.286}, {0.000, 1.000, 0.000});
|
|
||||||
|
|
||||||
// Setup Vulkan
|
|
||||||
if(!glfwVulkanSupported())
|
|
||||||
{
|
|
||||||
printf("GLFW: Vulkan Not Supported\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup some basic things for the sample, logging file for example
|
|
||||||
NVPSystem system(PROJECT_NAME);
|
|
||||||
|
|
||||||
// Search path for shaders and other media
|
|
||||||
defaultSearchPaths = {
|
|
||||||
NVPSystem::exePath() + PROJECT_RELDIRECTORY,
|
|
||||||
NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
|
|
||||||
std::string(PROJECT_NAME),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Vulkan required extensions
|
|
||||||
assert(glfwVulkanSupported() == 1);
|
|
||||||
uint32_t count{0};
|
|
||||||
auto reqExtensions = glfwGetRequiredInstanceExtensions(&count);
|
|
||||||
|
|
||||||
// Requesting Vulkan extensions and layers
|
|
||||||
nvvk::ContextCreateInfo contextInfo;
|
|
||||||
contextInfo.setVersion(1, 2); // Using Vulkan 1.2
|
|
||||||
for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..)
|
|
||||||
contextInfo.addInstanceExtension(reqExtensions[ext_id]);
|
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering
|
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
|
||||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures
|
|
||||||
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline
|
|
||||||
|
|
||||||
// Creating Vulkan base application
|
|
||||||
nvvk::Context vkctx{};
|
|
||||||
vkctx.initInstance(contextInfo);
|
|
||||||
// Find all compatible devices
|
|
||||||
auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo);
|
|
||||||
assert(!compatibleDevices.empty());
|
|
||||||
// Use a compatible device
|
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
|
||||||
|
|
||||||
// Create example
|
|
||||||
HelloVulkan helloVk;
|
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
|
||||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
||||||
helloVk.createDepthBuffer();
|
|
||||||
helloVk.createRenderPass();
|
|
||||||
helloVk.createFrameBuffers();
|
|
||||||
|
|
||||||
// Setup Imgui
|
|
||||||
helloVk.initGUI(0); // Using sub-pass 0
|
|
||||||
|
|
||||||
// Creation of the example
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true),
|
|
||||||
glm::scale(glm::mat4(1.f), glm::vec3(0.5f)) * glm::translate(glm::mat4(1.f), glm::vec3(0.0f, 0.0f, 6.0f)));
|
|
||||||
|
|
||||||
std::random_device rd; // Will be used to obtain a seed for the random number engine
|
|
||||||
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
|
|
||||||
std::normal_distribution<float> dis(2.0f, 2.0f);
|
|
||||||
std::normal_distribution<float> disn(0.5f, 0.2f);
|
|
||||||
auto wusonIndex = static_cast<int>(helloVk.m_objModel.size() - 1);
|
|
||||||
|
|
||||||
for(int n = 0; n < 50; ++n)
|
|
||||||
{
|
|
||||||
ObjInstance inst;
|
|
||||||
inst.objIndex = wusonIndex;
|
|
||||||
float scale = fabsf(disn(gen));
|
|
||||||
glm::mat4 mat = glm::translate(glm::mat4(1), glm::vec3{dis(gen), 0.f, dis(gen) + 6});
|
|
||||||
// mat = mat * glm::rotation_mat4_x(dis(gen));
|
|
||||||
mat = glm::scale(mat, glm::vec3(scale));
|
|
||||||
inst.transform = mat;
|
|
||||||
|
|
||||||
helloVk.m_instances.push_back(inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creation of implicit geometry
|
|
||||||
MaterialObj mat;
|
|
||||||
// Reflective
|
|
||||||
mat.diffuse = glm::vec3(0, 0, 0);
|
|
||||||
mat.specular = glm::vec3(1.f);
|
|
||||||
mat.shininess = 0.0;
|
|
||||||
mat.illum = 3;
|
|
||||||
helloVk.addImplMaterial(mat);
|
|
||||||
// Transparent
|
|
||||||
mat.diffuse = glm::vec3(0.4, 0.4, 1);
|
|
||||||
mat.illum = 4;
|
|
||||||
mat.dissolve = 0.5;
|
|
||||||
helloVk.addImplMaterial(mat);
|
|
||||||
helloVk.addImplCube({-6.1, 0, -6}, {-6, 10, 6}, 0);
|
|
||||||
helloVk.addImplSphere({1, 2, 4}, 1.f, 1);
|
|
||||||
|
|
||||||
|
|
||||||
helloVk.initOffscreen();
|
|
||||||
Offscreen& offscreen = helloVk.offscreen();
|
|
||||||
|
|
||||||
helloVk.createImplictBuffers();
|
|
||||||
|
|
||||||
|
|
||||||
helloVk.createDescriptorSetLayout();
|
|
||||||
helloVk.createGraphicsPipeline();
|
|
||||||
helloVk.createUniformBuffer();
|
|
||||||
helloVk.createObjDescriptionBuffer();
|
|
||||||
helloVk.updateDescriptorSet();
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
helloVk.initRayTracing();
|
|
||||||
|
|
||||||
|
|
||||||
glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f);
|
|
||||||
bool useRaytracer = true;
|
|
||||||
|
|
||||||
|
|
||||||
helloVk.setupGlfwCallbacks(window);
|
|
||||||
ImGui_ImplGlfw_InitForVulkan(window, true);
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
while(!glfwWindowShouldClose(window))
|
|
||||||
{
|
|
||||||
glfwPollEvents();
|
|
||||||
if(helloVk.isMinimized())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
|
||||||
ImGui_ImplGlfw_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
|
||||||
if(helloVk.showGui())
|
|
||||||
{
|
|
||||||
ImGuiH::Panel::Begin();
|
|
||||||
bool changed = false;
|
|
||||||
// Edit 3 floats representing a color
|
|
||||||
changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
|
||||||
// Switch between raster and ray tracing
|
|
||||||
changed |= ImGui::Checkbox("Ray Tracer mode", &useRaytracer);
|
|
||||||
if(changed)
|
|
||||||
helloVk.resetFrame();
|
|
||||||
|
|
||||||
renderUI(helloVk);
|
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
|
||||||
ImGuiH::Panel::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start rendering the scene
|
|
||||||
helloVk.prepareFrame();
|
|
||||||
|
|
||||||
// Start command buffer of this frame
|
|
||||||
auto curFrame = helloVk.getCurFrame();
|
|
||||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
|
||||||
|
|
||||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
|
||||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
||||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
|
||||||
|
|
||||||
// Updating camera buffer
|
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
|
||||||
|
|
||||||
// Clearing screen
|
|
||||||
std::array<VkClearValue, 2> clearValues{};
|
|
||||||
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
|
||||||
clearValues[1].depthStencil = {1.0f, 0};
|
|
||||||
|
|
||||||
// Offscreen render pass
|
|
||||||
{
|
|
||||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
|
||||||
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
|
||||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
|
||||||
offscreenRenderPassBeginInfo.renderPass = offscreen.renderPass();
|
|
||||||
offscreenRenderPassBeginInfo.framebuffer = offscreen.frameBuffer();
|
|
||||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
|
||||||
|
|
||||||
// Rendering Scene
|
|
||||||
if(useRaytracer)
|
|
||||||
{
|
|
||||||
helloVk.raytrace(cmdBuf, clearColor);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
helloVk.rasterize(cmdBuf);
|
|
||||||
vkCmdEndRenderPass(cmdBuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
|
||||||
{
|
|
||||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
|
||||||
postRenderPassBeginInfo.clearValueCount = 2;
|
|
||||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
|
||||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
|
||||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
|
||||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
|
||||||
|
|
||||||
// Rendering tonemapper
|
|
||||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
offscreen.draw(cmdBuf, helloVk.getSize());
|
|
||||||
|
|
||||||
// Rendering UI
|
|
||||||
ImGui::Render();
|
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
|
||||||
vkCmdEndRenderPass(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit for display
|
|
||||||
vkEndCommandBuffer(cmdBuf);
|
|
||||||
helloVk.submitFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
vkDeviceWaitIdle(helloVk.getDevice());
|
|
||||||
|
|
||||||
helloVk.destroyResources();
|
|
||||||
helloVk.destroy();
|
|
||||||
vkctx.deinit();
|
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
|
||||||
glfwTerminate();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "obj_loader.h"
|
|
||||||
|
|
||||||
|
|
||||||
// The OBJ model
|
|
||||||
struct ObjModel
|
|
||||||
{
|
|
||||||
uint32_t nbIndices{0};
|
|
||||||
uint32_t nbVertices{0};
|
|
||||||
nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex'
|
|
||||||
nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles
|
|
||||||
nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material'
|
|
||||||
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ObjInstance
|
|
||||||
{
|
|
||||||
glm::mat4 transform; // Matrix of the instance
|
|
||||||
uint32_t objIndex{0}; // Model index reference
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum EObjType
|
|
||||||
{
|
|
||||||
eSphere = 0,
|
|
||||||
eCube
|
|
||||||
};
|
|
||||||
|
|
||||||
// One single implicit object
|
|
||||||
struct ObjImplicit
|
|
||||||
{
|
|
||||||
glm::vec3 minimum{0, 0, 0}; // Aabb
|
|
||||||
glm::vec3 maximum{0, 0, 0}; // Aabb
|
|
||||||
int objType{0}; // 0: Sphere, 1: Cube
|
|
||||||
int matId{0};
|
|
||||||
};
|
|
||||||
|
|
||||||
// All implicit objects
|
|
||||||
struct ImplInst
|
|
||||||
{
|
|
||||||
std::vector<ObjImplicit> objImpl; // All objects
|
|
||||||
std::vector<MaterialObj> implMat; // All materials used by implicit obj
|
|
||||||
nvvk::Buffer implBuf; // Buffer of objects
|
|
||||||
nvvk::Buffer implMatBuf; // Buffer of material
|
|
||||||
int blasId{0};
|
|
||||||
glm::mat4 transform{1};
|
|
||||||
};
|
|
||||||
|
|
@ -1,191 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "offscreen.hpp"
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
#include "nvvk/images_vk.hpp"
|
|
||||||
#include "nvvk/pipeline_vk.hpp"
|
|
||||||
#include "nvvk/renderpasses_vk.hpp"
|
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Post-processing
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void Offscreen::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily)
|
|
||||||
{
|
|
||||||
m_device = device;
|
|
||||||
m_alloc = allocator;
|
|
||||||
m_graphicsQueueIndex = queueFamily;
|
|
||||||
m_debug.setup(m_device);
|
|
||||||
m_depthFormat = nvvk::findDepthFormat(physicalDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Offscreen::destroy()
|
|
||||||
{
|
|
||||||
vkDestroyPipeline(m_device, m_pipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
|
||||||
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_dsetLayout, nullptr);
|
|
||||||
vkDestroyRenderPass(m_device, m_renderPass, nullptr);
|
|
||||||
vkDestroyFramebuffer(m_device, m_framebuffer, nullptr);
|
|
||||||
m_alloc->destroy(m_colorTexture);
|
|
||||||
m_alloc->destroy(m_depthTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating an offscreen frame buffer and the associated render pass
|
|
||||||
//
|
|
||||||
void Offscreen::createFramebuffer(const VkExtent2D& size)
|
|
||||||
{
|
|
||||||
m_alloc->destroy(m_colorTexture);
|
|
||||||
m_alloc->destroy(m_depthTexture);
|
|
||||||
|
|
||||||
// Creating the color image
|
|
||||||
{
|
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(
|
|
||||||
size, m_colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
|
|
||||||
|
|
||||||
nvvk::Image image = m_alloc->createImage(colorCreateInfo);
|
|
||||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
|
||||||
|
|
||||||
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
|
||||||
m_colorTexture = m_alloc->createTexture(image, ivInfo, sampler);
|
|
||||||
m_colorTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Creating the depth buffer
|
|
||||||
{
|
|
||||||
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(size, m_depthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
|
||||||
nvvk::Image image = m_alloc->createImage(depthCreateInfo);
|
|
||||||
|
|
||||||
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
|
||||||
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
depthStencilView.format = m_depthFormat;
|
|
||||||
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
|
||||||
depthStencilView.image = image.image;
|
|
||||||
|
|
||||||
m_depthTexture = m_alloc->createTexture(image, depthStencilView);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting the image layout for both color and depth
|
|
||||||
{
|
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
|
||||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_colorTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_depthTexture.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
|
||||||
|
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating a renderpass for the offscreen
|
|
||||||
if(!m_renderPass)
|
|
||||||
{
|
|
||||||
m_renderPass = nvvk::createRenderPass(m_device, {m_colorFormat}, m_depthFormat, 1, true, true,
|
|
||||||
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating the frame buffer for offscreen
|
|
||||||
std::vector<VkImageView> attachments = {m_colorTexture.descriptor.imageView, m_depthTexture.descriptor.imageView};
|
|
||||||
|
|
||||||
vkDestroyFramebuffer(m_device, m_framebuffer, nullptr);
|
|
||||||
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
|
||||||
info.renderPass = m_renderPass;
|
|
||||||
info.attachmentCount = 2;
|
|
||||||
info.pAttachments = attachments.data();
|
|
||||||
info.width = size.width;
|
|
||||||
info.height = size.height;
|
|
||||||
info.layers = 1;
|
|
||||||
vkCreateFramebuffer(m_device, &info, nullptr, &m_framebuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more
|
|
||||||
// The incoming render pass, is in which rendering pass it will be displayed (framebuffer)
|
|
||||||
//
|
|
||||||
void Offscreen::createPipeline(VkRenderPass& renderPass)
|
|
||||||
{
|
|
||||||
// Push constants in the fragment shader
|
|
||||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
|
||||||
|
|
||||||
// Creating the pipeline layout
|
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
||||||
pipelineLayoutCreateInfo.setLayoutCount = 1;
|
|
||||||
pipelineLayoutCreateInfo.pSetLayouts = &m_dsetLayout;
|
|
||||||
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
|
|
||||||
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRanges;
|
|
||||||
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_pipelineLayout);
|
|
||||||
|
|
||||||
// Pipeline: completely generic, no vertices
|
|
||||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_pipelineLayout, renderPass);
|
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
||||||
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
|
||||||
m_pipeline = pipelineGenerator.createPipeline();
|
|
||||||
m_debug.setObjectName(m_pipeline, "post");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// The descriptor layout is the description of the data that is passed to the vertex or the
|
|
||||||
// fragment program.
|
|
||||||
//
|
|
||||||
void Offscreen::createDescriptor()
|
|
||||||
{
|
|
||||||
m_dsetLayoutBinding.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
||||||
m_dsetLayout = m_dsetLayoutBinding.createLayout(m_device);
|
|
||||||
m_descPool = m_dsetLayoutBinding.createPool(m_device);
|
|
||||||
m_dset = nvvk::allocateDescriptorSet(m_device, m_descPool, m_dsetLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Update the output
|
|
||||||
//
|
|
||||||
void Offscreen::updateDescriptorSet()
|
|
||||||
{
|
|
||||||
VkWriteDescriptorSet writeDescriptorSets = m_dsetLayoutBinding.makeWrite(m_dset, 0, &m_colorTexture.descriptor);
|
|
||||||
vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Draw a full screen quad with the attached image
|
|
||||||
//
|
|
||||||
void Offscreen::draw(VkCommandBuffer cmdBuf, const VkExtent2D& size)
|
|
||||||
{
|
|
||||||
m_debug.beginLabel(cmdBuf, "Post");
|
|
||||||
|
|
||||||
VkViewport viewport{0, 0, (float)size.width, (float)size.height, 0, 1};
|
|
||||||
vkCmdSetViewport(cmdBuf, 0, 1, &viewport);
|
|
||||||
VkRect2D scissor{{0, 0}, {size.width, size.height}};
|
|
||||||
vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
|
|
||||||
|
|
||||||
|
|
||||||
auto aspectRatio = static_cast<float>(size.width) / static_cast<float>(size.height);
|
|
||||||
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
|
||||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_dset, 0, nullptr);
|
|
||||||
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
#include "nvvk/resourceallocator_vk.hpp"
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Class to render in off-screen framebuffers. Instead of rendering directly to the
|
|
||||||
// screen back buffer, this class create the output frame buffer 'createFramebuffer',
|
|
||||||
// and use the pipeline from 'createPipeline' to render a quad 'draw' with the colorTexture
|
|
||||||
// image
|
|
||||||
|
|
||||||
class Offscreen
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily);
|
|
||||||
void destroy();
|
|
||||||
|
|
||||||
void createFramebuffer(const VkExtent2D& size);
|
|
||||||
void createPipeline(VkRenderPass& renderPass);
|
|
||||||
void createDescriptor();
|
|
||||||
void updateDescriptorSet();
|
|
||||||
void draw(VkCommandBuffer cmdBuf, const VkExtent2D& size);
|
|
||||||
|
|
||||||
const VkRenderPass& renderPass() { return m_renderPass; }
|
|
||||||
const VkFramebuffer& frameBuffer() { return m_framebuffer; }
|
|
||||||
const nvvk::Texture& colorTexture() { return m_colorTexture; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
nvvk::DescriptorSetBindings m_dsetLayoutBinding;
|
|
||||||
VkDescriptorPool m_descPool{VK_NULL_HANDLE};
|
|
||||||
VkDescriptorSetLayout m_dsetLayout{VK_NULL_HANDLE};
|
|
||||||
VkDescriptorSet m_dset{VK_NULL_HANDLE};
|
|
||||||
VkPipeline m_pipeline{VK_NULL_HANDLE};
|
|
||||||
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
|
|
||||||
VkRenderPass m_renderPass{VK_NULL_HANDLE};
|
|
||||||
VkFramebuffer m_framebuffer{VK_NULL_HANDLE};
|
|
||||||
|
|
||||||
nvvk::Texture m_colorTexture;
|
|
||||||
VkFormat m_colorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
|
||||||
nvvk::Texture m_depthTexture;
|
|
||||||
VkFormat m_depthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
|
||||||
|
|
||||||
nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
|
|
||||||
VkDevice m_device;
|
|
||||||
int m_graphicsQueueIndex{0};
|
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
|
||||||
};
|
|
||||||
|
|
@ -1,439 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "raytrace.hpp"
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
|
|
||||||
#include "nvh/alignment.hpp"
|
|
||||||
#include "nvvk/shaders_vk.hpp"
|
|
||||||
#include "obj_loader.h"
|
|
||||||
#include "nvvk/buffers_vk.hpp"
|
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
|
|
||||||
void Raytracer::setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily)
|
|
||||||
{
|
|
||||||
m_device = device;
|
|
||||||
m_physicalDevice = physicalDevice;
|
|
||||||
m_alloc = allocator;
|
|
||||||
m_graphicsQueueIndex = queueFamily;
|
|
||||||
|
|
||||||
// Requesting ray tracing properties
|
|
||||||
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
|
||||||
prop2.pNext = &m_rtProperties;
|
|
||||||
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
|
||||||
|
|
||||||
m_rtBuilder.setup(m_device, allocator, m_graphicsQueueIndex);
|
|
||||||
m_sbtWrapper.setup(device, queueFamily, allocator, m_rtProperties);
|
|
||||||
m_debug.setup(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Raytracer::destroy()
|
|
||||||
{
|
|
||||||
m_sbtWrapper.destroy();
|
|
||||||
m_rtBuilder.destroy();
|
|
||||||
vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr);
|
|
||||||
vkDestroyPipeline(m_device, m_rtPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr);
|
|
||||||
m_alloc->destroy(m_rtSBTBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Converting a OBJ primitive to the ray tracing geometry used for the BLAS
|
|
||||||
//
|
|
||||||
auto Raytracer::objectToVkGeometryKHR(const ObjModel& model)
|
|
||||||
{
|
|
||||||
// Building part
|
|
||||||
VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
|
|
||||||
VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
|
|
||||||
|
|
||||||
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
|
||||||
triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
triangles.vertexData.deviceAddress = vertexAddress;
|
|
||||||
triangles.vertexStride = sizeof(VertexObj);
|
|
||||||
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
|
||||||
triangles.indexData.deviceAddress = indexAddress;
|
|
||||||
triangles.transformData = {};
|
|
||||||
triangles.maxVertex = model.nbVertices - 1;
|
|
||||||
|
|
||||||
// Setting up the build info of the acceleration
|
|
||||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
|
||||||
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
|
||||||
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit
|
|
||||||
asGeom.geometry.triangles = triangles;
|
|
||||||
|
|
||||||
|
|
||||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
|
||||||
offset.firstVertex = 0;
|
|
||||||
offset.primitiveCount = model.nbIndices / 3; // Nb triangles
|
|
||||||
offset.primitiveOffset = 0;
|
|
||||||
offset.transformOffset = 0;
|
|
||||||
|
|
||||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
|
||||||
input.asGeometry.emplace_back(asGeom);
|
|
||||||
input.asBuildOffsetInfo.emplace_back(offset);
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Returning the ray tracing geometry used for the BLAS, containing all spheres
|
|
||||||
//
|
|
||||||
auto Raytracer::implicitToVkGeometryKHR(const ImplInst& implicitObj)
|
|
||||||
{
|
|
||||||
VkDeviceAddress dataAddress = nvvk::getBufferDeviceAddress(m_device, implicitObj.implBuf.buffer);
|
|
||||||
|
|
||||||
VkAccelerationStructureGeometryAabbsDataKHR aabbs{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR};
|
|
||||||
aabbs.data.deviceAddress = dataAddress;
|
|
||||||
aabbs.stride = sizeof(ObjImplicit);
|
|
||||||
|
|
||||||
// Setting up the build info of the acceleration
|
|
||||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
|
||||||
asGeom.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
|
|
||||||
asGeom.flags = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; // For AnyHit
|
|
||||||
asGeom.geometry.aabbs = aabbs;
|
|
||||||
|
|
||||||
|
|
||||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
|
||||||
offset.firstVertex = 0;
|
|
||||||
offset.primitiveCount = static_cast<uint32_t>(implicitObj.objImpl.size()); // Nb aabb
|
|
||||||
offset.primitiveOffset = 0;
|
|
||||||
offset.transformOffset = 0;
|
|
||||||
|
|
||||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
|
||||||
input.asGeometry.emplace_back(asGeom);
|
|
||||||
input.asBuildOffsetInfo.emplace_back(offset);
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Raytracer::createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj)
|
|
||||||
{
|
|
||||||
// BLAS - Storing each primitive in a geometry
|
|
||||||
std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
|
|
||||||
allBlas.reserve(models.size());
|
|
||||||
for(const auto& obj : models)
|
|
||||||
{
|
|
||||||
auto blas = objectToVkGeometryKHR(obj);
|
|
||||||
|
|
||||||
// We could add more geometry in each BLAS, but we add only one for now
|
|
||||||
allBlas.emplace_back(blas);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adding implicit
|
|
||||||
if(!implicitObj.objImpl.empty())
|
|
||||||
{
|
|
||||||
auto blas = implicitToVkGeometryKHR(implicitObj);
|
|
||||||
allBlas.emplace_back(blas);
|
|
||||||
implicitObj.blasId = static_cast<int>(allBlas.size() - 1); // remember blas ID for tlas
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR
|
|
||||||
| VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Raytracer::createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj)
|
|
||||||
{
|
|
||||||
std::vector<VkAccelerationStructureInstanceKHR> tlas;
|
|
||||||
|
|
||||||
|
|
||||||
auto nbObj = static_cast<uint32_t>(instances.size()) - 1; // minus the implicit (for material)
|
|
||||||
tlas.reserve(instances.size());
|
|
||||||
for(uint32_t i = 0; i < nbObj; i++)
|
|
||||||
{
|
|
||||||
VkAccelerationStructureInstanceKHR rayInst{};
|
|
||||||
rayInst.transform = nvvk::toTransformMatrixKHR(instances[i].transform); // Position of the instance
|
|
||||||
rayInst.instanceCustomIndex = instances[i].objIndex; // gl_InstanceCustomIndexEXT
|
|
||||||
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(instances[i].objIndex);
|
|
||||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
|
||||||
rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
|
|
||||||
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
|
|
||||||
tlas.emplace_back(rayInst);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the blas containing all implicit
|
|
||||||
if(!implicitObj.objImpl.empty())
|
|
||||||
{
|
|
||||||
VkAccelerationStructureInstanceKHR rayInst{};
|
|
||||||
rayInst.transform = nvvk::toTransformMatrixKHR(implicitObj.transform); // Position of the instance
|
|
||||||
rayInst.instanceCustomIndex = instances[nbObj].objIndex;
|
|
||||||
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(static_cast<uint32_t>(implicitObj.blasId));
|
|
||||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
|
||||||
rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
|
|
||||||
rayInst.instanceShaderBindingTableRecordOffset = 1; // We will use the same hit group for all objects (the second one)
|
|
||||||
tlas.emplace_back(rayInst);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// This descriptor set holds the Acceleration structure and the output image
|
|
||||||
//
|
|
||||||
void Raytracer::createRtDescriptorSet(const VkImageView& outputImage)
|
|
||||||
{
|
|
||||||
using vkDSLB = VkDescriptorSetLayoutBinding;
|
|
||||||
|
|
||||||
m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
|
|
||||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
|
|
||||||
m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
|
|
||||||
|
|
||||||
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
|
|
||||||
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
|
|
||||||
|
|
||||||
VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
|
||||||
allocateInfo.descriptorPool = m_rtDescPool;
|
|
||||||
allocateInfo.descriptorSetCount = 1;
|
|
||||||
allocateInfo.pSetLayouts = &m_rtDescSetLayout;
|
|
||||||
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet);
|
|
||||||
|
|
||||||
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
|
||||||
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
|
||||||
descASInfo.accelerationStructureCount = 1;
|
|
||||||
descASInfo.pAccelerationStructures = &tlas;
|
|
||||||
VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<VkWriteDescriptorSet> writes;
|
|
||||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo));
|
|
||||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo));
|
|
||||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Writes the output image to the descriptor set
|
|
||||||
// - Required when changing resolution
|
|
||||||
//
|
|
||||||
void Raytracer::updateRtDescriptorSet(const VkImageView& outputImage)
|
|
||||||
{
|
|
||||||
VkDescriptorImageInfo imageInfo{{}, outputImage, VK_IMAGE_LAYOUT_GENERAL};
|
|
||||||
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo);
|
|
||||||
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Pipeline for the ray tracer: all shaders, raygen, chit, miss
|
|
||||||
//
|
|
||||||
void Raytracer::createRtPipeline(VkDescriptorSetLayout& sceneDescLayout)
|
|
||||||
{
|
|
||||||
|
|
||||||
enum StageIndices
|
|
||||||
{
|
|
||||||
eRaygen,
|
|
||||||
eMiss,
|
|
||||||
eMiss2,
|
|
||||||
eClosestHit,
|
|
||||||
eAnyHit,
|
|
||||||
eClosestHit1,
|
|
||||||
eAnyHit1,
|
|
||||||
eIntersect,
|
|
||||||
eCall0,
|
|
||||||
eCall1,
|
|
||||||
eCall2,
|
|
||||||
eShaderGroupCount
|
|
||||||
};
|
|
||||||
|
|
||||||
// All stages
|
|
||||||
std::array<VkPipelineShaderStageCreateInfo, eShaderGroupCount> stages{};
|
|
||||||
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
|
||||||
stage.pName = "main"; // All the same entry point
|
|
||||||
// Raygen
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
|
||||||
stages[eRaygen] = stage;
|
|
||||||
// Miss
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
|
||||||
stages[eMiss] = stage;
|
|
||||||
// The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found
|
|
||||||
stage.module =
|
|
||||||
nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
|
||||||
stages[eMiss2] = stage;
|
|
||||||
// Hit Group - Closest Hit
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
|
||||||
stages[eClosestHit] = stage;
|
|
||||||
// Hit Group - Closest Hit
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rahit.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
|
||||||
stages[eAnyHit] = stage;
|
|
||||||
// Hit Group - 1
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rchit.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
|
||||||
stages[eClosestHit1] = stage;
|
|
||||||
// Hit
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace2.rahit.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
|
|
||||||
stages[eAnyHit1] = stage;
|
|
||||||
// Hit
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rint.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
|
|
||||||
stages[eIntersect] = stage;
|
|
||||||
|
|
||||||
// Call0
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_point.rcall.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
|
||||||
stages[eCall0] = stage;
|
|
||||||
// Call1
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_spot.rcall.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
|
||||||
stages[eCall1] = stage;
|
|
||||||
// Call2
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/light_inf.rcall.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_CALLABLE_BIT_KHR;
|
|
||||||
stages[eCall2] = stage;
|
|
||||||
|
|
||||||
|
|
||||||
// Shader groups
|
|
||||||
VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR};
|
|
||||||
group.anyHitShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.intersectionShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
|
|
||||||
// Raygen
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
|
||||||
group.generalShader = eRaygen;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
// Miss
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
|
||||||
group.generalShader = eMiss;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
// Shadow Miss
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
|
||||||
group.generalShader = eMiss2;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
// closest hit shader
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
|
||||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.closestHitShader = eClosestHit;
|
|
||||||
group.anyHitShader = eAnyHit;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
// closest hit shader
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
|
|
||||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.closestHitShader = eClosestHit1;
|
|
||||||
group.anyHitShader = eAnyHit1;
|
|
||||||
group.intersectionShader = eIntersect;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
// Callable shaders
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
|
||||||
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.anyHitShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.intersectionShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.generalShader = eCall0;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
group.generalShader = eCall1;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
group.generalShader = eCall2;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
|
|
||||||
// Push constant: we want to be able to update constants used by the shaders
|
|
||||||
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR
|
|
||||||
| VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR,
|
|
||||||
0, sizeof(PushConstantRay)};
|
|
||||||
|
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
||||||
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
|
|
||||||
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant;
|
|
||||||
|
|
||||||
// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline
|
|
||||||
std::vector<VkDescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, sceneDescLayout};
|
|
||||||
pipelineLayoutCreateInfo.setLayoutCount = static_cast<uint32_t>(rtDescSetLayouts.size());
|
|
||||||
pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data();
|
|
||||||
|
|
||||||
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout);
|
|
||||||
|
|
||||||
|
|
||||||
// Assemble the shader stages and recursion depth info into the ray tracing pipeline
|
|
||||||
VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
|
|
||||||
rayPipelineInfo.stageCount = static_cast<uint32_t>(stages.size()); // Stages are shaders
|
|
||||||
rayPipelineInfo.pStages = stages.data();
|
|
||||||
|
|
||||||
rayPipelineInfo.groupCount = static_cast<uint32_t>(m_rtShaderGroups.size());
|
|
||||||
rayPipelineInfo.pGroups = m_rtShaderGroups.data();
|
|
||||||
|
|
||||||
// The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the
|
|
||||||
// hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
|
|
||||||
// as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
|
|
||||||
// in the ray generation to avoid deep recursion.
|
|
||||||
rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth
|
|
||||||
rayPipelineInfo.layout = m_rtPipelineLayout;
|
|
||||||
|
|
||||||
vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
|
|
||||||
|
|
||||||
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo);
|
|
||||||
|
|
||||||
|
|
||||||
for(auto& s : stages)
|
|
||||||
vkDestroyShaderModule(m_device, s.module, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Ray Tracing the scene
|
|
||||||
//
|
|
||||||
void Raytracer::raytrace(const VkCommandBuffer& cmdBuf,
|
|
||||||
const glm::vec4& clearColor,
|
|
||||||
VkDescriptorSet& sceneDescSet,
|
|
||||||
VkExtent2D& size,
|
|
||||||
PushConstantRaster& sceneConstants)
|
|
||||||
{
|
|
||||||
m_debug.beginLabel(cmdBuf, "Ray trace");
|
|
||||||
// Initializing push constant values
|
|
||||||
m_pcRay.clearColor = clearColor;
|
|
||||||
m_pcRay.lightPosition = sceneConstants.lightPosition;
|
|
||||||
m_pcRay.lightIntensity = sceneConstants.lightIntensity;
|
|
||||||
m_pcRay.lightDirection = sceneConstants.lightDirection;
|
|
||||||
m_pcRay.lightSpotCutoff = sceneConstants.lightSpotCutoff;
|
|
||||||
m_pcRay.lightSpotOuterCutoff = sceneConstants.lightSpotOuterCutoff;
|
|
||||||
m_pcRay.lightType = sceneConstants.lightType;
|
|
||||||
m_pcRay.frame = sceneConstants.frame;
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<VkDescriptorSet> descSets{m_rtDescSet, sceneDescSet};
|
|
||||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0,
|
|
||||||
(uint32_t)descSets.size(), descSets.data(), 0, nullptr);
|
|
||||||
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
|
|
||||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR
|
|
||||||
| VK_SHADER_STAGE_CALLABLE_BIT_KHR,
|
|
||||||
0, sizeof(PushConstantRay), &m_pcRay);
|
|
||||||
|
|
||||||
|
|
||||||
auto& regions = m_sbtWrapper.getRegions();
|
|
||||||
vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], size.width, size.height, 1);
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
|
||||||
#include "nvvk/sbtwrapper_vk.hpp"
|
|
||||||
#include "obj.hpp"
|
|
||||||
|
|
||||||
#include "shaders/host_device.h"
|
|
||||||
|
|
||||||
class Raytracer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void setup(const VkDevice& device, const VkPhysicalDevice& physicalDevice, nvvk::ResourceAllocator* allocator, uint32_t queueFamily);
|
|
||||||
void destroy();
|
|
||||||
|
|
||||||
auto objectToVkGeometryKHR(const ObjModel& model);
|
|
||||||
auto implicitToVkGeometryKHR(const ImplInst& implicitObj);
|
|
||||||
void createBottomLevelAS(std::vector<ObjModel>& models, ImplInst& implicitObj);
|
|
||||||
void createTopLevelAS(std::vector<ObjInstance>& instances, ImplInst& implicitObj);
|
|
||||||
void createRtDescriptorSet(const VkImageView& outputImage);
|
|
||||||
void updateRtDescriptorSet(const VkImageView& outputImage);
|
|
||||||
void createRtPipeline(VkDescriptorSetLayout& sceneDescLayout);
|
|
||||||
void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor, VkDescriptorSet& sceneDescSet, VkExtent2D& size, PushConstantRaster& sceneConstants);
|
|
||||||
|
|
||||||
private:
|
|
||||||
nvvk::ResourceAllocator* m_alloc{nullptr}; // Allocator for buffer, images, acceleration structures
|
|
||||||
VkPhysicalDevice m_physicalDevice;
|
|
||||||
VkDevice m_device;
|
|
||||||
int m_graphicsQueueIndex{0};
|
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
|
||||||
nvvk::SBTWrapper m_sbtWrapper;
|
|
||||||
|
|
||||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
|
||||||
VkDescriptorPool m_rtDescPool;
|
|
||||||
VkDescriptorSetLayout m_rtDescSetLayout;
|
|
||||||
VkDescriptorSet m_rtDescSet;
|
|
||||||
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
|
||||||
VkPipelineLayout m_rtPipelineLayout;
|
|
||||||
VkPipeline m_rtPipeline;
|
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
|
||||||
|
|
||||||
|
|
||||||
PushConstantRay m_pcRay{};
|
|
||||||
};
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRaster
|
|
||||||
{
|
|
||||||
PushConstantRaster pcRaster;
|
|
||||||
};
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
// Incoming
|
|
||||||
layout(location = 1) in vec3 i_worldPos;
|
|
||||||
layout(location = 2) in vec3 i_worldNrm;
|
|
||||||
layout(location = 3) in vec3 i_viewDir;
|
|
||||||
layout(location = 4) in vec2 i_texCoord;
|
|
||||||
// Outgoing
|
|
||||||
layout(location = 0) out vec4 o_color;
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
|
|
||||||
layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
layout(binding = eTextures) uniform sampler2D[] textureSamplers;
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Material of the object
|
|
||||||
ObjDesc objResource = objDesc.i[pcRaster.objIndex];
|
|
||||||
MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
|
|
||||||
int matIndex = matIndices.i[gl_PrimitiveID];
|
|
||||||
WaveFrontMaterial mat = materials.m[matIndex];
|
|
||||||
|
|
||||||
vec3 N = normalize(i_worldNrm);
|
|
||||||
|
|
||||||
// Vector toward light
|
|
||||||
vec3 LightDir;
|
|
||||||
float lightIntensity;
|
|
||||||
|
|
||||||
// Point light
|
|
||||||
if(pcRaster.lightType == 0)
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRaster.lightPosition - i_worldPos;
|
|
||||||
float lightDistance = length(lDir);
|
|
||||||
lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance);
|
|
||||||
LightDir = normalize(lDir);
|
|
||||||
}
|
|
||||||
else if(pcRaster.lightType == 1)
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRaster.lightPosition - i_worldPos;
|
|
||||||
float lightDistance = length(lDir);
|
|
||||||
lightIntensity = pcRaster.lightIntensity / (lightDistance * lightDistance);
|
|
||||||
LightDir = normalize(lDir);
|
|
||||||
float theta = dot(LightDir, normalize(-pcRaster.lightDirection));
|
|
||||||
float epsilon = pcRaster.lightSpotCutoff - pcRaster.lightSpotOuterCutoff;
|
|
||||||
float spotIntensity = clamp((theta - pcRaster.lightSpotOuterCutoff) / epsilon, 0.0, 1.0);
|
|
||||||
lightIntensity *= spotIntensity;
|
|
||||||
}
|
|
||||||
else // Directional light
|
|
||||||
{
|
|
||||||
LightDir = normalize(-pcRaster.lightDirection);
|
|
||||||
lightIntensity = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Diffuse
|
|
||||||
vec3 diffuse = computeDiffuse(mat, LightDir, N);
|
|
||||||
|
|
||||||
if(mat.textureId >= 0)
|
|
||||||
{
|
|
||||||
int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
|
|
||||||
uint txtId = txtOffset + mat.textureId;
|
|
||||||
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
|
|
||||||
diffuse *= diffuseTxt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Specular
|
|
||||||
vec3 specular = computeSpecular(mat, i_viewDir, LightDir, N);
|
|
||||||
|
|
||||||
// Result
|
|
||||||
o_color = vec4(lightIntensity * (diffuse + specular), 1);
|
|
||||||
}
|
|
||||||
|
|
@ -1,126 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef COMMON_HOST_DEVICE
|
|
||||||
#define COMMON_HOST_DEVICE
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
// GLSL Type
|
|
||||||
using vec2 = glm::vec2;
|
|
||||||
using vec3 = glm::vec3;
|
|
||||||
using vec4 = glm::vec4;
|
|
||||||
using mat4 = glm::mat4;
|
|
||||||
using uint = unsigned int;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
|
|
||||||
#define START_BINDING(a) enum a {
|
|
||||||
#define END_BINDING() }
|
|
||||||
#else
|
|
||||||
#define START_BINDING(a) const uint
|
|
||||||
#define END_BINDING()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
START_BINDING(SceneBindings)
|
|
||||||
eGlobals = 0, // Global uniform containing camera matrices
|
|
||||||
eObjDescs = 1, // Access to the object descriptions
|
|
||||||
eTextures = 2, // Access to textures
|
|
||||||
eImplicits = 3 // Implicit objects
|
|
||||||
END_BINDING();
|
|
||||||
|
|
||||||
START_BINDING(RtxBindings)
|
|
||||||
eTlas = 0, // Top-level acceleration structure
|
|
||||||
eOutImage = 1 // Ray tracer output image
|
|
||||||
END_BINDING();
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
// Information of a obj model when referenced in a shader
|
|
||||||
struct ObjDesc
|
|
||||||
{
|
|
||||||
int txtOffset; // Texture index offset in the array of textures
|
|
||||||
uint64_t vertexAddress; // Address of the Vertex buffer
|
|
||||||
uint64_t indexAddress; // Address of the index buffer
|
|
||||||
uint64_t materialAddress; // Address of the material buffer
|
|
||||||
uint64_t materialIndexAddress; // Address of the triangle material index buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
// Uniform buffer set at each frame
|
|
||||||
struct GlobalUniforms
|
|
||||||
{
|
|
||||||
mat4 viewProj; // Camera view * projection
|
|
||||||
mat4 viewInverse; // Camera inverse view matrix
|
|
||||||
mat4 projInverse; // Camera inverse projection matrix
|
|
||||||
};
|
|
||||||
|
|
||||||
// Push constant structure for the raster
|
|
||||||
struct PushConstantRaster
|
|
||||||
{
|
|
||||||
mat4 modelMatrix; // matrix of the instance
|
|
||||||
vec3 lightPosition;
|
|
||||||
uint objIndex;
|
|
||||||
vec3 lightDirection;
|
|
||||||
float lightSpotCutoff;
|
|
||||||
float lightSpotOuterCutoff;
|
|
||||||
float lightIntensity;
|
|
||||||
int lightType;
|
|
||||||
int frame;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Push constant structure for the ray tracer
|
|
||||||
struct PushConstantRay
|
|
||||||
{
|
|
||||||
vec4 clearColor;
|
|
||||||
vec3 lightPosition;
|
|
||||||
uint objIndex;
|
|
||||||
vec3 lightDirection;
|
|
||||||
float lightSpotCutoff;
|
|
||||||
float lightSpotOuterCutoff;
|
|
||||||
float lightIntensity;
|
|
||||||
int lightType;
|
|
||||||
int frame;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
|
|
||||||
{
|
|
||||||
vec3 pos;
|
|
||||||
vec3 nrm;
|
|
||||||
vec3 color;
|
|
||||||
vec2 texCoord;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
|
|
||||||
{
|
|
||||||
vec3 ambient;
|
|
||||||
vec3 diffuse;
|
|
||||||
vec3 specular;
|
|
||||||
vec3 transmittance;
|
|
||||||
vec3 emission;
|
|
||||||
float shininess;
|
|
||||||
float ior; // index of refraction
|
|
||||||
float dissolve; // 1 == opaque; 0 == fully transparent
|
|
||||||
int illum; // illumination model (see http://www.fileformat.info/format/material/)
|
|
||||||
int textureId;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460 core
|
|
||||||
#extension GL_EXT_ray_tracing : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "host_device.h"
|
|
||||||
|
|
||||||
layout(location = 3) callableDataInEXT rayLight cLight;
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay
|
|
||||||
{
|
|
||||||
PushConstantRay pcRay;
|
|
||||||
};
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
cLight.outLightDistance = 10000000;
|
|
||||||
cLight.outIntensity = 1.0;
|
|
||||||
cLight.outLightDir = normalize(-pcRay.lightDirection);
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460 core
|
|
||||||
#extension GL_EXT_ray_tracing : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "host_device.h"
|
|
||||||
|
|
||||||
layout(location = 3) callableDataInEXT rayLight cLight;
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay
|
|
||||||
{
|
|
||||||
PushConstantRay pcRay;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
|
|
||||||
cLight.outLightDistance = length(lDir);
|
|
||||||
cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance);
|
|
||||||
cLight.outLightDir = normalize(lDir);
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460 core
|
|
||||||
#extension GL_EXT_ray_tracing : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "host_device.h"
|
|
||||||
|
|
||||||
layout(location = 3) callableDataInEXT rayLight cLight;
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay
|
|
||||||
{
|
|
||||||
PushConstantRay pcRay;
|
|
||||||
};
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
|
|
||||||
cLight.outLightDistance = length(lDir);
|
|
||||||
cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance);
|
|
||||||
cLight.outLightDir = normalize(lDir);
|
|
||||||
float theta = dot(cLight.outLightDir, normalize(-pcRay.lightDirection));
|
|
||||||
float epsilon = pcRay.lightSpotCutoff - pcRay.lightSpotOuterCutoff;
|
|
||||||
float spotIntensity = clamp((theta - pcRay.lightSpotOuterCutoff) / epsilon, 0.0, 1.0);
|
|
||||||
cLight.outIntensity *= spotIntensity;
|
|
||||||
}
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(location = 0) out vec2 outUV;
|
|
||||||
|
|
||||||
|
|
||||||
out gl_PerVertex
|
|
||||||
{
|
|
||||||
vec4 gl_Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
|
||||||
gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(location = 0) in vec2 outUV;
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform sampler2D noisyTxt;
|
|
||||||
|
|
||||||
layout(push_constant) uniform shaderInformation
|
|
||||||
{
|
|
||||||
float aspectRatio;
|
|
||||||
}
|
|
||||||
pushc;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec2 uv = outUV;
|
|
||||||
float gamma = 1. / 2.2;
|
|
||||||
fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma));
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Generate a random unsigned int from two unsigned int values, using 16 pairs
|
|
||||||
// of rounds of the Tiny Encryption Algorithm. See Zafar, Olano, and Curtis,
|
|
||||||
// "GPU Random Numbers via the Tiny Encryption Algorithm"
|
|
||||||
uint tea(uint val0, uint val1)
|
|
||||||
{
|
|
||||||
uint v0 = val0;
|
|
||||||
uint v1 = val1;
|
|
||||||
uint s0 = 0;
|
|
||||||
|
|
||||||
for(uint n = 0; n < 16; n++)
|
|
||||||
{
|
|
||||||
s0 += 0x9e3779b9;
|
|
||||||
v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4);
|
|
||||||
v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a random unsigned int in [0, 2^24) given the previous RNG state
|
|
||||||
// using the Numerical Recipes linear congruential generator
|
|
||||||
uint lcg(inout uint prev)
|
|
||||||
{
|
|
||||||
uint LCG_A = 1664525u;
|
|
||||||
uint LCG_C = 1013904223u;
|
|
||||||
prev = (LCG_A * prev + LCG_C);
|
|
||||||
return prev & 0x00FFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a random float in [0, 1) given the previous RNG state
|
|
||||||
float rnd(inout uint prev)
|
|
||||||
{
|
|
||||||
return (float(lcg(prev)) / float(0x01000000));
|
|
||||||
}
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitValue;
|
|
||||||
uint seed;
|
|
||||||
int depth;
|
|
||||||
vec3 attenuation;
|
|
||||||
int done;
|
|
||||||
vec3 rayOrigin;
|
|
||||||
vec3 rayDir;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct rayLight
|
|
||||||
{
|
|
||||||
vec3 inHitPosition;
|
|
||||||
float outLightDistance;
|
|
||||||
vec3 outLightDir;
|
|
||||||
float outIntensity;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Implicit
|
|
||||||
{
|
|
||||||
vec3 minimum;
|
|
||||||
vec3 maximum;
|
|
||||||
int objType;
|
|
||||||
int matId;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Sphere
|
|
||||||
{
|
|
||||||
vec3 center;
|
|
||||||
float radius;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Aabb
|
|
||||||
{
|
|
||||||
vec3 minimum;
|
|
||||||
vec3 maximum;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define KIND_SPHERE 0
|
|
||||||
#define KIND_CUBE 1
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "random.glsl"
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Object of this instance
|
|
||||||
ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
|
|
||||||
MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
|
|
||||||
int matIdx = matIndices.i[gl_PrimitiveID];
|
|
||||||
WaveFrontMaterial mat = materials.m[matIdx];
|
|
||||||
|
|
||||||
if(mat.illum != 4)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint seed = prd.seed; // We don't want to modify the PRD
|
|
||||||
if(mat.dissolve == 0.0)
|
|
||||||
ignoreIntersectionEXT;
|
|
||||||
else if(rnd(seed) > mat.dissolve)
|
|
||||||
ignoreIntersectionEXT;
|
|
||||||
}
|
|
||||||
|
|
@ -1,176 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
hitAttributeEXT vec2 attribs;
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
|
||||||
layout(location = 1) rayPayloadEXT bool isShadowed;
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
|
|
||||||
layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[];
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
layout(location = 3) callableDataEXT rayLight cLight;
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Object data
|
|
||||||
ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
|
|
||||||
MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
Indices indices = Indices(objResource.indexAddress);
|
|
||||||
Vertices vertices = Vertices(objResource.vertexAddress);
|
|
||||||
|
|
||||||
// Indices of the triangle
|
|
||||||
ivec3 ind = indices.i[gl_PrimitiveID];
|
|
||||||
|
|
||||||
// Vertex of the triangle
|
|
||||||
Vertex v0 = vertices.v[ind.x];
|
|
||||||
Vertex v1 = vertices.v[ind.y];
|
|
||||||
Vertex v2 = vertices.v[ind.z];
|
|
||||||
|
|
||||||
const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
|
|
||||||
|
|
||||||
// Computing the normal at hit position
|
|
||||||
vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
|
|
||||||
// Transforming the normal to world space
|
|
||||||
normal = normalize(vec3(normal * gl_WorldToObjectEXT));
|
|
||||||
|
|
||||||
// Computing the coordinates of the hit position
|
|
||||||
vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
|
|
||||||
// Transforming the position to world space
|
|
||||||
worldPos = vec3(gl_ObjectToWorldEXT * vec4(worldPos, 1.0));
|
|
||||||
|
|
||||||
cLight.inHitPosition = worldPos;
|
|
||||||
//#define DONT_USE_CALLABLE
|
|
||||||
#if defined(DONT_USE_CALLABLE)
|
|
||||||
// Point light
|
|
||||||
if(pcRay.lightType == 0)
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
|
|
||||||
float lightDistance = length(lDir);
|
|
||||||
cLight.outIntensity = pcRay.lightIntensity / (lightDistance * lightDistance);
|
|
||||||
cLight.outLightDir = normalize(lDir);
|
|
||||||
cLight.outLightDistance = lightDistance;
|
|
||||||
}
|
|
||||||
else if(pcRay.lightType == 1)
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRay.lightPosition - cLight.inHitPosition;
|
|
||||||
cLight.outLightDistance = length(lDir);
|
|
||||||
cLight.outIntensity = pcRay.lightIntensity / (cLight.outLightDistance * cLight.outLightDistance);
|
|
||||||
cLight.outLightDir = normalize(lDir);
|
|
||||||
float theta = dot(cLight.outLightDir, normalize(-pcRay.lightDirection));
|
|
||||||
float epsilon = pcRay.lightSpotCutoff - pcRay.lightSpotOuterCutoff;
|
|
||||||
float spotIntensity = clamp((theta - pcRay.lightSpotOuterCutoff) / epsilon, 0.0, 1.0);
|
|
||||||
cLight.outIntensity *= spotIntensity;
|
|
||||||
}
|
|
||||||
else // Directional light
|
|
||||||
{
|
|
||||||
cLight.outLightDir = normalize(-pcRay.lightDirection);
|
|
||||||
cLight.outIntensity = 1.0;
|
|
||||||
cLight.outLightDistance = 10000000;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
executeCallableEXT(pcRay.lightType, 3);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Material of the object
|
|
||||||
int matIdx = matIndices.i[gl_PrimitiveID];
|
|
||||||
WaveFrontMaterial mat = materials.m[matIdx];
|
|
||||||
|
|
||||||
|
|
||||||
// Diffuse
|
|
||||||
vec3 diffuse = computeDiffuse(mat, cLight.outLightDir, normal);
|
|
||||||
if(mat.textureId >= 0)
|
|
||||||
{
|
|
||||||
uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
|
|
||||||
vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
|
|
||||||
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 specular = vec3(0);
|
|
||||||
float attenuation = 1;
|
|
||||||
|
|
||||||
// Tracing shadow ray only if the light is visible from the surface
|
|
||||||
if(dot(normal, cLight.outLightDir) > 0)
|
|
||||||
{
|
|
||||||
float tMin = 0.001;
|
|
||||||
float tMax = cLight.outLightDistance;
|
|
||||||
vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
|
|
||||||
vec3 rayDir = cLight.outLightDir;
|
|
||||||
uint flags = gl_RayFlagsSkipClosestHitShaderEXT;
|
|
||||||
isShadowed = true;
|
|
||||||
traceRayEXT(topLevelAS, // acceleration structure
|
|
||||||
flags, // rayFlags
|
|
||||||
0xFF, // cullMask
|
|
||||||
0, // sbtRecordOffset
|
|
||||||
0, // sbtRecordStride
|
|
||||||
1, // missIndex
|
|
||||||
origin, // ray origin
|
|
||||||
tMin, // ray min range
|
|
||||||
rayDir, // ray direction
|
|
||||||
tMax, // ray max range
|
|
||||||
1 // payload (location = 1)
|
|
||||||
);
|
|
||||||
|
|
||||||
if(isShadowed)
|
|
||||||
{
|
|
||||||
attenuation = 0.3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Specular
|
|
||||||
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, cLight.outLightDir, normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reflection
|
|
||||||
if(mat.illum == 3)
|
|
||||||
{
|
|
||||||
vec3 origin = worldPos;
|
|
||||||
vec3 rayDir = reflect(gl_WorldRayDirectionEXT, normal);
|
|
||||||
prd.attenuation *= mat.specular;
|
|
||||||
prd.done = 0;
|
|
||||||
prd.rayOrigin = origin;
|
|
||||||
prd.rayDir = rayDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
prd.hitValue = vec3(cLight.outIntensity * attenuation * (diffuse + specular));
|
|
||||||
}
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "random.glsl"
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
layout(location = 0) rayPayloadEXT hitPayload prd;
|
|
||||||
|
|
||||||
layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
|
|
||||||
layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image;
|
|
||||||
layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; };
|
|
||||||
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
const int NBSAMPLES = 5;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Initialize the random number
|
|
||||||
uint seed = tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, pcRay.frame * NBSAMPLES);
|
|
||||||
prd.seed = seed;
|
|
||||||
|
|
||||||
vec3 hitValues = vec3(0);
|
|
||||||
|
|
||||||
for(int smpl = 0; smpl < NBSAMPLES; smpl++)
|
|
||||||
{
|
|
||||||
|
|
||||||
float r1 = rnd(seed);
|
|
||||||
float r2 = rnd(seed);
|
|
||||||
// Subpixel jitter: send the ray through a different position inside the pixel
|
|
||||||
// each time, to provide antialiasing.
|
|
||||||
vec2 subpixel_jitter = pcRay.frame == 0 ? vec2(0.5f, 0.5f) : vec2(r1, r2);
|
|
||||||
|
|
||||||
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + subpixel_jitter;
|
|
||||||
|
|
||||||
|
|
||||||
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
|
|
||||||
vec2 d = inUV * 2.0 - 1.0;
|
|
||||||
|
|
||||||
vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1);
|
|
||||||
vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1);
|
|
||||||
vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0);
|
|
||||||
|
|
||||||
uint rayFlags = gl_RayFlagsNoneEXT;
|
|
||||||
float tMin = 0.001;
|
|
||||||
float tMax = 10000.0;
|
|
||||||
|
|
||||||
prd.done = 1;
|
|
||||||
prd.rayOrigin = origin.xyz;
|
|
||||||
prd.rayDir = direction.xyz;
|
|
||||||
prd.depth = 0;
|
|
||||||
prd.hitValue = vec3(0);
|
|
||||||
prd.attenuation = vec3(1.f, 1.f, 1.f);
|
|
||||||
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
traceRayEXT(topLevelAS, // acceleration structure
|
|
||||||
rayFlags, // rayFlags
|
|
||||||
0xFF, // cullMask
|
|
||||||
0, // sbtRecordOffset
|
|
||||||
0, // sbtRecordStride
|
|
||||||
0, // missIndex
|
|
||||||
origin.xyz, // ray origin
|
|
||||||
tMin, // ray min range
|
|
||||||
direction.xyz, // ray direction
|
|
||||||
tMax, // ray max range
|
|
||||||
0 // payload (location = 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
hitValues += prd.hitValue * prd.attenuation;
|
|
||||||
|
|
||||||
prd.depth++;
|
|
||||||
if(prd.done == 1 || prd.depth >= 10)
|
|
||||||
break;
|
|
||||||
|
|
||||||
origin.xyz = prd.rayOrigin;
|
|
||||||
direction.xyz = prd.rayDir;
|
|
||||||
prd.done = 1; // Will stop if a reflective material isn't hit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prd.hitValue = hitValues / NBSAMPLES;
|
|
||||||
|
|
||||||
if(pcRay.frame == 0)
|
|
||||||
{
|
|
||||||
// First frame, replace the value in the buffer
|
|
||||||
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.f));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Do accumulation over time
|
|
||||||
float a = 1.0f / float(pcRay.frame + 1);
|
|
||||||
vec3 old_color = imageLoad(image, ivec2(gl_LaunchIDEXT.xy)).xyz;
|
|
||||||
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(mix(old_color, prd.hitValue, a), 1.f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
hitAttributeEXT vec3 HitAttribute;
|
|
||||||
|
|
||||||
layout(set = 1, binding = eImplicits, scalar) buffer allImpl_
|
|
||||||
{
|
|
||||||
Implicit i[];
|
|
||||||
}
|
|
||||||
allImplicits;
|
|
||||||
|
|
||||||
|
|
||||||
struct Ray
|
|
||||||
{
|
|
||||||
vec3 origin;
|
|
||||||
vec3 direction;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ray-Sphere intersection
|
|
||||||
// http://viclw17.github.io/2018/07/16/raytracing-ray-sphere-intersection/
|
|
||||||
float hitSphere(const Sphere s, const Ray r)
|
|
||||||
{
|
|
||||||
vec3 oc = r.origin - s.center;
|
|
||||||
float a = dot(r.direction, r.direction);
|
|
||||||
float b = 2.0 * dot(oc, r.direction);
|
|
||||||
float c = dot(oc, oc) - s.radius * s.radius;
|
|
||||||
float discriminant = b * b - 4 * a * c;
|
|
||||||
if(discriminant < 0)
|
|
||||||
{
|
|
||||||
return -1.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (-b - sqrt(discriminant)) / (2.0 * a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ray-AABB intersection
|
|
||||||
float hitAabb(const Aabb aabb, const Ray r)
|
|
||||||
{
|
|
||||||
vec3 invDir = 1.0 / r.direction;
|
|
||||||
vec3 tbot = invDir * (aabb.minimum - r.origin);
|
|
||||||
vec3 ttop = invDir * (aabb.maximum - r.origin);
|
|
||||||
vec3 tmin = min(ttop, tbot);
|
|
||||||
vec3 tmax = max(ttop, tbot);
|
|
||||||
float t0 = max(tmin.x, max(tmin.y, tmin.z));
|
|
||||||
float t1 = min(tmax.x, min(tmax.y, tmax.z));
|
|
||||||
return t1 > max(t0, 0.0) ? t0 : -1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
|
|
||||||
Ray ray;
|
|
||||||
ray.origin = gl_WorldRayOriginEXT;
|
|
||||||
ray.direction = gl_WorldRayDirectionEXT;
|
|
||||||
|
|
||||||
// Sphere data
|
|
||||||
Implicit impl = allImplicits.i[gl_PrimitiveID];
|
|
||||||
|
|
||||||
float tHit = -1;
|
|
||||||
int hitKind = impl.objType;
|
|
||||||
if(hitKind == KIND_SPHERE)
|
|
||||||
{
|
|
||||||
Sphere sphere;
|
|
||||||
sphere.center = (impl.maximum + impl.minimum) * 0.5;
|
|
||||||
sphere.radius = impl.maximum.y - sphere.center.y;
|
|
||||||
// Sphere intersection
|
|
||||||
tHit = hitSphere(sphere, ray);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// AABB intersection
|
|
||||||
Aabb aabb;
|
|
||||||
aabb.minimum = impl.minimum;
|
|
||||||
aabb.maximum = impl.maximum;
|
|
||||||
tHit = hitAabb(aabb, ray);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Report hit point
|
|
||||||
if(tHit > 0)
|
|
||||||
reportIntersectionEXT(tHit, hitKind);
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay
|
|
||||||
{
|
|
||||||
PushConstantRay pcRay;
|
|
||||||
};
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
prd.hitValue = pcRay.clearColor.xyz * 0.8;
|
|
||||||
}
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "random.glsl"
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
layout(set = 1, binding = eImplicits, scalar) buffer allImplicits_ {Implicit i[];} allImplicits;
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Material of the object
|
|
||||||
Implicit impl = allImplicits.i[gl_PrimitiveID];
|
|
||||||
|
|
||||||
ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
|
|
||||||
WaveFrontMaterial mat = materials.m[impl.matId];
|
|
||||||
|
|
||||||
if(mat.illum != 4)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint seed = prd.seed; // We don't want to modify the PRD
|
|
||||||
if(mat.dissolve == 0.0)
|
|
||||||
ignoreIntersectionEXT;
|
|
||||||
else if(rnd(seed) > mat.dissolve)
|
|
||||||
ignoreIntersectionEXT;
|
|
||||||
}
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
hitAttributeEXT vec2 attribs;
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
|
||||||
layout(location = 1) rayPayloadEXT bool isShadowed;
|
|
||||||
|
|
||||||
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
|
|
||||||
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
layout(set = 1, binding = eImplicits, scalar) buffer allImplicits_ {Implicit i[];} allImplicits;
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
layout(location = 3) callableDataEXT rayLight cLight;
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec3 worldPos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
|
|
||||||
|
|
||||||
Implicit impl = allImplicits.i[gl_PrimitiveID];
|
|
||||||
|
|
||||||
// Computing the normal at hit position
|
|
||||||
vec3 normal;
|
|
||||||
if(gl_HitKindEXT == KIND_SPHERE)
|
|
||||||
{
|
|
||||||
vec3 center = (impl.maximum + impl.minimum) * 0.5;
|
|
||||||
normal = normalize(worldPos - center);
|
|
||||||
}
|
|
||||||
else if(gl_HitKindEXT == KIND_CUBE)
|
|
||||||
{
|
|
||||||
const float epsilon = 0.00001;
|
|
||||||
if(abs(impl.maximum.x - worldPos.x) < epsilon)
|
|
||||||
normal = vec3(1, 0, 0);
|
|
||||||
else if(abs(impl.maximum.y - worldPos.y) < epsilon)
|
|
||||||
normal = vec3(0, 1, 0);
|
|
||||||
else if(abs(impl.maximum.z - worldPos.z) < epsilon)
|
|
||||||
normal = vec3(0, 0, 1);
|
|
||||||
else if(abs(impl.minimum.x - worldPos.x) < epsilon)
|
|
||||||
normal = vec3(-1, 0, 0);
|
|
||||||
else if(abs(impl.minimum.y - worldPos.y) < epsilon)
|
|
||||||
normal = vec3(0, -1, 0);
|
|
||||||
else if(abs(impl.minimum.z - worldPos.z) < epsilon)
|
|
||||||
normal = vec3(0, 0, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cLight.inHitPosition = worldPos;
|
|
||||||
executeCallableEXT(pcRay.lightType, 3);
|
|
||||||
|
|
||||||
// Material of the object
|
|
||||||
ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
WaveFrontMaterial mat = materials.m[impl.matId];
|
|
||||||
|
|
||||||
|
|
||||||
// Diffuse
|
|
||||||
vec3 diffuse = computeDiffuse(mat, cLight.outLightDir, normal);
|
|
||||||
|
|
||||||
vec3 specular = vec3(0);
|
|
||||||
float attenuation = 1;
|
|
||||||
|
|
||||||
// Tracing shadow ray only if the light is visible from the surface
|
|
||||||
if(dot(normal, cLight.outLightDir) > 0)
|
|
||||||
{
|
|
||||||
float tMin = 0.001;
|
|
||||||
float tMax = cLight.outLightDistance;
|
|
||||||
vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
|
|
||||||
vec3 rayDir = cLight.outLightDir;
|
|
||||||
uint flags = gl_RayFlagsSkipClosestHitShaderEXT;
|
|
||||||
isShadowed = true;
|
|
||||||
traceRayEXT(topLevelAS, // acceleration structure
|
|
||||||
flags, // rayFlags
|
|
||||||
0xFF, // cullMask
|
|
||||||
0, // sbtRecordOffset
|
|
||||||
0, // sbtRecordStride
|
|
||||||
1, // missIndex
|
|
||||||
origin, // ray origin
|
|
||||||
tMin, // ray min range
|
|
||||||
rayDir, // ray direction
|
|
||||||
tMax, // ray max range
|
|
||||||
1 // payload (location = 1)
|
|
||||||
);
|
|
||||||
|
|
||||||
if(isShadowed)
|
|
||||||
{
|
|
||||||
attenuation = 0.3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Specular
|
|
||||||
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, cLight.outLightDir, normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reflection
|
|
||||||
if(mat.illum == 3)
|
|
||||||
{
|
|
||||||
vec3 origin = worldPos;
|
|
||||||
vec3 rayDir = reflect(gl_WorldRayDirectionEXT, normal);
|
|
||||||
prd.attenuation *= mat.specular;
|
|
||||||
prd.done = 0;
|
|
||||||
prd.rayOrigin = origin;
|
|
||||||
prd.rayDir = rayDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
prd.hitValue = vec3(cLight.outIntensity * attenuation * (diffuse + specular));
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
layout(location = 1) rayPayloadInEXT bool isShadowed;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
isShadowed = false;
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
layout(binding = 0) uniform _GlobalUniforms
|
|
||||||
{
|
|
||||||
GlobalUniforms uni;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRaster
|
|
||||||
{
|
|
||||||
PushConstantRaster pcRaster;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 i_position;
|
|
||||||
layout(location = 1) in vec3 i_normal;
|
|
||||||
layout(location = 2) in vec3 i_color;
|
|
||||||
layout(location = 3) in vec2 i_texCoord;
|
|
||||||
|
|
||||||
|
|
||||||
layout(location = 1) out vec3 o_worldPos;
|
|
||||||
layout(location = 2) out vec3 o_worldNrm;
|
|
||||||
layout(location = 3) out vec3 o_viewDir;
|
|
||||||
layout(location = 4) out vec2 o_texCoord;
|
|
||||||
|
|
||||||
out gl_PerVertex
|
|
||||||
{
|
|
||||||
vec4 gl_Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
|
|
||||||
|
|
||||||
o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
|
|
||||||
o_viewDir = vec3(o_worldPos - origin);
|
|
||||||
o_texCoord = i_texCoord;
|
|
||||||
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
|
|
||||||
|
|
||||||
gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "host_device.h"
|
|
||||||
|
|
||||||
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
|
|
||||||
{
|
|
||||||
// Lambertian
|
|
||||||
float dotNL = max(dot(normal, lightDir), 0.0);
|
|
||||||
vec3 c = mat.diffuse * dotNL;
|
|
||||||
if(mat.illum >= 1)
|
|
||||||
c += mat.ambient;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal)
|
|
||||||
{
|
|
||||||
if(mat.illum < 2)
|
|
||||||
return vec3(0);
|
|
||||||
|
|
||||||
// Compute specular only if not in shadow
|
|
||||||
const float kPi = 3.14159265;
|
|
||||||
const float kShininess = max(mat.shininess, 4.0);
|
|
||||||
|
|
||||||
// Specular
|
|
||||||
const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi);
|
|
||||||
vec3 V = normalize(-viewDir);
|
|
||||||
vec3 R = reflect(-lightDir, normal);
|
|
||||||
float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess);
|
|
||||||
|
|
||||||
return vec3(mat.specular * specular);
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
#*****************************************************************************
|
|
||||||
# Copyright 2020 NVIDIA Corporation. All rights reserved.
|
|
||||||
#*****************************************************************************
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Project setting
|
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
|
||||||
message(STATUS "-------------------------------")
|
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# C++ target and defines
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
add_executable(${PROJNAME})
|
|
||||||
_add_project_definitions(${PROJNAME})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Source files for this project
|
|
||||||
#
|
|
||||||
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
|
|
||||||
file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
|
|
||||||
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
|
||||||
include_directories(${TUTO_KHR_DIR}/common)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# GLSL to SPIR-V custom build
|
|
||||||
compile_glsl_directory(
|
|
||||||
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
|
|
||||||
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
|
|
||||||
VULKAN_TARGET "vulkan1.2"
|
|
||||||
DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sources
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sub-folders in Visual Studio
|
|
||||||
#
|
|
||||||
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
|
|
||||||
source_group("Sources" FILES ${SOURCE_FILES})
|
|
||||||
source_group("Headers" FILES ${HEADER_FILES})
|
|
||||||
source_group("Shader Sources" FILES ${GLSL_SOURCES})
|
|
||||||
source_group("Shader Headers" FILES ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Linkage
|
|
||||||
#
|
|
||||||
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core)
|
|
||||||
|
|
||||||
foreach(DEBUGLIB ${LIBRARIES_DEBUG})
|
|
||||||
target_link_libraries(${PROJNAME} debug ${DEBUGLIB})
|
|
||||||
endforeach(DEBUGLIB)
|
|
||||||
|
|
||||||
foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
|
|
||||||
target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
|
|
||||||
endforeach(RELEASELIB)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# copies binaries that need to be put next to the exe files (ZLib, etc.)
|
|
||||||
#
|
|
||||||
_finalize_target( ${PROJNAME} )
|
|
||||||
|
|
||||||
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
# NVIDIA Vulkan Ray Tracing Tutorial
|
|
||||||
|
|
||||||
This sample is a simple OBJ viewer in Vulkan, without any ray tracing functionality.
|
|
||||||
It is the starting point of the [ray tracing tutorial](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html),
|
|
||||||
the source of the application where ray tracing will be added.
|
|
||||||

|
|
||||||
|
|
||||||
Before starting the tutorial and adding what is necessary to enable ray tracing, here is a brief description of how this basic example was created.
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
* main.cpp : creates a Vulkan context, call for loading OBJ files, drawing loop
|
|
||||||
* hello_vulkan.[cpp|h]: example class that loads and store OBJ in Vulkan buffers, load textures, creates pipelines and render the scene
|
|
||||||
* [nvvk](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk): library of independent Vulkan helpers.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The following describes the function calls in main(). The helpers will not be described here, but following the link should give more details on how they work.
|
|
||||||
|
|
||||||
### Window and Vulkan Setup
|
|
||||||
|
|
||||||
* Creates a window using [GLFW](https://www.glfw.org/).
|
|
||||||
* Creates a Vulkan context using the [`nvvk::Context`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#context_vkhpp)
|
|
||||||
helper. The result is a `VkInstance`, `VkDevice`, `VkPhisicalDevice`, the queues and the extensions initialized.
|
|
||||||
* The window was created, but not the surface to draw in this window. This is done using the information from `VkInstance` and `GLFWwindow`. The
|
|
||||||
`VkSurfaceKHR` will be used to find the proper queue.
|
|
||||||
|
|
||||||
### Sample Setup
|
|
||||||
|
|
||||||
* Hello vulkan setup:
|
|
||||||
* [base] Keep a copy of `VkInstance`, `VkDevice`, `VkPhysicalDevice` and graphics Queue Index.
|
|
||||||
* [base] Create a command pool
|
|
||||||
* Initialize the [Vulkan resource allocator](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#resourceallocator_vkhpp) (nvvk::alloc).
|
|
||||||
* Create Swapchain [base]:
|
|
||||||
* Using the base class method and the help of [`nvvk::Swapchain`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#swapchain_vkhpp),
|
|
||||||
initialize the swapchain for rendering onto the surface.
|
|
||||||
* Finds the surface color and depth format.
|
|
||||||
* Create *n* `VkFence` for synchronization.
|
|
||||||
* Create depth buffer [base]: depth buffer image with the format query in the swapchain
|
|
||||||
* Create render pass [base]:
|
|
||||||
* Simple render pass, with two attachments: color and depth
|
|
||||||
* Using swapchain color and depth format.
|
|
||||||
* Create frame buffers [base]:
|
|
||||||
* Create *n images* of the number returned by the swapchain
|
|
||||||
* Create as many frame buffers and attach the images
|
|
||||||
* Initialize GUI [base]: we are using [Dear ImGui](https://github.com/ocornut/imgui) and
|
|
||||||
this is doing the initialization for Vulkan.
|
|
||||||
* Loading [Wavefront .obj file](https://en.wikipedia.org/wiki/Wavefront_.obj_file):
|
|
||||||
* This is a very simple format, but it allows us to make manual modifications in the file, to load several .obj files and to combine them to obtain a more complex scene. We can also easily create several instances of the loaded objects.
|
|
||||||
* Loading the .obj is done through the [ObjLoader](https://github.com/nvpro-samples/vk_raytracing_tutorial_KHR/blob/3e399adf0a3e991795fbdf91e0e6c23b9f492bb8/common/obj_loader.cpp#L26) which is using [tinyobjloader](https://github.com/tinyobjloader/tinyobjloader).
|
|
||||||
* All vertices are in the form of: position, normal, color, texture coordinates
|
|
||||||
* Every 3 vertex indices are creating a triangle.
|
|
||||||
* Every triangle has an index of the material it is using.
|
|
||||||
* There are M materials and T textures.
|
|
||||||
* We allocate buffers and staging the transfer to the GPU using our resource allocator.
|
|
||||||
* We create an instance of the loaded model.
|
|
||||||
* :warning: We keep the addresses of the created buffers and append this to a vector of `ObjDesc`, which allows easy access to the model information from a shader.
|
|
||||||
|
|
||||||
### Offscreen image & Graphic Pipeline
|
|
||||||
|
|
||||||
We have a swapchain and window frame buffers, but we will not render the scene directly to them. Instead, we will render to an RGBA32F image, and then render that image to a full screen triangle using a tone mapper. We could have rendered directly to one of the swapchain framebuffers and applied a tone mapper, but this separation will be very useful for rendering G-Buffers and doing something similar with ray tracing.
|
|
||||||
|
|
||||||
* Create offscreen render:
|
|
||||||
* Create a color and depth image, format are VK_FORMAT_R32G32B32A32_SFLOAT and best depth for the physical device using [`nvvk::findDepthFormat`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#renderpasses_vkhpp).
|
|
||||||
* Create a render pass to render using those images [`nvvk::createRenderPass`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#renderpasses_vkhpp).
|
|
||||||
* Create a frame buffer, to use as a target when rendering offline.
|
|
||||||
* Create descriptor set layout:
|
|
||||||
* Using the [`nvvk::DescriptorSetBindings`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#class-nvvkdescriptorsetbindings), describing the resources that will be used in the vertex and fragment shader.
|
|
||||||
* Create graphic pipeline:
|
|
||||||
* Using [`nvvk::GraphicsPipelineGeneratorCombined`](https://github.com/nvpro-samples/nvpro_core/tree/master/nvvk#class-nvvkgraphicspipelinegeneratorcombined)
|
|
||||||
* Load both vertex and fragment SpirV shaders
|
|
||||||
* Describe the vertex attributes: pos, nrm, color, uv
|
|
||||||
* Create uniform buffer:
|
|
||||||
* The uniform buffer is holding global scene information and is updated at each frame.
|
|
||||||
* The information in this sample consist of camera matrices and will be
|
|
||||||
updated in the drawing loop using `updateUniformBuffer()`.
|
|
||||||
* Create Obj description buffer:
|
|
||||||
* When loading .obj, we stored the addresses of the OBJ buffers.
|
|
||||||
* If we have loaded many .obj, the array will be as large as the number of obj loaded.
|
|
||||||
* Each instance has the index of the OBJ, therefore the information of the model will be easily retrievable in the shader.
|
|
||||||
* This function creates the buffer holding the vector of `ObjDesc`.
|
|
||||||
* Update descriptor set:
|
|
||||||
* The descriptor set has been created, but here we are writing the information, meaning all the buffers and textures we have created.
|
|
||||||
|
|
||||||
At this point, the OBJs are loaded and their information is uploaded to the GPU. The graphic pipeline and the information describing the resources are also created.
|
|
||||||
|
|
||||||
### Post Pipeline
|
|
||||||
|
|
||||||
We need to create a "post pipeline". This is specific to the raster of this sample. As mentioned before, we render in a full screen triangle, the result of the raster and apply a tonemapper. This step will be rendered directly into the framebuffer of the swapchain.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
* Create post descriptor:
|
|
||||||
* Adding the image input (result of rendering)
|
|
||||||
* Create post pipeline:
|
|
||||||
* Passtrough vertex shader (full screen triangle)
|
|
||||||
* Fragment tone-mapper shader
|
|
||||||
* Update post descriptor:
|
|
||||||
* Writing the image (RGB32F) address
|
|
||||||
|
|
||||||
At this point we are ready to start the rendering loop.
|
|
||||||
|
|
||||||
* Setup Glfw callback:
|
|
||||||
* Our base class has many functions to react on Glfw, such as change of window size, mouse and keyboard inputs.
|
|
||||||
* All callback functions are virtual, which allow to override the base functionality, but for most there isn't anything to do.
|
|
||||||
* Except for `onResize`, since we render to an intermediate image (RGB32F), this image will need to be re-created with the new size and the post pipeline will need the address of this image. Therefore, there is an overload of this function.
|
|
||||||
|
|
||||||
### Rendering Loop
|
|
||||||
|
|
||||||
* Render indefinitely until Glfw receive a close action
|
|
||||||
* Glfw pulling events
|
|
||||||
* Imgui new frame and rendering (not drawing)
|
|
||||||
* Prepare Frame
|
|
||||||
* This is part of the swapchain, we can have a double or triple buffer and
|
|
||||||
this call will be waiting (fence) to make sure that one swapchain frame buffer
|
|
||||||
is available.
|
|
||||||
* Get current frame
|
|
||||||
* Depending if we have a double or triple buffer, it will return: 0 or 1, or 0, 1 or 2.
|
|
||||||
* Resources in the base class exist in that amount: color images, frame buffer, command buffer, fence
|
|
||||||
* Get the command buffer for the current frame (better to re-use command buffers than creating new ones)
|
|
||||||
* Update the uniform buffer:
|
|
||||||
* Push the current camera matrices
|
|
||||||
|
|
||||||
#### Offscreen
|
|
||||||
|
|
||||||
* Start offscreen rendering pass
|
|
||||||
* We will be rendering (raster) in the RGBA32F image using the offscreen render pass and frame buffer.
|
|
||||||
* Rasterize
|
|
||||||
* This is rasterizing the entire scene, all instances of each object.
|
|
||||||
|
|
||||||
#### Final
|
|
||||||
|
|
||||||
Start another rendering, this time in the swapchain frame buffer
|
|
||||||
|
|
||||||
* Use the base class render pass
|
|
||||||
* Use the swapchain frame buffer
|
|
||||||
* Render a full-screen triangle with the raster image and tone-mapping it.
|
|
||||||
* Actually rendering Imgui in Vulkan
|
|
||||||
* Submit the frame for execution and display
|
|
||||||
|
|
||||||
### Clean up
|
|
||||||
|
|
||||||
The rest is clean up all allocations
|
|
||||||
|
|
@ -1,568 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include "obj_loader.h"
|
|
||||||
#include "stb_image.h"
|
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
|
||||||
#include "nvh/alignment.hpp"
|
|
||||||
#include "nvh/cameramanipulator.hpp"
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
#include "nvvk/images_vk.hpp"
|
|
||||||
#include "nvvk/pipeline_vk.hpp"
|
|
||||||
#include "nvvk/renderpasses_vk.hpp"
|
|
||||||
#include "nvvk/shaders_vk.hpp"
|
|
||||||
#include "nvvk/buffers_vk.hpp"
|
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Keep the handle on the device
|
|
||||||
// Initialize the tool to do all our allocations: buffers, images
|
|
||||||
//
|
|
||||||
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
|
||||||
{
|
|
||||||
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
|
||||||
m_alloc.init(instance, device, physicalDevice);
|
|
||||||
m_debug.setup(m_device);
|
|
||||||
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Called at each frame to update the camera matrix
|
|
||||||
//
|
|
||||||
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
|
||||||
{
|
|
||||||
// Prepare new UBO contents on host.
|
|
||||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
|
||||||
GlobalUniforms hostUBO = {};
|
|
||||||
const auto& view = CameraManip.getMatrix();
|
|
||||||
glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f);
|
|
||||||
proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
|
||||||
|
|
||||||
hostUBO.viewProj = proj * view;
|
|
||||||
hostUBO.viewInverse = glm::inverse(view);
|
|
||||||
hostUBO.projInverse = glm::inverse(proj);
|
|
||||||
|
|
||||||
// UBO on the device, and what stages access it.
|
|
||||||
VkBuffer deviceUBO = m_bGlobals.buffer;
|
|
||||||
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
|
||||||
|
|
||||||
// Ensure that the modified UBO is not visible to previous frames.
|
|
||||||
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
|
||||||
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
beforeBarrier.buffer = deviceUBO;
|
|
||||||
beforeBarrier.offset = 0;
|
|
||||||
beforeBarrier.size = sizeof(hostUBO);
|
|
||||||
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
|
||||||
nullptr, 1, &beforeBarrier, 0, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
|
||||||
// buffer so it is okay to deallocate when the function returns).
|
|
||||||
vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
|
|
||||||
|
|
||||||
// Making sure the updated UBO will be visible.
|
|
||||||
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
|
||||||
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
afterBarrier.buffer = deviceUBO;
|
|
||||||
afterBarrier.offset = 0;
|
|
||||||
afterBarrier.size = sizeof(hostUBO);
|
|
||||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
|
||||||
nullptr, 1, &afterBarrier, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Describing the layout pushed when rendering
|
|
||||||
//
|
|
||||||
void HelloVulkan::createDescriptorSetLayout()
|
|
||||||
{
|
|
||||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
|
||||||
|
|
||||||
// Camera matrices
|
|
||||||
m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
|
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
|
|
||||||
// Obj descriptions
|
|
||||||
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
|
||||||
// Textures
|
|
||||||
m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
|
|
||||||
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
|
||||||
|
|
||||||
|
|
||||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
|
||||||
m_descPool = m_descSetLayoutBind.createPool(m_device, 1);
|
|
||||||
m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Setting up the buffers in the descriptor set
|
|
||||||
//
|
|
||||||
void HelloVulkan::updateDescriptorSet()
|
|
||||||
{
|
|
||||||
std::vector<VkWriteDescriptorSet> writes;
|
|
||||||
|
|
||||||
// Camera matrices and scene description
|
|
||||||
VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
|
|
||||||
|
|
||||||
VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
|
|
||||||
|
|
||||||
// All texture samplers
|
|
||||||
std::vector<VkDescriptorImageInfo> diit;
|
|
||||||
for(auto& texture : m_textures)
|
|
||||||
{
|
|
||||||
diit.emplace_back(texture.descriptor);
|
|
||||||
}
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
|
|
||||||
|
|
||||||
// Writing the information
|
|
||||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating the pipeline layout
|
|
||||||
//
|
|
||||||
void HelloVulkan::createGraphicsPipeline()
|
|
||||||
{
|
|
||||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
|
|
||||||
|
|
||||||
// Creating the Pipeline Layout
|
|
||||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
||||||
createInfo.setLayoutCount = 1;
|
|
||||||
createInfo.pSetLayouts = &m_descSetLayout;
|
|
||||||
createInfo.pushConstantRangeCount = 1;
|
|
||||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
|
||||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
|
||||||
|
|
||||||
|
|
||||||
// Creating the Pipeline
|
|
||||||
std::vector<std::string> paths = defaultSearchPaths;
|
|
||||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
|
||||||
gpb.depthStencilState.depthTestEnable = true;
|
|
||||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
|
||||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
||||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
|
||||||
gpb.addAttributeDescriptions({
|
|
||||||
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
|
||||||
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
|
||||||
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
|
||||||
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
|
||||||
});
|
|
||||||
|
|
||||||
m_graphicsPipeline = gpb.createPipeline();
|
|
||||||
m_debug.setObjectName(m_graphicsPipeline, "Graphics");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Loading the OBJ file and setting up all buffers
|
|
||||||
//
|
|
||||||
void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform)
|
|
||||||
{
|
|
||||||
LOGI("Loading File: %s \n", filename.c_str());
|
|
||||||
ObjLoader loader;
|
|
||||||
loader.loadModel(filename);
|
|
||||||
|
|
||||||
// Converting from Srgb to linear
|
|
||||||
for(auto& m : loader.m_materials)
|
|
||||||
{
|
|
||||||
m.ambient = glm::pow(m.ambient, glm::vec3(2.2f));
|
|
||||||
m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f));
|
|
||||||
m.specular = glm::pow(m.specular, glm::vec3(2.2f));
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjModel model;
|
|
||||||
model.nbIndices = static_cast<uint32_t>(loader.m_indices.size());
|
|
||||||
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
|
||||||
|
|
||||||
// Create the buffers on Device and copy vertices, indices and materials
|
|
||||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
|
||||||
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
|
||||||
VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
|
||||||
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | flag);
|
|
||||||
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | flag);
|
|
||||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
|
|
||||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
|
|
||||||
// Creates all textures found and find the offset for this model
|
|
||||||
auto txtOffset = static_cast<uint32_t>(m_textures.size());
|
|
||||||
createTextureImages(cmdBuf, loader.m_textures);
|
|
||||||
cmdBufGet.submitAndWait(cmdBuf);
|
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
|
||||||
|
|
||||||
std::string objNb = std::to_string(m_objModel.size());
|
|
||||||
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
|
|
||||||
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
|
|
||||||
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
|
|
||||||
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
|
|
||||||
|
|
||||||
// Keeping transformation matrix of the instance
|
|
||||||
ObjInstance instance;
|
|
||||||
instance.transform = transform;
|
|
||||||
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
|
|
||||||
m_instances.push_back(instance);
|
|
||||||
|
|
||||||
// Creating information for device access
|
|
||||||
ObjDesc desc;
|
|
||||||
desc.txtOffset = txtOffset;
|
|
||||||
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
|
|
||||||
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
|
|
||||||
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
|
|
||||||
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
|
|
||||||
|
|
||||||
// Keeping the obj host model and device description
|
|
||||||
m_objModel.emplace_back(model);
|
|
||||||
m_objDesc.emplace_back(desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating the uniform buffer holding the camera matrices
|
|
||||||
// - Buffer is host visible
|
|
||||||
//
|
|
||||||
void HelloVulkan::createUniformBuffer()
|
|
||||||
{
|
|
||||||
m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
m_debug.setObjectName(m_bGlobals.buffer, "Globals");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Create a storage buffer containing the description of the scene elements
|
|
||||||
// - Which geometry is used by which instance
|
|
||||||
// - Transformation
|
|
||||||
// - Offset for texture
|
|
||||||
//
|
|
||||||
void HelloVulkan::createObjDescriptionBuffer()
|
|
||||||
{
|
|
||||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
|
||||||
|
|
||||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
|
||||||
m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
|
||||||
cmdGen.submitAndWait(cmdBuf);
|
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
|
||||||
m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating all textures and samplers
|
|
||||||
//
|
|
||||||
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
|
|
||||||
{
|
|
||||||
VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
|
||||||
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
samplerCreateInfo.maxLod = FLT_MAX;
|
|
||||||
|
|
||||||
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
|
||||||
|
|
||||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
|
||||||
if(textures.empty() && m_textures.empty())
|
|
||||||
{
|
|
||||||
nvvk::Texture texture;
|
|
||||||
|
|
||||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
|
||||||
VkDeviceSize bufferSize = sizeof(color);
|
|
||||||
auto imgSize = VkExtent2D{1, 1};
|
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
|
||||||
|
|
||||||
// Creating the dummy texture
|
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
|
||||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
|
||||||
|
|
||||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
m_textures.push_back(texture);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Uploading all images
|
|
||||||
for(const auto& texture : textures)
|
|
||||||
{
|
|
||||||
std::stringstream o;
|
|
||||||
int texWidth, texHeight, texChannels;
|
|
||||||
o << "media/textures/" << texture;
|
|
||||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
|
||||||
|
|
||||||
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
|
||||||
|
|
||||||
stbi_uc* pixels = stbi_pixels;
|
|
||||||
// Handle failure
|
|
||||||
if(!stbi_pixels)
|
|
||||||
{
|
|
||||||
texWidth = texHeight = 1;
|
|
||||||
texChannels = 4;
|
|
||||||
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
|
||||||
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
|
||||||
|
|
||||||
{
|
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
|
||||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
|
||||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
|
||||||
|
|
||||||
m_textures.push_back(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
stbi_image_free(stbi_pixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Destroying all allocations
|
|
||||||
//
|
|
||||||
void HelloVulkan::destroyResources()
|
|
||||||
{
|
|
||||||
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
|
||||||
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
|
||||||
|
|
||||||
m_alloc.destroy(m_bGlobals);
|
|
||||||
m_alloc.destroy(m_bObjDesc);
|
|
||||||
|
|
||||||
for(auto& m : m_objModel)
|
|
||||||
{
|
|
||||||
m_alloc.destroy(m.vertexBuffer);
|
|
||||||
m_alloc.destroy(m.indexBuffer);
|
|
||||||
m_alloc.destroy(m.matColorBuffer);
|
|
||||||
m_alloc.destroy(m.matIndexBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& t : m_textures)
|
|
||||||
{
|
|
||||||
m_alloc.destroy(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#Post
|
|
||||||
m_alloc.destroy(m_offscreenColor);
|
|
||||||
m_alloc.destroy(m_offscreenDepth);
|
|
||||||
vkDestroyPipeline(m_device, m_postPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
|
|
||||||
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
|
|
||||||
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
|
|
||||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
|
||||||
|
|
||||||
m_alloc.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Drawing the scene in raster mode
|
|
||||||
//
|
|
||||||
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
|
||||||
{
|
|
||||||
VkDeviceSize offset{0};
|
|
||||||
|
|
||||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
|
||||||
|
|
||||||
// Dynamic Viewport
|
|
||||||
setViewport(cmdBuf);
|
|
||||||
|
|
||||||
// Drawing all triangles
|
|
||||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
for(const HelloVulkan::ObjInstance& inst : m_instances)
|
|
||||||
{
|
|
||||||
auto& model = m_objModel[inst.objIndex];
|
|
||||||
m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
|
||||||
m_pcRaster.modelMatrix = inst.transform;
|
|
||||||
|
|
||||||
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
|
||||||
sizeof(PushConstantRaster), &m_pcRaster);
|
|
||||||
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
|
||||||
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
|
||||||
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
|
||||||
}
|
|
||||||
m_debug.endLabel(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Handling resize of the window
|
|
||||||
//
|
|
||||||
void HelloVulkan::onResize(int /*w*/, int /*h*/)
|
|
||||||
{
|
|
||||||
createOffscreenRender();
|
|
||||||
updatePostDescriptorSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Post-processing
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating an offscreen frame buffer and the associated render pass
|
|
||||||
//
|
|
||||||
void HelloVulkan::createOffscreenRender()
|
|
||||||
{
|
|
||||||
m_alloc.destroy(m_offscreenColor);
|
|
||||||
m_alloc.destroy(m_offscreenDepth);
|
|
||||||
|
|
||||||
// Creating the color image
|
|
||||||
{
|
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
|
||||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
|
||||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
|
||||||
|
|
||||||
|
|
||||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
|
||||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
|
||||||
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
|
||||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
|
|
||||||
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating the depth buffer
|
|
||||||
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
|
||||||
{
|
|
||||||
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
|
||||||
|
|
||||||
|
|
||||||
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
|
||||||
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
depthStencilView.format = m_offscreenDepthFormat;
|
|
||||||
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
|
||||||
depthStencilView.image = image.image;
|
|
||||||
|
|
||||||
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting the image layout for both color and depth
|
|
||||||
{
|
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
|
||||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
|
||||||
|
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating a renderpass for the offscreen
|
|
||||||
if(!m_offscreenRenderPass)
|
|
||||||
{
|
|
||||||
m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
|
|
||||||
true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Creating the frame buffer for offscreen
|
|
||||||
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView};
|
|
||||||
|
|
||||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
|
||||||
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
|
||||||
info.renderPass = m_offscreenRenderPass;
|
|
||||||
info.attachmentCount = 2;
|
|
||||||
info.pAttachments = attachments.data();
|
|
||||||
info.width = m_size.width;
|
|
||||||
info.height = m_size.height;
|
|
||||||
info.layers = 1;
|
|
||||||
vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more
|
|
||||||
//
|
|
||||||
void HelloVulkan::createPostPipeline()
|
|
||||||
{
|
|
||||||
// Push constants in the fragment shader
|
|
||||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
|
||||||
|
|
||||||
// Creating the pipeline layout
|
|
||||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
||||||
createInfo.setLayoutCount = 1;
|
|
||||||
createInfo.pSetLayouts = &m_postDescSetLayout;
|
|
||||||
createInfo.pushConstantRangeCount = 1;
|
|
||||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
|
||||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
|
|
||||||
|
|
||||||
|
|
||||||
// Pipeline: completely generic, no vertices
|
|
||||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
|
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
||||||
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
|
||||||
m_postPipeline = pipelineGenerator.createPipeline();
|
|
||||||
m_debug.setObjectName(m_postPipeline, "post");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// The descriptor layout is the description of the data that is passed to the vertex or the
|
|
||||||
// fragment program.
|
|
||||||
//
|
|
||||||
void HelloVulkan::createPostDescriptor()
|
|
||||||
{
|
|
||||||
m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
||||||
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
|
||||||
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
|
||||||
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Update the output
|
|
||||||
//
|
|
||||||
void HelloVulkan::updatePostDescriptorSet()
|
|
||||||
{
|
|
||||||
VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
|
|
||||||
vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Draw a full screen quad with the attached image
|
|
||||||
//
|
|
||||||
void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
|
|
||||||
{
|
|
||||||
m_debug.beginLabel(cmdBuf, "Post");
|
|
||||||
|
|
||||||
setViewport(cmdBuf);
|
|
||||||
|
|
||||||
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
|
||||||
vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
|
||||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
|
|
||||||
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
|
||||||
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "nvvkhl/appbase_vk.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
|
||||||
#include "nvvk/resourceallocator_vk.hpp"
|
|
||||||
#include "shaders/host_device.h"
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Simple rasterizer of OBJ objects
|
|
||||||
// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance`
|
|
||||||
// - It is possible to have many `ObjInstance` referencing the same `ObjModel`
|
|
||||||
// - Rendering is done in an offscreen framebuffer
|
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
|
||||||
//
|
|
||||||
class HelloVulkan : public nvvkhl::AppBaseVk
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
|
||||||
void createGraphicsPipeline();
|
|
||||||
void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1));
|
|
||||||
void updateDescriptorSet();
|
|
||||||
void createUniformBuffer();
|
|
||||||
void createObjDescriptionBuffer();
|
|
||||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
|
||||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
|
||||||
void destroyResources();
|
|
||||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
|
||||||
|
|
||||||
// The OBJ model
|
|
||||||
struct ObjModel
|
|
||||||
{
|
|
||||||
uint32_t nbIndices{0};
|
|
||||||
uint32_t nbVertices{0};
|
|
||||||
nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex'
|
|
||||||
nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles
|
|
||||||
nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material'
|
|
||||||
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ObjInstance
|
|
||||||
{
|
|
||||||
glm::mat4 transform; // Matrix of the instance
|
|
||||||
uint32_t objIndex{0}; // Model index reference
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Information pushed at each draw call
|
|
||||||
PushConstantRaster m_pcRaster{
|
|
||||||
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix
|
|
||||||
{10.f, 15.f, 8.f}, // light position
|
|
||||||
0, // instance Id
|
|
||||||
100.f, // light intensity
|
|
||||||
0 // light type
|
|
||||||
};
|
|
||||||
|
|
||||||
// Array of objects and instances in the scene
|
|
||||||
std::vector<ObjModel> m_objModel; // Model on host
|
|
||||||
std::vector<ObjDesc> m_objDesc; // Model description for device access
|
|
||||||
std::vector<ObjInstance> m_instances; // Scene model instances
|
|
||||||
|
|
||||||
|
|
||||||
// Graphic pipeline
|
|
||||||
VkPipelineLayout m_pipelineLayout;
|
|
||||||
VkPipeline m_graphicsPipeline;
|
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
|
||||||
VkDescriptorPool m_descPool;
|
|
||||||
VkDescriptorSetLayout m_descSetLayout;
|
|
||||||
VkDescriptorSet m_descSet;
|
|
||||||
|
|
||||||
nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
|
|
||||||
nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
|
|
||||||
|
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
|
||||||
|
|
||||||
|
|
||||||
// #Post - Draw the rendered image on a quad using a tonemapper
|
|
||||||
void createOffscreenRender();
|
|
||||||
void createPostPipeline();
|
|
||||||
void createPostDescriptor();
|
|
||||||
void updatePostDescriptorSet();
|
|
||||||
void drawPost(VkCommandBuffer cmdBuf);
|
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
|
||||||
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
|
||||||
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
|
||||||
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
|
||||||
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
|
||||||
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
|
||||||
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
|
||||||
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
|
||||||
nvvk::Texture m_offscreenColor;
|
|
||||||
nvvk::Texture m_offscreenDepth;
|
|
||||||
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
|
||||||
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
|
||||||
};
|
|
||||||
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
|
@ -1,265 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// ImGui - standalone example application for Glfw + Vulkan, using programmable
|
|
||||||
// pipeline If you are new to ImGui, see examples/README.txt and documentation
|
|
||||||
// at the top of imgui.cpp.
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
|
||||||
#include "backends/imgui_impl_vulkan.h"
|
|
||||||
#include "imgui.h"
|
|
||||||
#include "imgui/imgui_helper.h"
|
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
|
||||||
#include "imgui/imgui_camera_widget.h"
|
|
||||||
#include "nvh/cameramanipulator.hpp"
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvpsystem.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/context_vk.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
#define UNUSED(x) (void)(x)
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default search path for shaders
|
|
||||||
std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
|
||||||
static void onErrorCallback(int error, const char* description)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extra UI
|
|
||||||
void renderUI(HelloVulkan& helloVk)
|
|
||||||
{
|
|
||||||
ImGuiH::CameraWidget();
|
|
||||||
if(ImGui::CollapsingHeader("Light"))
|
|
||||||
{
|
|
||||||
ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1);
|
|
||||||
|
|
||||||
ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
|
|
||||||
ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Application Entry
|
|
||||||
//
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
UNUSED(argc);
|
|
||||||
|
|
||||||
// Setup GLFW window
|
|
||||||
glfwSetErrorCallback(onErrorCallback);
|
|
||||||
if(!glfwInit())
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
||||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
// Setup camera
|
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
||||||
CameraManip.setLookat(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
|
|
||||||
|
|
||||||
// Setup Vulkan
|
|
||||||
if(!glfwVulkanSupported())
|
|
||||||
{
|
|
||||||
printf("GLFW: Vulkan Not Supported\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup some basic things for the sample, logging file for example
|
|
||||||
NVPSystem system(PROJECT_NAME);
|
|
||||||
|
|
||||||
// Search path for shaders and other media
|
|
||||||
defaultSearchPaths = {
|
|
||||||
NVPSystem::exePath() + PROJECT_RELDIRECTORY,
|
|
||||||
NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
|
|
||||||
std::string(PROJECT_NAME),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Vulkan required extensions
|
|
||||||
assert(glfwVulkanSupported() == 1);
|
|
||||||
uint32_t count{0};
|
|
||||||
auto reqExtensions = glfwGetRequiredInstanceExtensions(&count);
|
|
||||||
|
|
||||||
// Requesting Vulkan extensions and layers
|
|
||||||
nvvk::ContextCreateInfo contextInfo;
|
|
||||||
contextInfo.setVersion(1, 2); // Using Vulkan 1.2
|
|
||||||
for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..)
|
|
||||||
contextInfo.addInstanceExtension(reqExtensions[ext_id]);
|
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering
|
|
||||||
|
|
||||||
// Creating Vulkan base application
|
|
||||||
nvvk::Context vkctx{};
|
|
||||||
vkctx.initInstance(contextInfo);
|
|
||||||
// Find all compatible devices
|
|
||||||
auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo);
|
|
||||||
assert(!compatibleDevices.empty());
|
|
||||||
// Use a compatible device
|
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
|
||||||
|
|
||||||
// Create example
|
|
||||||
HelloVulkan helloVk;
|
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
|
||||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
||||||
helloVk.createDepthBuffer();
|
|
||||||
helloVk.createRenderPass();
|
|
||||||
helloVk.createFrameBuffers();
|
|
||||||
|
|
||||||
// Setup Imgui
|
|
||||||
helloVk.initGUI(0); // Using sub-pass 0
|
|
||||||
|
|
||||||
// Creation of the example
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/cube_multi.obj", defaultSearchPaths, true));
|
|
||||||
|
|
||||||
helloVk.createOffscreenRender();
|
|
||||||
helloVk.createDescriptorSetLayout();
|
|
||||||
helloVk.createGraphicsPipeline();
|
|
||||||
helloVk.createUniformBuffer();
|
|
||||||
helloVk.createObjDescriptionBuffer();
|
|
||||||
helloVk.updateDescriptorSet();
|
|
||||||
|
|
||||||
helloVk.createPostDescriptor();
|
|
||||||
helloVk.createPostPipeline();
|
|
||||||
helloVk.updatePostDescriptorSet();
|
|
||||||
glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f);
|
|
||||||
|
|
||||||
|
|
||||||
helloVk.setupGlfwCallbacks(window);
|
|
||||||
ImGui_ImplGlfw_InitForVulkan(window, true);
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
while(!glfwWindowShouldClose(window))
|
|
||||||
{
|
|
||||||
glfwPollEvents();
|
|
||||||
if(helloVk.isMinimized())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
|
||||||
ImGui_ImplGlfw_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
|
|
||||||
// Show UI window.
|
|
||||||
if(helloVk.showGui())
|
|
||||||
{
|
|
||||||
ImGuiH::Panel::Begin();
|
|
||||||
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
|
||||||
renderUI(helloVk);
|
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
|
||||||
ImGuiH::Panel::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start rendering the scene
|
|
||||||
helloVk.prepareFrame();
|
|
||||||
|
|
||||||
// Start command buffer of this frame
|
|
||||||
auto curFrame = helloVk.getCurFrame();
|
|
||||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
|
||||||
|
|
||||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
|
||||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
||||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
|
||||||
|
|
||||||
// Updating camera buffer
|
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
|
||||||
|
|
||||||
// Clearing screen
|
|
||||||
std::array<VkClearValue, 2> clearValues{};
|
|
||||||
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
|
||||||
clearValues[1].depthStencil = {1.0f, 0};
|
|
||||||
|
|
||||||
// Offscreen render pass
|
|
||||||
{
|
|
||||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
|
||||||
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
|
||||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
|
||||||
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
|
||||||
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
|
||||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
|
||||||
|
|
||||||
// Rendering Scene
|
|
||||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
helloVk.rasterize(cmdBuf);
|
|
||||||
vkCmdEndRenderPass(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
|
||||||
{
|
|
||||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
|
||||||
postRenderPassBeginInfo.clearValueCount = 2;
|
|
||||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
|
||||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
|
||||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
|
||||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
|
||||||
|
|
||||||
// Rendering tonemapper
|
|
||||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
helloVk.drawPost(cmdBuf);
|
|
||||||
// Rendering UI
|
|
||||||
ImGui::Render();
|
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
|
||||||
vkCmdEndRenderPass(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit for display
|
|
||||||
vkEndCommandBuffer(cmdBuf);
|
|
||||||
helloVk.submitFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
vkDeviceWaitIdle(helloVk.getDevice());
|
|
||||||
|
|
||||||
helloVk.destroyResources();
|
|
||||||
helloVk.destroy();
|
|
||||||
vkctx.deinit();
|
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
|
||||||
glfwTerminate();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRaster
|
|
||||||
{
|
|
||||||
PushConstantRaster pcRaster;
|
|
||||||
};
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
// Incoming
|
|
||||||
layout(location = 1) in vec3 i_worldPos;
|
|
||||||
layout(location = 2) in vec3 i_worldNrm;
|
|
||||||
layout(location = 3) in vec3 i_viewDir;
|
|
||||||
layout(location = 4) in vec2 i_texCoord;
|
|
||||||
// Outgoing
|
|
||||||
layout(location = 0) out vec4 o_color;
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
|
|
||||||
layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
layout(binding = eTextures) uniform sampler2D[] textureSamplers;
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Material of the object
|
|
||||||
ObjDesc objResource = objDesc.i[pcRaster.objIndex];
|
|
||||||
MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
|
|
||||||
int matIndex = matIndices.i[gl_PrimitiveID];
|
|
||||||
WaveFrontMaterial mat = materials.m[matIndex];
|
|
||||||
|
|
||||||
vec3 N = normalize(i_worldNrm);
|
|
||||||
|
|
||||||
// Vector toward light
|
|
||||||
vec3 L;
|
|
||||||
float lightIntensity = pcRaster.lightIntensity;
|
|
||||||
if(pcRaster.lightType == 0)
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRaster.lightPosition - i_worldPos;
|
|
||||||
float d = length(lDir);
|
|
||||||
lightIntensity = pcRaster.lightIntensity / (d * d);
|
|
||||||
L = normalize(lDir);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
L = normalize(pcRaster.lightPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Diffuse
|
|
||||||
vec3 diffuse = computeDiffuse(mat, L, N);
|
|
||||||
if(mat.textureId >= 0)
|
|
||||||
{
|
|
||||||
int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
|
|
||||||
uint txtId = txtOffset + mat.textureId;
|
|
||||||
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
|
|
||||||
diffuse *= diffuseTxt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specular
|
|
||||||
vec3 specular = computeSpecular(mat, i_viewDir, L, N);
|
|
||||||
|
|
||||||
// Result
|
|
||||||
o_color = vec4(lightIntensity * (diffuse + specular), 1);
|
|
||||||
}
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef COMMON_HOST_DEVICE
|
|
||||||
#define COMMON_HOST_DEVICE
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
// GLSL Type
|
|
||||||
using vec2 = glm::vec2;
|
|
||||||
using vec3 = glm::vec3;
|
|
||||||
using vec4 = glm::vec4;
|
|
||||||
using mat4 = glm::mat4;
|
|
||||||
using uint = unsigned int;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
|
|
||||||
#define START_BINDING(a) enum a {
|
|
||||||
#define END_BINDING() }
|
|
||||||
#else
|
|
||||||
#define START_BINDING(a) const uint
|
|
||||||
#define END_BINDING()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
START_BINDING(SceneBindings)
|
|
||||||
eGlobals = 0, // Global uniform containing camera matrices
|
|
||||||
eObjDescs = 1, // Access to the object descriptions
|
|
||||||
eTextures = 2 // Access to textures
|
|
||||||
END_BINDING();
|
|
||||||
|
|
||||||
START_BINDING(RtxBindings)
|
|
||||||
eTlas = 0, // Top-level acceleration structure
|
|
||||||
eOutImage = 1 // Ray tracer output image
|
|
||||||
END_BINDING();
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
// Information of a obj model when referenced in a shader
|
|
||||||
struct ObjDesc
|
|
||||||
{
|
|
||||||
int txtOffset; // Texture index offset in the array of textures
|
|
||||||
uint64_t vertexAddress; // Address of the Vertex buffer
|
|
||||||
uint64_t indexAddress; // Address of the index buffer
|
|
||||||
uint64_t materialAddress; // Address of the material buffer
|
|
||||||
uint64_t materialIndexAddress; // Address of the triangle material index buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
// Uniform buffer set at each frame
|
|
||||||
struct GlobalUniforms
|
|
||||||
{
|
|
||||||
mat4 viewProj; // Camera view * projection
|
|
||||||
mat4 viewInverse; // Camera inverse view matrix
|
|
||||||
mat4 projInverse; // Camera inverse projection matrix
|
|
||||||
};
|
|
||||||
|
|
||||||
// Push constant structure for the raster
|
|
||||||
struct PushConstantRaster
|
|
||||||
{
|
|
||||||
mat4 modelMatrix; // matrix of the instance
|
|
||||||
vec3 lightPosition;
|
|
||||||
uint objIndex;
|
|
||||||
float lightIntensity;
|
|
||||||
int lightType;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Push constant structure for the ray tracer
|
|
||||||
struct PushConstantRay
|
|
||||||
{
|
|
||||||
vec4 clearColor;
|
|
||||||
vec3 lightPosition;
|
|
||||||
float lightIntensity;
|
|
||||||
int lightType;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
|
|
||||||
{
|
|
||||||
vec3 pos;
|
|
||||||
vec3 nrm;
|
|
||||||
vec3 color;
|
|
||||||
vec2 texCoord;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
|
|
||||||
{
|
|
||||||
vec3 ambient;
|
|
||||||
vec3 diffuse;
|
|
||||||
vec3 specular;
|
|
||||||
vec3 transmittance;
|
|
||||||
vec3 emission;
|
|
||||||
float shininess;
|
|
||||||
float ior; // index of refraction
|
|
||||||
float dissolve; // 1 == opaque; 0 == fully transparent
|
|
||||||
int illum; // illumination model (see http://www.fileformat.info/format/material/)
|
|
||||||
int textureId;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(location = 0) out vec2 outUV;
|
|
||||||
|
|
||||||
|
|
||||||
out gl_PerVertex
|
|
||||||
{
|
|
||||||
vec4 gl_Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
|
||||||
gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(location = 0) in vec2 outUV;
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform sampler2D noisyTxt;
|
|
||||||
|
|
||||||
layout(push_constant) uniform shaderInformation
|
|
||||||
{
|
|
||||||
float aspectRatio;
|
|
||||||
}
|
|
||||||
pushc;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec2 uv = outUV;
|
|
||||||
float gamma = 1. / 2.2;
|
|
||||||
fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma));
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
layout(binding = 0) uniform _GlobalUniforms
|
|
||||||
{
|
|
||||||
GlobalUniforms uni;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRaster
|
|
||||||
{
|
|
||||||
PushConstantRaster pcRaster;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 i_position;
|
|
||||||
layout(location = 1) in vec3 i_normal;
|
|
||||||
layout(location = 2) in vec3 i_color;
|
|
||||||
layout(location = 3) in vec2 i_texCoord;
|
|
||||||
|
|
||||||
|
|
||||||
layout(location = 1) out vec3 o_worldPos;
|
|
||||||
layout(location = 2) out vec3 o_worldNrm;
|
|
||||||
layout(location = 3) out vec3 o_viewDir;
|
|
||||||
layout(location = 4) out vec2 o_texCoord;
|
|
||||||
|
|
||||||
out gl_PerVertex
|
|
||||||
{
|
|
||||||
vec4 gl_Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
|
|
||||||
|
|
||||||
o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
|
|
||||||
o_viewDir = vec3(o_worldPos - origin);
|
|
||||||
o_texCoord = i_texCoord;
|
|
||||||
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
|
|
||||||
|
|
||||||
gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "host_device.h"
|
|
||||||
|
|
||||||
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
|
|
||||||
{
|
|
||||||
// Lambertian
|
|
||||||
float dotNL = max(dot(normal, lightDir), 0.0);
|
|
||||||
vec3 c = mat.diffuse * dotNL;
|
|
||||||
if(mat.illum >= 1)
|
|
||||||
c += mat.ambient;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal)
|
|
||||||
{
|
|
||||||
if(mat.illum < 2)
|
|
||||||
return vec3(0);
|
|
||||||
|
|
||||||
// Compute specular only if not in shadow
|
|
||||||
const float kPi = 3.14159265;
|
|
||||||
const float kShininess = max(mat.shininess, 4.0);
|
|
||||||
|
|
||||||
// Specular
|
|
||||||
const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi);
|
|
||||||
vec3 V = normalize(-viewDir);
|
|
||||||
vec3 R = reflect(-lightDir, normal);
|
|
||||||
float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess);
|
|
||||||
|
|
||||||
return vec3(mat.specular * specular);
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
#*****************************************************************************
|
|
||||||
# Copyright 2020 NVIDIA Corporation. All rights reserved.
|
|
||||||
#*****************************************************************************
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Project setting
|
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
|
||||||
message(STATUS "-------------------------------")
|
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# C++ target and defines
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
add_executable(${PROJNAME})
|
|
||||||
_add_project_definitions(${PROJNAME})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Source files for this project
|
|
||||||
#
|
|
||||||
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
|
|
||||||
file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
|
|
||||||
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
|
||||||
include_directories(${TUTO_KHR_DIR}/common)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# GLSL to SPIR-V custom build
|
|
||||||
compile_glsl_directory(
|
|
||||||
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
|
|
||||||
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
|
|
||||||
VULKAN_TARGET "vulkan1.2"
|
|
||||||
DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sources
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sub-folders in Visual Studio
|
|
||||||
#
|
|
||||||
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
|
|
||||||
source_group("Sources" FILES ${SOURCE_FILES})
|
|
||||||
source_group("Headers" FILES ${HEADER_FILES})
|
|
||||||
source_group("Shader Sources" FILES ${GLSL_SOURCES})
|
|
||||||
source_group("Shader Headers" FILES ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Linkage
|
|
||||||
#
|
|
||||||
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core)
|
|
||||||
|
|
||||||
foreach(DEBUGLIB ${LIBRARIES_DEBUG})
|
|
||||||
target_link_libraries(${PROJNAME} debug ${DEBUGLIB})
|
|
||||||
endforeach(DEBUGLIB)
|
|
||||||
|
|
||||||
foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
|
|
||||||
target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
|
|
||||||
endforeach(RELEASELIB)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# copies binaries that need to be put next to the exe files (ZLib, etc.)
|
|
||||||
#
|
|
||||||
_finalize_target( ${PROJNAME} )
|
|
||||||
|
|
||||||
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
# NVIDIA Vulkan Ray Tracing Tutorial
|
|
||||||
|
|
||||||
This example is the result of the ray tracing tutorial.
|
|
||||||
The tutorial is adding ray tracing capability to an OBJ rasterizer in Vulkan
|
|
||||||
|
|
||||||
If you haven't done it, [**Start Ray Tracing Tutorial**](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tutorial.md.html).
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Going Further
|
|
||||||
|
|
||||||
Once the tutorial completed and the basics of ray tracing are in place, other tuturials are going further from this code base.
|
|
||||||
|
|
||||||
See all other [additional ray tracing tutorials](../README.md#extra-tutorials)
|
|
||||||
|
|
@ -1,936 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include "obj_loader.h"
|
|
||||||
#include "stb_image.h"
|
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
|
||||||
#include "nvh/alignment.hpp"
|
|
||||||
#include "nvh/cameramanipulator.hpp"
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
#include "nvvk/images_vk.hpp"
|
|
||||||
#include "nvvk/pipeline_vk.hpp"
|
|
||||||
#include "nvvk/renderpasses_vk.hpp"
|
|
||||||
#include "nvvk/shaders_vk.hpp"
|
|
||||||
#include "nvvk/buffers_vk.hpp"
|
|
||||||
|
|
||||||
extern std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Keep the handle on the device
|
|
||||||
// Initialize the tool to do all our allocations: buffers, images
|
|
||||||
//
|
|
||||||
void HelloVulkan::setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily)
|
|
||||||
{
|
|
||||||
AppBaseVk::setup(instance, device, physicalDevice, queueFamily);
|
|
||||||
m_alloc.init(instance, device, physicalDevice);
|
|
||||||
m_debug.setup(m_device);
|
|
||||||
m_offscreenDepthFormat = nvvk::findDepthFormat(physicalDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Called at each frame to update the camera matrix
|
|
||||||
//
|
|
||||||
void HelloVulkan::updateUniformBuffer(const VkCommandBuffer& cmdBuf)
|
|
||||||
{
|
|
||||||
// Prepare new UBO contents on host.
|
|
||||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
|
||||||
GlobalUniforms hostUBO = {};
|
|
||||||
const auto& view = CameraManip.getMatrix();
|
|
||||||
glm::mat4 proj = glm::perspectiveRH_ZO(glm::radians(CameraManip.getFov()), aspectRatio, 0.1f, 1000.0f);
|
|
||||||
proj[1][1] *= -1; // Inverting Y for Vulkan (not needed with perspectiveVK).
|
|
||||||
|
|
||||||
hostUBO.viewProj = proj * view;
|
|
||||||
hostUBO.viewInverse = glm::inverse(view);
|
|
||||||
hostUBO.projInverse = glm::inverse(proj);
|
|
||||||
|
|
||||||
// UBO on the device, and what stages access it.
|
|
||||||
VkBuffer deviceUBO = m_bGlobals.buffer;
|
|
||||||
auto uboUsageStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
|
||||||
|
|
||||||
// Ensure that the modified UBO is not visible to previous frames.
|
|
||||||
VkBufferMemoryBarrier beforeBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
|
||||||
beforeBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
beforeBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
beforeBarrier.buffer = deviceUBO;
|
|
||||||
beforeBarrier.offset = 0;
|
|
||||||
beforeBarrier.size = sizeof(hostUBO);
|
|
||||||
vkCmdPipelineBarrier(cmdBuf, uboUsageStages, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
|
||||||
nullptr, 1, &beforeBarrier, 0, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
// Schedule the host-to-device upload. (hostUBO is copied into the cmd
|
|
||||||
// buffer so it is okay to deallocate when the function returns).
|
|
||||||
vkCmdUpdateBuffer(cmdBuf, m_bGlobals.buffer, 0, sizeof(GlobalUniforms), &hostUBO);
|
|
||||||
|
|
||||||
// Making sure the updated UBO will be visible.
|
|
||||||
VkBufferMemoryBarrier afterBarrier{VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER};
|
|
||||||
afterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
||||||
afterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
||||||
afterBarrier.buffer = deviceUBO;
|
|
||||||
afterBarrier.offset = 0;
|
|
||||||
afterBarrier.size = sizeof(hostUBO);
|
|
||||||
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, uboUsageStages, VK_DEPENDENCY_DEVICE_GROUP_BIT, 0,
|
|
||||||
nullptr, 1, &afterBarrier, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Describing the layout pushed when rendering
|
|
||||||
//
|
|
||||||
void HelloVulkan::createDescriptorSetLayout()
|
|
||||||
{
|
|
||||||
auto nbTxt = static_cast<uint32_t>(m_textures.size());
|
|
||||||
|
|
||||||
// Camera matrices
|
|
||||||
m_descSetLayoutBind.addBinding(SceneBindings::eGlobals, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1,
|
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR);
|
|
||||||
// Obj descriptions
|
|
||||||
m_descSetLayoutBind.addBinding(SceneBindings::eObjDescs, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1,
|
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
|
||||||
// Textures
|
|
||||||
m_descSetLayoutBind.addBinding(SceneBindings::eTextures, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, nbTxt,
|
|
||||||
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
|
|
||||||
|
|
||||||
|
|
||||||
m_descSetLayout = m_descSetLayoutBind.createLayout(m_device);
|
|
||||||
m_descPool = m_descSetLayoutBind.createPool(m_device, 1);
|
|
||||||
m_descSet = nvvk::allocateDescriptorSet(m_device, m_descPool, m_descSetLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Setting up the buffers in the descriptor set
|
|
||||||
//
|
|
||||||
void HelloVulkan::updateDescriptorSet()
|
|
||||||
{
|
|
||||||
std::vector<VkWriteDescriptorSet> writes;
|
|
||||||
|
|
||||||
// Camera matrices and scene description
|
|
||||||
VkDescriptorBufferInfo dbiUnif{m_bGlobals.buffer, 0, VK_WHOLE_SIZE};
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eGlobals, &dbiUnif));
|
|
||||||
|
|
||||||
VkDescriptorBufferInfo dbiSceneDesc{m_bObjDesc.buffer, 0, VK_WHOLE_SIZE};
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWrite(m_descSet, SceneBindings::eObjDescs, &dbiSceneDesc));
|
|
||||||
|
|
||||||
// All texture samplers
|
|
||||||
std::vector<VkDescriptorImageInfo> diit;
|
|
||||||
for(auto& texture : m_textures)
|
|
||||||
{
|
|
||||||
diit.emplace_back(texture.descriptor);
|
|
||||||
}
|
|
||||||
writes.emplace_back(m_descSetLayoutBind.makeWriteArray(m_descSet, SceneBindings::eTextures, diit.data()));
|
|
||||||
|
|
||||||
// Writing the information
|
|
||||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating the pipeline layout
|
|
||||||
//
|
|
||||||
void HelloVulkan::createGraphicsPipeline()
|
|
||||||
{
|
|
||||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstantRaster)};
|
|
||||||
|
|
||||||
// Creating the Pipeline Layout
|
|
||||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
||||||
createInfo.setLayoutCount = 1;
|
|
||||||
createInfo.pSetLayouts = &m_descSetLayout;
|
|
||||||
createInfo.pushConstantRangeCount = 1;
|
|
||||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
|
||||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_pipelineLayout);
|
|
||||||
|
|
||||||
|
|
||||||
// Creating the Pipeline
|
|
||||||
std::vector<std::string> paths = defaultSearchPaths;
|
|
||||||
nvvk::GraphicsPipelineGeneratorCombined gpb(m_device, m_pipelineLayout, m_offscreenRenderPass);
|
|
||||||
gpb.depthStencilState.depthTestEnable = true;
|
|
||||||
gpb.addShader(nvh::loadFile("spv/vert_shader.vert.spv", true, paths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
|
||||||
gpb.addShader(nvh::loadFile("spv/frag_shader.frag.spv", true, paths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
||||||
gpb.addBindingDescription({0, sizeof(VertexObj)});
|
|
||||||
gpb.addAttributeDescriptions({
|
|
||||||
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, pos))},
|
|
||||||
{1, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, nrm))},
|
|
||||||
{2, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, color))},
|
|
||||||
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexObj, texCoord))},
|
|
||||||
});
|
|
||||||
|
|
||||||
m_graphicsPipeline = gpb.createPipeline();
|
|
||||||
m_debug.setObjectName(m_graphicsPipeline, "Graphics");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Loading the OBJ file and setting up all buffers
|
|
||||||
//
|
|
||||||
void HelloVulkan::loadModel(const std::string& filename, glm::mat4 transform)
|
|
||||||
{
|
|
||||||
LOGI("Loading File: %s \n", filename.c_str());
|
|
||||||
ObjLoader loader;
|
|
||||||
loader.loadModel(filename);
|
|
||||||
|
|
||||||
// Converting from Srgb to linear
|
|
||||||
for(auto& m : loader.m_materials)
|
|
||||||
{
|
|
||||||
m.ambient = glm::pow(m.ambient, glm::vec3(2.2f));
|
|
||||||
m.diffuse = glm::pow(m.diffuse, glm::vec3(2.2f));
|
|
||||||
m.specular = glm::pow(m.specular, glm::vec3(2.2f));
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjModel model;
|
|
||||||
model.nbIndices = static_cast<uint32_t>(loader.m_indices.size());
|
|
||||||
model.nbVertices = static_cast<uint32_t>(loader.m_vertices.size());
|
|
||||||
|
|
||||||
// Create the buffers on Device and copy vertices, indices and materials
|
|
||||||
nvvk::CommandPool cmdBufGet(m_device, m_graphicsQueueIndex);
|
|
||||||
VkCommandBuffer cmdBuf = cmdBufGet.createCommandBuffer();
|
|
||||||
VkBufferUsageFlags flag = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
|
||||||
VkBufferUsageFlags rayTracingFlags = // used also for building acceleration structures
|
|
||||||
flag | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
|
||||||
model.vertexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | rayTracingFlags);
|
|
||||||
model.indexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | rayTracingFlags);
|
|
||||||
model.matColorBuffer = m_alloc.createBuffer(cmdBuf, loader.m_materials, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
|
|
||||||
model.matIndexBuffer = m_alloc.createBuffer(cmdBuf, loader.m_matIndx, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | flag);
|
|
||||||
// Creates all textures found and find the offset for this model
|
|
||||||
auto txtOffset = static_cast<uint32_t>(m_textures.size());
|
|
||||||
createTextureImages(cmdBuf, loader.m_textures);
|
|
||||||
cmdBufGet.submitAndWait(cmdBuf);
|
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
|
||||||
|
|
||||||
std::string objNb = std::to_string(m_objModel.size());
|
|
||||||
m_debug.setObjectName(model.vertexBuffer.buffer, (std::string("vertex_" + objNb)));
|
|
||||||
m_debug.setObjectName(model.indexBuffer.buffer, (std::string("index_" + objNb)));
|
|
||||||
m_debug.setObjectName(model.matColorBuffer.buffer, (std::string("mat_" + objNb)));
|
|
||||||
m_debug.setObjectName(model.matIndexBuffer.buffer, (std::string("matIdx_" + objNb)));
|
|
||||||
|
|
||||||
// Keeping transformation matrix of the instance
|
|
||||||
ObjInstance instance;
|
|
||||||
instance.transform = transform;
|
|
||||||
instance.objIndex = static_cast<uint32_t>(m_objModel.size());
|
|
||||||
m_instances.push_back(instance);
|
|
||||||
|
|
||||||
// Creating information for device access
|
|
||||||
ObjDesc desc;
|
|
||||||
desc.txtOffset = txtOffset;
|
|
||||||
desc.vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
|
|
||||||
desc.indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
|
|
||||||
desc.materialAddress = nvvk::getBufferDeviceAddress(m_device, model.matColorBuffer.buffer);
|
|
||||||
desc.materialIndexAddress = nvvk::getBufferDeviceAddress(m_device, model.matIndexBuffer.buffer);
|
|
||||||
|
|
||||||
// Keeping the obj host model and device description
|
|
||||||
m_objModel.emplace_back(model);
|
|
||||||
m_objDesc.emplace_back(desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating the uniform buffer holding the camera matrices
|
|
||||||
// - Buffer is host visible
|
|
||||||
//
|
|
||||||
void HelloVulkan::createUniformBuffer()
|
|
||||||
{
|
|
||||||
m_bGlobals = m_alloc.createBuffer(sizeof(GlobalUniforms), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
m_debug.setObjectName(m_bGlobals.buffer, "Globals");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Create a storage buffer containing the description of the scene elements
|
|
||||||
// - Which geometry is used by which instance
|
|
||||||
// - Transformation
|
|
||||||
// - Offset for texture
|
|
||||||
//
|
|
||||||
void HelloVulkan::createObjDescriptionBuffer()
|
|
||||||
{
|
|
||||||
nvvk::CommandPool cmdGen(m_device, m_graphicsQueueIndex);
|
|
||||||
|
|
||||||
auto cmdBuf = cmdGen.createCommandBuffer();
|
|
||||||
m_bObjDesc = m_alloc.createBuffer(cmdBuf, m_objDesc, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
|
|
||||||
cmdGen.submitAndWait(cmdBuf);
|
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
|
||||||
m_debug.setObjectName(m_bObjDesc.buffer, "ObjDescs");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating all textures and samplers
|
|
||||||
//
|
|
||||||
void HelloVulkan::createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures)
|
|
||||||
{
|
|
||||||
VkSamplerCreateInfo samplerCreateInfo{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
|
||||||
samplerCreateInfo.minFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.magFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
samplerCreateInfo.maxLod = FLT_MAX;
|
|
||||||
|
|
||||||
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
|
||||||
|
|
||||||
// If no textures are present, create a dummy one to accommodate the pipeline layout
|
|
||||||
if(textures.empty() && m_textures.empty())
|
|
||||||
{
|
|
||||||
nvvk::Texture texture;
|
|
||||||
|
|
||||||
std::array<uint8_t, 4> color{255u, 255u, 255u, 255u};
|
|
||||||
VkDeviceSize bufferSize = sizeof(color);
|
|
||||||
auto imgSize = VkExtent2D{1, 1};
|
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format);
|
|
||||||
|
|
||||||
// Creating the dummy texture
|
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, color.data(), imageCreateInfo);
|
|
||||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
|
||||||
|
|
||||||
// The image format must be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
m_textures.push_back(texture);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Uploading all images
|
|
||||||
for(const auto& texture : textures)
|
|
||||||
{
|
|
||||||
std::stringstream o;
|
|
||||||
int texWidth, texHeight, texChannels;
|
|
||||||
o << "media/textures/" << texture;
|
|
||||||
std::string txtFile = nvh::findFile(o.str(), defaultSearchPaths, true);
|
|
||||||
|
|
||||||
stbi_uc* stbi_pixels = stbi_load(txtFile.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
std::array<stbi_uc, 4> color{255u, 0u, 255u, 255u};
|
|
||||||
|
|
||||||
stbi_uc* pixels = stbi_pixels;
|
|
||||||
// Handle failure
|
|
||||||
if(!stbi_pixels)
|
|
||||||
{
|
|
||||||
texWidth = texHeight = 1;
|
|
||||||
texChannels = 4;
|
|
||||||
pixels = reinterpret_cast<stbi_uc*>(color.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize bufferSize = static_cast<uint64_t>(texWidth) * texHeight * sizeof(uint8_t) * 4;
|
|
||||||
auto imgSize = VkExtent2D{(uint32_t)texWidth, (uint32_t)texHeight};
|
|
||||||
auto imageCreateInfo = nvvk::makeImage2DCreateInfo(imgSize, format, VK_IMAGE_USAGE_SAMPLED_BIT, true);
|
|
||||||
|
|
||||||
{
|
|
||||||
nvvk::Image image = m_alloc.createImage(cmdBuf, bufferSize, pixels, imageCreateInfo);
|
|
||||||
nvvk::cmdGenerateMipmaps(cmdBuf, image.image, format, imgSize, imageCreateInfo.mipLevels);
|
|
||||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, imageCreateInfo);
|
|
||||||
nvvk::Texture texture = m_alloc.createTexture(image, ivInfo, samplerCreateInfo);
|
|
||||||
|
|
||||||
m_textures.push_back(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
stbi_image_free(stbi_pixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Destroying all allocations
|
|
||||||
//
|
|
||||||
void HelloVulkan::destroyResources()
|
|
||||||
{
|
|
||||||
vkDestroyPipeline(m_device, m_graphicsPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
|
|
||||||
vkDestroyDescriptorPool(m_device, m_descPool, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_descSetLayout, nullptr);
|
|
||||||
|
|
||||||
m_alloc.destroy(m_bGlobals);
|
|
||||||
m_alloc.destroy(m_bObjDesc);
|
|
||||||
|
|
||||||
for(auto& m : m_objModel)
|
|
||||||
{
|
|
||||||
m_alloc.destroy(m.vertexBuffer);
|
|
||||||
m_alloc.destroy(m.indexBuffer);
|
|
||||||
m_alloc.destroy(m.matColorBuffer);
|
|
||||||
m_alloc.destroy(m.matIndexBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& t : m_textures)
|
|
||||||
{
|
|
||||||
m_alloc.destroy(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#Post
|
|
||||||
m_alloc.destroy(m_offscreenColor);
|
|
||||||
m_alloc.destroy(m_offscreenDepth);
|
|
||||||
vkDestroyPipeline(m_device, m_postPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(m_device, m_postPipelineLayout, nullptr);
|
|
||||||
vkDestroyDescriptorPool(m_device, m_postDescPool, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_postDescSetLayout, nullptr);
|
|
||||||
vkDestroyRenderPass(m_device, m_offscreenRenderPass, nullptr);
|
|
||||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
m_rtBuilder.destroy();
|
|
||||||
vkDestroyPipeline(m_device, m_rtPipeline, nullptr);
|
|
||||||
vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr);
|
|
||||||
vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr);
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr);
|
|
||||||
m_alloc.destroy(m_rtSBTBuffer);
|
|
||||||
|
|
||||||
m_alloc.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Drawing the scene in raster mode
|
|
||||||
//
|
|
||||||
void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf)
|
|
||||||
{
|
|
||||||
VkDeviceSize offset{0};
|
|
||||||
|
|
||||||
m_debug.beginLabel(cmdBuf, "Rasterize");
|
|
||||||
|
|
||||||
// Dynamic Viewport
|
|
||||||
setViewport(cmdBuf);
|
|
||||||
|
|
||||||
// Drawing all triangles
|
|
||||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_graphicsPipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
for(const HelloVulkan::ObjInstance& inst : m_instances)
|
|
||||||
{
|
|
||||||
auto& model = m_objModel[inst.objIndex];
|
|
||||||
m_pcRaster.objIndex = inst.objIndex; // Telling which object is drawn
|
|
||||||
m_pcRaster.modelMatrix = inst.transform;
|
|
||||||
|
|
||||||
vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
|
|
||||||
sizeof(PushConstantRaster), &m_pcRaster);
|
|
||||||
vkCmdBindVertexBuffers(cmdBuf, 0, 1, &model.vertexBuffer.buffer, &offset);
|
|
||||||
vkCmdBindIndexBuffer(cmdBuf, model.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
|
||||||
vkCmdDrawIndexed(cmdBuf, model.nbIndices, 1, 0, 0, 0);
|
|
||||||
}
|
|
||||||
m_debug.endLabel(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Handling resize of the window
|
|
||||||
//
|
|
||||||
void HelloVulkan::onResize(int /*w*/, int /*h*/)
|
|
||||||
{
|
|
||||||
createOffscreenRender();
|
|
||||||
updatePostDescriptorSet();
|
|
||||||
updateRtDescriptorSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Post-processing
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Creating an offscreen frame buffer and the associated render pass
|
|
||||||
//
|
|
||||||
void HelloVulkan::createOffscreenRender()
|
|
||||||
{
|
|
||||||
m_alloc.destroy(m_offscreenColor);
|
|
||||||
m_alloc.destroy(m_offscreenDepth);
|
|
||||||
|
|
||||||
// Creating the color image
|
|
||||||
{
|
|
||||||
auto colorCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenColorFormat,
|
|
||||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT
|
|
||||||
| VK_IMAGE_USAGE_STORAGE_BIT);
|
|
||||||
|
|
||||||
|
|
||||||
nvvk::Image image = m_alloc.createImage(colorCreateInfo);
|
|
||||||
VkImageViewCreateInfo ivInfo = nvvk::makeImageViewCreateInfo(image.image, colorCreateInfo);
|
|
||||||
VkSamplerCreateInfo sampler{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
|
||||||
m_offscreenColor = m_alloc.createTexture(image, ivInfo, sampler);
|
|
||||||
m_offscreenColor.descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating the depth buffer
|
|
||||||
auto depthCreateInfo = nvvk::makeImage2DCreateInfo(m_size, m_offscreenDepthFormat, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
|
||||||
{
|
|
||||||
nvvk::Image image = m_alloc.createImage(depthCreateInfo);
|
|
||||||
|
|
||||||
|
|
||||||
VkImageViewCreateInfo depthStencilView{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
|
||||||
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
depthStencilView.format = m_offscreenDepthFormat;
|
|
||||||
depthStencilView.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
|
|
||||||
depthStencilView.image = image.image;
|
|
||||||
|
|
||||||
m_offscreenDepth = m_alloc.createTexture(image, depthStencilView);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting the image layout for both color and depth
|
|
||||||
{
|
|
||||||
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex);
|
|
||||||
auto cmdBuf = genCmdBuf.createCommandBuffer();
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenColor.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
nvvk::cmdBarrierImageLayout(cmdBuf, m_offscreenDepth.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_DEPTH_BIT);
|
|
||||||
|
|
||||||
genCmdBuf.submitAndWait(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating a renderpass for the offscreen
|
|
||||||
if(!m_offscreenRenderPass)
|
|
||||||
{
|
|
||||||
m_offscreenRenderPass = nvvk::createRenderPass(m_device, {m_offscreenColorFormat}, m_offscreenDepthFormat, 1, true,
|
|
||||||
true, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Creating the frame buffer for offscreen
|
|
||||||
std::vector<VkImageView> attachments = {m_offscreenColor.descriptor.imageView, m_offscreenDepth.descriptor.imageView};
|
|
||||||
|
|
||||||
vkDestroyFramebuffer(m_device, m_offscreenFramebuffer, nullptr);
|
|
||||||
VkFramebufferCreateInfo info{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
|
|
||||||
info.renderPass = m_offscreenRenderPass;
|
|
||||||
info.attachmentCount = 2;
|
|
||||||
info.pAttachments = attachments.data();
|
|
||||||
info.width = m_size.width;
|
|
||||||
info.height = m_size.height;
|
|
||||||
info.layers = 1;
|
|
||||||
vkCreateFramebuffer(m_device, &info, nullptr, &m_offscreenFramebuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// The pipeline is how things are rendered, which shaders, type of primitives, depth test and more
|
|
||||||
//
|
|
||||||
void HelloVulkan::createPostPipeline()
|
|
||||||
{
|
|
||||||
// Push constants in the fragment shader
|
|
||||||
VkPushConstantRange pushConstantRanges = {VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float)};
|
|
||||||
|
|
||||||
// Creating the pipeline layout
|
|
||||||
VkPipelineLayoutCreateInfo createInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
||||||
createInfo.setLayoutCount = 1;
|
|
||||||
createInfo.pSetLayouts = &m_postDescSetLayout;
|
|
||||||
createInfo.pushConstantRangeCount = 1;
|
|
||||||
createInfo.pPushConstantRanges = &pushConstantRanges;
|
|
||||||
vkCreatePipelineLayout(m_device, &createInfo, nullptr, &m_postPipelineLayout);
|
|
||||||
|
|
||||||
|
|
||||||
// Pipeline: completely generic, no vertices
|
|
||||||
nvvk::GraphicsPipelineGeneratorCombined pipelineGenerator(m_device, m_postPipelineLayout, m_renderPass);
|
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/passthrough.vert.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_VERTEX_BIT);
|
|
||||||
pipelineGenerator.addShader(nvh::loadFile("spv/post.frag.spv", true, defaultSearchPaths, true), VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
||||||
pipelineGenerator.rasterizationState.cullMode = VK_CULL_MODE_NONE;
|
|
||||||
m_postPipeline = pipelineGenerator.createPipeline();
|
|
||||||
m_debug.setObjectName(m_postPipeline, "post");
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// The descriptor layout is the description of the data that is passed to the vertex or the
|
|
||||||
// fragment program.
|
|
||||||
//
|
|
||||||
void HelloVulkan::createPostDescriptor()
|
|
||||||
{
|
|
||||||
m_postDescSetLayoutBind.addBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
||||||
m_postDescSetLayout = m_postDescSetLayoutBind.createLayout(m_device);
|
|
||||||
m_postDescPool = m_postDescSetLayoutBind.createPool(m_device);
|
|
||||||
m_postDescSet = nvvk::allocateDescriptorSet(m_device, m_postDescPool, m_postDescSetLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Update the output
|
|
||||||
//
|
|
||||||
void HelloVulkan::updatePostDescriptorSet()
|
|
||||||
{
|
|
||||||
VkWriteDescriptorSet writeDescriptorSets = m_postDescSetLayoutBind.makeWrite(m_postDescSet, 0, &m_offscreenColor.descriptor);
|
|
||||||
vkUpdateDescriptorSets(m_device, 1, &writeDescriptorSets, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Draw a full screen quad with the attached image
|
|
||||||
//
|
|
||||||
void HelloVulkan::drawPost(VkCommandBuffer cmdBuf)
|
|
||||||
{
|
|
||||||
m_debug.beginLabel(cmdBuf, "Post");
|
|
||||||
|
|
||||||
setViewport(cmdBuf);
|
|
||||||
|
|
||||||
auto aspectRatio = static_cast<float>(m_size.width) / static_cast<float>(m_size.height);
|
|
||||||
vkCmdPushConstants(cmdBuf, m_postPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(float), &aspectRatio);
|
|
||||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_postPipelineLayout, 0, 1, &m_postDescSet, 0, nullptr);
|
|
||||||
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Initialize Vulkan ray tracing
|
|
||||||
// #VKRay
|
|
||||||
void HelloVulkan::initRayTracing()
|
|
||||||
{
|
|
||||||
// Requesting ray tracing properties
|
|
||||||
VkPhysicalDeviceProperties2 prop2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
|
||||||
prop2.pNext = &m_rtProperties;
|
|
||||||
vkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);
|
|
||||||
|
|
||||||
m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Convert an OBJ model into the ray tracing geometry used to build the BLAS
|
|
||||||
//
|
|
||||||
auto HelloVulkan::objectToVkGeometryKHR(const ObjModel& model)
|
|
||||||
{
|
|
||||||
// BLAS builder requires raw device addresses.
|
|
||||||
VkDeviceAddress vertexAddress = nvvk::getBufferDeviceAddress(m_device, model.vertexBuffer.buffer);
|
|
||||||
VkDeviceAddress indexAddress = nvvk::getBufferDeviceAddress(m_device, model.indexBuffer.buffer);
|
|
||||||
|
|
||||||
uint32_t maxPrimitiveCount = model.nbIndices / 3;
|
|
||||||
|
|
||||||
// Describe buffer as array of VertexObj.
|
|
||||||
VkAccelerationStructureGeometryTrianglesDataKHR triangles{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR};
|
|
||||||
triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; // vec3 vertex position data.
|
|
||||||
triangles.vertexData.deviceAddress = vertexAddress;
|
|
||||||
triangles.vertexStride = sizeof(VertexObj);
|
|
||||||
// Describe index data (32-bit unsigned int)
|
|
||||||
triangles.indexType = VK_INDEX_TYPE_UINT32;
|
|
||||||
triangles.indexData.deviceAddress = indexAddress;
|
|
||||||
// Indicate identity transform by setting transformData to null device pointer.
|
|
||||||
//triangles.transformData = {};
|
|
||||||
triangles.maxVertex = model.nbVertices - 1;
|
|
||||||
|
|
||||||
// Identify the above data as containing opaque triangles.
|
|
||||||
VkAccelerationStructureGeometryKHR asGeom{VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR};
|
|
||||||
asGeom.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
|
||||||
asGeom.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
|
||||||
asGeom.geometry.triangles = triangles;
|
|
||||||
|
|
||||||
// The entire array will be used to build the BLAS.
|
|
||||||
VkAccelerationStructureBuildRangeInfoKHR offset;
|
|
||||||
offset.firstVertex = 0;
|
|
||||||
offset.primitiveCount = maxPrimitiveCount;
|
|
||||||
offset.primitiveOffset = 0;
|
|
||||||
offset.transformOffset = 0;
|
|
||||||
|
|
||||||
// Our blas is made from only one geometry, but could be made of many geometries
|
|
||||||
nvvk::RaytracingBuilderKHR::BlasInput input;
|
|
||||||
input.asGeometry.emplace_back(asGeom);
|
|
||||||
input.asBuildOffsetInfo.emplace_back(offset);
|
|
||||||
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
void HelloVulkan::createBottomLevelAS()
|
|
||||||
{
|
|
||||||
// BLAS - Storing each primitive in a geometry
|
|
||||||
std::vector<nvvk::RaytracingBuilderKHR::BlasInput> allBlas;
|
|
||||||
allBlas.reserve(m_objModel.size());
|
|
||||||
for(const auto& obj : m_objModel)
|
|
||||||
{
|
|
||||||
auto blas = objectToVkGeometryKHR(obj);
|
|
||||||
|
|
||||||
// We could add more geometry in each BLAS, but we add only one for now
|
|
||||||
allBlas.emplace_back(blas);
|
|
||||||
}
|
|
||||||
m_rtBuilder.buildBlas(allBlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
//
|
|
||||||
void HelloVulkan::createTopLevelAS()
|
|
||||||
{
|
|
||||||
std::vector<VkAccelerationStructureInstanceKHR> tlas;
|
|
||||||
tlas.reserve(m_instances.size());
|
|
||||||
for(const HelloVulkan::ObjInstance& inst : m_instances)
|
|
||||||
{
|
|
||||||
VkAccelerationStructureInstanceKHR rayInst{};
|
|
||||||
rayInst.transform = nvvk::toTransformMatrixKHR(inst.transform); // Position of the instance
|
|
||||||
rayInst.instanceCustomIndex = inst.objIndex; // gl_InstanceCustomIndexEXT
|
|
||||||
rayInst.accelerationStructureReference = m_rtBuilder.getBlasDeviceAddress(inst.objIndex);
|
|
||||||
rayInst.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
|
||||||
rayInst.mask = 0xFF; // Only be hit if rayMask & instance.mask != 0
|
|
||||||
rayInst.instanceShaderBindingTableRecordOffset = 0; // We will use the same hit group for all objects
|
|
||||||
tlas.emplace_back(rayInst);
|
|
||||||
}
|
|
||||||
m_rtBuilder.buildTlas(tlas, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// This descriptor set holds the Acceleration structure and the output image
|
|
||||||
//
|
|
||||||
void HelloVulkan::createRtDescriptorSet()
|
|
||||||
{
|
|
||||||
// Top-level acceleration structure, usable by both the ray generation and the closest hit (to shoot shadow rays)
|
|
||||||
m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
|
|
||||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS
|
|
||||||
m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1,
|
|
||||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR); // Output image
|
|
||||||
|
|
||||||
m_rtDescPool = m_rtDescSetLayoutBind.createPool(m_device);
|
|
||||||
m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
|
|
||||||
|
|
||||||
VkDescriptorSetAllocateInfo allocateInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
|
||||||
allocateInfo.descriptorPool = m_rtDescPool;
|
|
||||||
allocateInfo.descriptorSetCount = 1;
|
|
||||||
allocateInfo.pSetLayouts = &m_rtDescSetLayout;
|
|
||||||
vkAllocateDescriptorSets(m_device, &allocateInfo, &m_rtDescSet);
|
|
||||||
|
|
||||||
|
|
||||||
VkAccelerationStructureKHR tlas = m_rtBuilder.getAccelerationStructure();
|
|
||||||
VkWriteDescriptorSetAccelerationStructureKHR descASInfo{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR};
|
|
||||||
descASInfo.accelerationStructureCount = 1;
|
|
||||||
descASInfo.pAccelerationStructures = &tlas;
|
|
||||||
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
|
|
||||||
|
|
||||||
std::vector<VkWriteDescriptorSet> writes;
|
|
||||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eTlas, &descASInfo));
|
|
||||||
writes.emplace_back(m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo));
|
|
||||||
vkUpdateDescriptorSets(m_device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Writes the output image to the descriptor set
|
|
||||||
// - Required when changing resolution
|
|
||||||
//
|
|
||||||
void HelloVulkan::updateRtDescriptorSet()
|
|
||||||
{
|
|
||||||
// (1) Output buffer
|
|
||||||
VkDescriptorImageInfo imageInfo{{}, m_offscreenColor.descriptor.imageView, VK_IMAGE_LAYOUT_GENERAL};
|
|
||||||
VkWriteDescriptorSet wds = m_rtDescSetLayoutBind.makeWrite(m_rtDescSet, RtxBindings::eOutImage, &imageInfo);
|
|
||||||
vkUpdateDescriptorSets(m_device, 1, &wds, 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Pipeline for the ray tracer: all shaders, raygen, chit, miss
|
|
||||||
//
|
|
||||||
void HelloVulkan::createRtPipeline()
|
|
||||||
{
|
|
||||||
enum StageIndices
|
|
||||||
{
|
|
||||||
eRaygen,
|
|
||||||
eMiss,
|
|
||||||
eMiss2,
|
|
||||||
eClosestHit,
|
|
||||||
eShaderGroupCount
|
|
||||||
};
|
|
||||||
|
|
||||||
// All stages
|
|
||||||
std::array<VkPipelineShaderStageCreateInfo, eShaderGroupCount> stages{};
|
|
||||||
VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
|
|
||||||
stage.pName = "main"; // All the same entry point
|
|
||||||
// Raygen
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rgen.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
|
||||||
stages[eRaygen] = stage;
|
|
||||||
// Miss
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rmiss.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
|
||||||
stages[eMiss] = stage;
|
|
||||||
// The second miss shader is invoked when a shadow ray misses the geometry. It simply indicates that no occlusion has been found
|
|
||||||
stage.module =
|
|
||||||
nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytraceShadow.rmiss.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
|
||||||
stages[eMiss2] = stage;
|
|
||||||
// Hit Group - Closest Hit
|
|
||||||
stage.module = nvvk::createShaderModule(m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
|
||||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
|
||||||
stages[eClosestHit] = stage;
|
|
||||||
|
|
||||||
|
|
||||||
// Shader groups
|
|
||||||
VkRayTracingShaderGroupCreateInfoKHR group{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR};
|
|
||||||
group.anyHitShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.closestHitShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.intersectionShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
|
|
||||||
// Raygen
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
|
||||||
group.generalShader = eRaygen;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
// Miss
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
|
||||||
group.generalShader = eMiss;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
// Shadow Miss
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
|
||||||
group.generalShader = eMiss2;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
// closest hit shader
|
|
||||||
group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
|
||||||
group.generalShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
group.closestHitShader = eClosestHit;
|
|
||||||
m_rtShaderGroups.push_back(group);
|
|
||||||
|
|
||||||
// Push constant: we want to be able to update constants used by the shaders
|
|
||||||
VkPushConstantRange pushConstant{VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
|
|
||||||
0, sizeof(PushConstantRay)};
|
|
||||||
|
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
||||||
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
|
|
||||||
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstant;
|
|
||||||
|
|
||||||
// Descriptor sets: one specific to ray tracing, and one shared with the rasterization pipeline
|
|
||||||
std::vector<VkDescriptorSetLayout> rtDescSetLayouts = {m_rtDescSetLayout, m_descSetLayout};
|
|
||||||
pipelineLayoutCreateInfo.setLayoutCount = static_cast<uint32_t>(rtDescSetLayouts.size());
|
|
||||||
pipelineLayoutCreateInfo.pSetLayouts = rtDescSetLayouts.data();
|
|
||||||
|
|
||||||
vkCreatePipelineLayout(m_device, &pipelineLayoutCreateInfo, nullptr, &m_rtPipelineLayout);
|
|
||||||
|
|
||||||
|
|
||||||
// Assemble the shader stages and recursion depth info into the ray tracing pipeline
|
|
||||||
VkRayTracingPipelineCreateInfoKHR rayPipelineInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
|
|
||||||
rayPipelineInfo.stageCount = static_cast<uint32_t>(stages.size()); // Stages are shaders
|
|
||||||
rayPipelineInfo.pStages = stages.data();
|
|
||||||
|
|
||||||
// In this case, m_rtShaderGroups.size() == 4: we have one raygen group,
|
|
||||||
// two miss shader groups, and one hit group.
|
|
||||||
rayPipelineInfo.groupCount = static_cast<uint32_t>(m_rtShaderGroups.size());
|
|
||||||
rayPipelineInfo.pGroups = m_rtShaderGroups.data();
|
|
||||||
|
|
||||||
// The ray tracing process can shoot rays from the camera, and a shadow ray can be shot from the
|
|
||||||
// hit points of the camera rays, hence a recursion level of 2. This number should be kept as low
|
|
||||||
// as possible for performance reasons. Even recursive ray tracing should be flattened into a loop
|
|
||||||
// in the ray generation to avoid deep recursion.
|
|
||||||
rayPipelineInfo.maxPipelineRayRecursionDepth = 2; // Ray depth
|
|
||||||
rayPipelineInfo.layout = m_rtPipelineLayout;
|
|
||||||
|
|
||||||
vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
|
|
||||||
|
|
||||||
|
|
||||||
// Spec only guarantees 1 level of "recursion". Check for that sad possibility here.
|
|
||||||
if(m_rtProperties.maxRayRecursionDepth <= 1)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Device fails to support ray recursion (m_rtProperties.maxRayRecursionDepth <= 1)");
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& s : stages)
|
|
||||||
vkDestroyShaderModule(m_device, s.module, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// The Shader Binding Table (SBT)
|
|
||||||
// - getting all shader handles and write them in a SBT buffer
|
|
||||||
// - Besides exception, this could be always done like this
|
|
||||||
//
|
|
||||||
void HelloVulkan::createRtShaderBindingTable()
|
|
||||||
{
|
|
||||||
uint32_t missCount{2};
|
|
||||||
uint32_t hitCount{1};
|
|
||||||
auto handleCount = 1 + missCount + hitCount;
|
|
||||||
uint32_t handleSize = m_rtProperties.shaderGroupHandleSize;
|
|
||||||
|
|
||||||
// The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned.
|
|
||||||
uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment);
|
|
||||||
|
|
||||||
m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment);
|
|
||||||
m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member
|
|
||||||
m_missRegion.stride = handleSizeAligned;
|
|
||||||
m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment);
|
|
||||||
m_hitRegion.stride = handleSizeAligned;
|
|
||||||
m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment);
|
|
||||||
|
|
||||||
// Get the shader group handles
|
|
||||||
uint32_t dataSize = handleCount * handleSize;
|
|
||||||
std::vector<uint8_t> handles(dataSize);
|
|
||||||
auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data());
|
|
||||||
assert(result == VK_SUCCESS);
|
|
||||||
|
|
||||||
// Allocate a buffer for storing the SBT.
|
|
||||||
VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size;
|
|
||||||
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize,
|
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
|
||||||
| VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
||||||
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight.
|
|
||||||
|
|
||||||
// Find the SBT addresses of each group
|
|
||||||
VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer};
|
|
||||||
VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info);
|
|
||||||
m_rgenRegion.deviceAddress = sbtAddress;
|
|
||||||
m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size;
|
|
||||||
m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size;
|
|
||||||
|
|
||||||
// Helper to retrieve the handle data
|
|
||||||
auto getHandle = [&](int i) { return handles.data() + i * handleSize; };
|
|
||||||
|
|
||||||
// Map the SBT buffer and write in the handles.
|
|
||||||
auto* pSBTBuffer = reinterpret_cast<uint8_t*>(m_alloc.map(m_rtSBTBuffer));
|
|
||||||
uint8_t* pData{nullptr};
|
|
||||||
uint32_t handleIdx{0};
|
|
||||||
// Raygen
|
|
||||||
pData = pSBTBuffer;
|
|
||||||
memcpy(pData, getHandle(handleIdx++), handleSize);
|
|
||||||
// Miss
|
|
||||||
pData = pSBTBuffer + m_rgenRegion.size;
|
|
||||||
for(uint32_t c = 0; c < missCount; c++)
|
|
||||||
{
|
|
||||||
memcpy(pData, getHandle(handleIdx++), handleSize);
|
|
||||||
pData += m_missRegion.stride;
|
|
||||||
}
|
|
||||||
// Hit
|
|
||||||
pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size;
|
|
||||||
for(uint32_t c = 0; c < hitCount; c++)
|
|
||||||
{
|
|
||||||
memcpy(pData, getHandle(handleIdx++), handleSize);
|
|
||||||
pData += m_hitRegion.stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_alloc.unmap(m_rtSBTBuffer);
|
|
||||||
m_alloc.finalizeAndReleaseStaging();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Ray Tracing the scene
|
|
||||||
//
|
|
||||||
void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor)
|
|
||||||
{
|
|
||||||
m_debug.beginLabel(cmdBuf, "Ray trace");
|
|
||||||
// Initializing push constant values
|
|
||||||
m_pcRay.clearColor = clearColor;
|
|
||||||
m_pcRay.lightPosition = m_pcRaster.lightPosition;
|
|
||||||
m_pcRay.lightIntensity = m_pcRaster.lightIntensity;
|
|
||||||
m_pcRay.lightType = m_pcRaster.lightType;
|
|
||||||
|
|
||||||
std::vector<VkDescriptorSet> descSets{m_rtDescSet, m_descSet};
|
|
||||||
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
|
|
||||||
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0,
|
|
||||||
(uint32_t)descSets.size(), descSets.data(), 0, nullptr);
|
|
||||||
vkCmdPushConstants(cmdBuf, m_rtPipelineLayout,
|
|
||||||
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
|
|
||||||
0, sizeof(PushConstantRay), &m_pcRay);
|
|
||||||
|
|
||||||
|
|
||||||
vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1);
|
|
||||||
|
|
||||||
|
|
||||||
m_debug.endLabel(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
@ -1,156 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "nvvkhl/appbase_vk.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
|
||||||
#include "nvvk/resourceallocator_vk.hpp"
|
|
||||||
#include "shaders/host_device.h"
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Simple rasterizer of OBJ objects
|
|
||||||
// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance`
|
|
||||||
// - It is possible to have many `ObjInstance` referencing the same `ObjModel`
|
|
||||||
// - Rendering is done in an offscreen framebuffer
|
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
|
||||||
//
|
|
||||||
class HelloVulkan : public nvvkhl::AppBaseVk
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
|
||||||
void createGraphicsPipeline();
|
|
||||||
void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1));
|
|
||||||
void updateDescriptorSet();
|
|
||||||
void createUniformBuffer();
|
|
||||||
void createObjDescriptionBuffer();
|
|
||||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
|
||||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
|
||||||
void destroyResources();
|
|
||||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
|
||||||
|
|
||||||
// The OBJ model
|
|
||||||
struct ObjModel
|
|
||||||
{
|
|
||||||
uint32_t nbIndices{0};
|
|
||||||
uint32_t nbVertices{0};
|
|
||||||
nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex'
|
|
||||||
nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles
|
|
||||||
nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material'
|
|
||||||
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ObjInstance
|
|
||||||
{
|
|
||||||
glm::mat4 transform; // Matrix of the instance
|
|
||||||
uint32_t objIndex{0}; // Model index reference
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Information pushed at each draw call
|
|
||||||
PushConstantRaster m_pcRaster{
|
|
||||||
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix
|
|
||||||
{10.f, 15.f, 8.f}, // light position
|
|
||||||
0, // instance Id
|
|
||||||
100.f, // light intensity
|
|
||||||
0 // light type
|
|
||||||
};
|
|
||||||
|
|
||||||
// Array of objects and instances in the scene
|
|
||||||
std::vector<ObjModel> m_objModel; // Model on host
|
|
||||||
std::vector<ObjDesc> m_objDesc; // Model description for device access
|
|
||||||
std::vector<ObjInstance> m_instances; // Scene model instances
|
|
||||||
|
|
||||||
|
|
||||||
// Graphic pipeline
|
|
||||||
VkPipelineLayout m_pipelineLayout;
|
|
||||||
VkPipeline m_graphicsPipeline;
|
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
|
||||||
VkDescriptorPool m_descPool;
|
|
||||||
VkDescriptorSetLayout m_descSetLayout;
|
|
||||||
VkDescriptorSet m_descSet;
|
|
||||||
|
|
||||||
nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
|
|
||||||
nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ descriptions
|
|
||||||
|
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
|
||||||
|
|
||||||
|
|
||||||
// #Post - Draw the rendered image on a quad using a tonemapper
|
|
||||||
void createOffscreenRender();
|
|
||||||
void createPostPipeline();
|
|
||||||
void createPostDescriptor();
|
|
||||||
void updatePostDescriptorSet();
|
|
||||||
void drawPost(VkCommandBuffer cmdBuf);
|
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
|
||||||
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
|
||||||
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
|
||||||
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
|
||||||
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
|
||||||
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
|
||||||
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
|
||||||
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
|
||||||
nvvk::Texture m_offscreenColor;
|
|
||||||
nvvk::Texture m_offscreenDepth;
|
|
||||||
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
|
||||||
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
void initRayTracing();
|
|
||||||
auto objectToVkGeometryKHR(const ObjModel& model);
|
|
||||||
void createBottomLevelAS();
|
|
||||||
void createTopLevelAS();
|
|
||||||
void createRtDescriptorSet();
|
|
||||||
void updateRtDescriptorSet();
|
|
||||||
void createRtPipeline();
|
|
||||||
void createRtShaderBindingTable();
|
|
||||||
void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor);
|
|
||||||
|
|
||||||
|
|
||||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
|
||||||
VkDescriptorPool m_rtDescPool;
|
|
||||||
VkDescriptorSetLayout m_rtDescSetLayout;
|
|
||||||
VkDescriptorSet m_rtDescSet;
|
|
||||||
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
|
||||||
VkPipelineLayout m_rtPipelineLayout;
|
|
||||||
VkPipeline m_rtPipeline;
|
|
||||||
|
|
||||||
nvvk::Buffer m_rtSBTBuffer;
|
|
||||||
VkStridedDeviceAddressRegionKHR m_rgenRegion{};
|
|
||||||
VkStridedDeviceAddressRegionKHR m_missRegion{};
|
|
||||||
VkStridedDeviceAddressRegionKHR m_hitRegion{};
|
|
||||||
VkStridedDeviceAddressRegionKHR m_callRegion{};
|
|
||||||
|
|
||||||
// Push constant for ray tracer
|
|
||||||
PushConstantRay m_pcRay{};
|
|
||||||
};
|
|
||||||
|
|
@ -1,293 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// ImGui - standalone example application for Glfw + Vulkan, using programmable
|
|
||||||
// pipeline If you are new to ImGui, see examples/README.txt and documentation
|
|
||||||
// at the top of imgui.cpp.
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
|
||||||
#include "backends/imgui_impl_vulkan.h"
|
|
||||||
#include "imgui.h"
|
|
||||||
#include "imgui/imgui_helper.h"
|
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
|
||||||
#include "imgui/imgui_camera_widget.h"
|
|
||||||
#include "nvh/cameramanipulator.hpp"
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvpsystem.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/context_vk.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
#define UNUSED(x) (void)(x)
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default search path for shaders
|
|
||||||
std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
|
||||||
static void onErrorCallback(int error, const char* description)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extra UI
|
|
||||||
void renderUI(HelloVulkan& helloVk)
|
|
||||||
{
|
|
||||||
ImGuiH::CameraWidget();
|
|
||||||
if(ImGui::CollapsingHeader("Light"))
|
|
||||||
{
|
|
||||||
ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1);
|
|
||||||
|
|
||||||
ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
|
|
||||||
ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Application Entry
|
|
||||||
//
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
UNUSED(argc);
|
|
||||||
|
|
||||||
// Setup GLFW window
|
|
||||||
glfwSetErrorCallback(onErrorCallback);
|
|
||||||
if(!glfwInit())
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
||||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
|
|
||||||
// Setup camera
|
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
||||||
CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0));
|
|
||||||
|
|
||||||
// Setup Vulkan
|
|
||||||
if(!glfwVulkanSupported())
|
|
||||||
{
|
|
||||||
printf("GLFW: Vulkan Not Supported\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup some basic things for the sample, logging file for example
|
|
||||||
NVPSystem system(PROJECT_NAME);
|
|
||||||
|
|
||||||
// Search path for shaders and other media
|
|
||||||
defaultSearchPaths = {
|
|
||||||
NVPSystem::exePath() + PROJECT_RELDIRECTORY,
|
|
||||||
NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
|
|
||||||
std::string(PROJECT_NAME),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Vulkan required extensions
|
|
||||||
assert(glfwVulkanSupported() == 1);
|
|
||||||
uint32_t count{0};
|
|
||||||
auto reqExtensions = glfwGetRequiredInstanceExtensions(&count);
|
|
||||||
|
|
||||||
// Requesting Vulkan extensions and layers
|
|
||||||
nvvk::ContextCreateInfo contextInfo;
|
|
||||||
contextInfo.setVersion(1, 2); // Using Vulkan 1.2
|
|
||||||
for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..)
|
|
||||||
contextInfo.addInstanceExtension(reqExtensions[ext_id]);
|
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering
|
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
|
||||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures
|
|
||||||
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline
|
|
||||||
|
|
||||||
// Creating Vulkan base application
|
|
||||||
nvvk::Context vkctx{};
|
|
||||||
vkctx.initInstance(contextInfo);
|
|
||||||
// Find all compatible devices
|
|
||||||
auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo);
|
|
||||||
assert(!compatibleDevices.empty());
|
|
||||||
// Use a compatible device
|
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
|
||||||
|
|
||||||
// Create example
|
|
||||||
HelloVulkan helloVk;
|
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
|
||||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
||||||
helloVk.createDepthBuffer();
|
|
||||||
helloVk.createRenderPass();
|
|
||||||
helloVk.createFrameBuffers();
|
|
||||||
|
|
||||||
// Setup Imgui
|
|
||||||
helloVk.initGUI(0); // Using sub-pass 0
|
|
||||||
|
|
||||||
// Creation of the example
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
|
||||||
|
|
||||||
helloVk.createOffscreenRender();
|
|
||||||
helloVk.createDescriptorSetLayout();
|
|
||||||
helloVk.createGraphicsPipeline();
|
|
||||||
helloVk.createUniformBuffer();
|
|
||||||
helloVk.createObjDescriptionBuffer();
|
|
||||||
helloVk.updateDescriptorSet();
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
helloVk.initRayTracing();
|
|
||||||
helloVk.createBottomLevelAS();
|
|
||||||
helloVk.createTopLevelAS();
|
|
||||||
helloVk.createRtDescriptorSet();
|
|
||||||
helloVk.createRtPipeline();
|
|
||||||
helloVk.createRtShaderBindingTable();
|
|
||||||
|
|
||||||
helloVk.createPostDescriptor();
|
|
||||||
helloVk.createPostPipeline();
|
|
||||||
helloVk.updatePostDescriptorSet();
|
|
||||||
|
|
||||||
|
|
||||||
glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f);
|
|
||||||
bool useRaytracer = true;
|
|
||||||
|
|
||||||
|
|
||||||
helloVk.setupGlfwCallbacks(window);
|
|
||||||
ImGui_ImplGlfw_InitForVulkan(window, true);
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
while(!glfwWindowShouldClose(window))
|
|
||||||
{
|
|
||||||
glfwPollEvents();
|
|
||||||
if(helloVk.isMinimized())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
|
||||||
ImGui_ImplGlfw_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
|
||||||
if(helloVk.showGui())
|
|
||||||
{
|
|
||||||
ImGuiH::Panel::Begin();
|
|
||||||
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
|
||||||
|
|
||||||
renderUI(helloVk);
|
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
|
||||||
ImGuiH::Panel::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start rendering the scene
|
|
||||||
helloVk.prepareFrame();
|
|
||||||
|
|
||||||
// Start command buffer of this frame
|
|
||||||
auto curFrame = helloVk.getCurFrame();
|
|
||||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
|
||||||
|
|
||||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
|
||||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
||||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
|
||||||
|
|
||||||
// Updating camera buffer
|
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
|
||||||
|
|
||||||
// Clearing screen
|
|
||||||
std::array<VkClearValue, 2> clearValues{};
|
|
||||||
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
|
||||||
clearValues[1].depthStencil = {1.0f, 0};
|
|
||||||
|
|
||||||
// Offscreen render pass
|
|
||||||
{
|
|
||||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
|
||||||
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
|
||||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
|
||||||
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
|
||||||
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
|
||||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
|
||||||
|
|
||||||
// Rendering Scene
|
|
||||||
if(useRaytracer)
|
|
||||||
{
|
|
||||||
helloVk.raytrace(cmdBuf, clearColor);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
helloVk.rasterize(cmdBuf);
|
|
||||||
vkCmdEndRenderPass(cmdBuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
|
||||||
{
|
|
||||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
|
||||||
postRenderPassBeginInfo.clearValueCount = 2;
|
|
||||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
|
||||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
|
||||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
|
||||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
|
||||||
|
|
||||||
// Rendering tonemapper
|
|
||||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
helloVk.drawPost(cmdBuf);
|
|
||||||
// Rendering UI
|
|
||||||
ImGui::Render();
|
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
|
||||||
vkCmdEndRenderPass(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit for display
|
|
||||||
vkEndCommandBuffer(cmdBuf);
|
|
||||||
helloVk.submitFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
vkDeviceWaitIdle(helloVk.getDevice());
|
|
||||||
|
|
||||||
helloVk.destroyResources();
|
|
||||||
helloVk.destroy();
|
|
||||||
vkctx.deinit();
|
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
|
||||||
glfwTerminate();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRaster
|
|
||||||
{
|
|
||||||
PushConstantRaster pcRaster;
|
|
||||||
};
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
// Incoming
|
|
||||||
layout(location = 1) in vec3 i_worldPos;
|
|
||||||
layout(location = 2) in vec3 i_worldNrm;
|
|
||||||
layout(location = 3) in vec3 i_viewDir;
|
|
||||||
layout(location = 4) in vec2 i_texCoord;
|
|
||||||
// Outgoing
|
|
||||||
layout(location = 0) out vec4 o_color;
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
|
|
||||||
layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
layout(binding = eTextures) uniform sampler2D[] textureSamplers;
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Material of the object
|
|
||||||
ObjDesc objResource = objDesc.i[pcRaster.objIndex];
|
|
||||||
MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
|
|
||||||
int matIndex = matIndices.i[gl_PrimitiveID];
|
|
||||||
WaveFrontMaterial mat = materials.m[matIndex];
|
|
||||||
|
|
||||||
vec3 N = normalize(i_worldNrm);
|
|
||||||
|
|
||||||
// Vector toward light
|
|
||||||
vec3 L;
|
|
||||||
float lightIntensity = pcRaster.lightIntensity;
|
|
||||||
if(pcRaster.lightType == 0)
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRaster.lightPosition - i_worldPos;
|
|
||||||
float d = length(lDir);
|
|
||||||
lightIntensity = pcRaster.lightIntensity / (d * d);
|
|
||||||
L = normalize(lDir);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
L = normalize(pcRaster.lightPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Diffuse
|
|
||||||
vec3 diffuse = computeDiffuse(mat, L, N);
|
|
||||||
if(mat.textureId >= 0)
|
|
||||||
{
|
|
||||||
int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
|
|
||||||
uint txtId = txtOffset + mat.textureId;
|
|
||||||
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
|
|
||||||
diffuse *= diffuseTxt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specular
|
|
||||||
vec3 specular = computeSpecular(mat, i_viewDir, L, N);
|
|
||||||
|
|
||||||
// Result
|
|
||||||
o_color = vec4(lightIntensity * (diffuse + specular), 1);
|
|
||||||
}
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef COMMON_HOST_DEVICE
|
|
||||||
#define COMMON_HOST_DEVICE
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
// GLSL Type
|
|
||||||
using vec2 = glm::vec2;
|
|
||||||
using vec3 = glm::vec3;
|
|
||||||
using vec4 = glm::vec4;
|
|
||||||
using mat4 = glm::mat4;
|
|
||||||
using uint = unsigned int;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
|
|
||||||
#define START_BINDING(a) enum a {
|
|
||||||
#define END_BINDING() }
|
|
||||||
#else
|
|
||||||
#define START_BINDING(a) const uint
|
|
||||||
#define END_BINDING()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
START_BINDING(SceneBindings)
|
|
||||||
eGlobals = 0, // Global uniform containing camera matrices
|
|
||||||
eObjDescs = 1, // Access to the object descriptions
|
|
||||||
eTextures = 2 // Access to textures
|
|
||||||
END_BINDING();
|
|
||||||
|
|
||||||
START_BINDING(RtxBindings)
|
|
||||||
eTlas = 0, // Top-level acceleration structure
|
|
||||||
eOutImage = 1 // Ray tracer output image
|
|
||||||
END_BINDING();
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
// Information of a obj model when referenced in a shader
|
|
||||||
struct ObjDesc
|
|
||||||
{
|
|
||||||
int txtOffset; // Texture index offset in the array of textures
|
|
||||||
uint64_t vertexAddress; // Address of the Vertex buffer
|
|
||||||
uint64_t indexAddress; // Address of the index buffer
|
|
||||||
uint64_t materialAddress; // Address of the material buffer
|
|
||||||
uint64_t materialIndexAddress; // Address of the triangle material index buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
// Uniform buffer set at each frame
|
|
||||||
struct GlobalUniforms
|
|
||||||
{
|
|
||||||
mat4 viewProj; // Camera view * projection
|
|
||||||
mat4 viewInverse; // Camera inverse view matrix
|
|
||||||
mat4 projInverse; // Camera inverse projection matrix
|
|
||||||
};
|
|
||||||
|
|
||||||
// Push constant structure for the raster
|
|
||||||
struct PushConstantRaster
|
|
||||||
{
|
|
||||||
mat4 modelMatrix; // matrix of the instance
|
|
||||||
vec3 lightPosition;
|
|
||||||
uint objIndex;
|
|
||||||
float lightIntensity;
|
|
||||||
int lightType;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Push constant structure for the ray tracer
|
|
||||||
struct PushConstantRay
|
|
||||||
{
|
|
||||||
vec4 clearColor;
|
|
||||||
vec3 lightPosition;
|
|
||||||
float lightIntensity;
|
|
||||||
int lightType;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
|
|
||||||
{
|
|
||||||
vec3 pos;
|
|
||||||
vec3 nrm;
|
|
||||||
vec3 color;
|
|
||||||
vec2 texCoord;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
|
|
||||||
{
|
|
||||||
vec3 ambient;
|
|
||||||
vec3 diffuse;
|
|
||||||
vec3 specular;
|
|
||||||
vec3 transmittance;
|
|
||||||
vec3 emission;
|
|
||||||
float shininess;
|
|
||||||
float ior; // index of refraction
|
|
||||||
float dissolve; // 1 == opaque; 0 == fully transparent
|
|
||||||
int illum; // illumination model (see http://www.fileformat.info/format/material/)
|
|
||||||
int textureId;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(location = 0) out vec2 outUV;
|
|
||||||
|
|
||||||
|
|
||||||
out gl_PerVertex
|
|
||||||
{
|
|
||||||
vec4 gl_Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
|
||||||
gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(location = 0) in vec2 outUV;
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform sampler2D noisyTxt;
|
|
||||||
|
|
||||||
layout(push_constant) uniform shaderInformation
|
|
||||||
{
|
|
||||||
float aspectRatio;
|
|
||||||
}
|
|
||||||
pushc;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec2 uv = outUV;
|
|
||||||
float gamma = 1. / 2.2;
|
|
||||||
fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma));
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitValue;
|
|
||||||
};
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
hitAttributeEXT vec2 attribs;
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
|
||||||
layout(location = 1) rayPayloadEXT bool isShadowed;
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
|
|
||||||
layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[];
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Object data
|
|
||||||
ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
|
|
||||||
MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
Indices indices = Indices(objResource.indexAddress);
|
|
||||||
Vertices vertices = Vertices(objResource.vertexAddress);
|
|
||||||
|
|
||||||
// Indices of the triangle
|
|
||||||
ivec3 ind = indices.i[gl_PrimitiveID];
|
|
||||||
|
|
||||||
// Vertex of the triangle
|
|
||||||
Vertex v0 = vertices.v[ind.x];
|
|
||||||
Vertex v1 = vertices.v[ind.y];
|
|
||||||
Vertex v2 = vertices.v[ind.z];
|
|
||||||
|
|
||||||
const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
|
|
||||||
|
|
||||||
// Computing the coordinates of the hit position
|
|
||||||
const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
|
|
||||||
const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space
|
|
||||||
|
|
||||||
// Computing the normal at hit position
|
|
||||||
const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
|
|
||||||
const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space
|
|
||||||
|
|
||||||
// Vector toward the light
|
|
||||||
vec3 L;
|
|
||||||
float lightIntensity = pcRay.lightIntensity;
|
|
||||||
float lightDistance = 100000.0;
|
|
||||||
// Point light
|
|
||||||
if(pcRay.lightType == 0)
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRay.lightPosition - worldPos;
|
|
||||||
lightDistance = length(lDir);
|
|
||||||
lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance);
|
|
||||||
L = normalize(lDir);
|
|
||||||
}
|
|
||||||
else // Directional light
|
|
||||||
{
|
|
||||||
L = normalize(pcRay.lightPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Material of the object
|
|
||||||
int matIdx = matIndices.i[gl_PrimitiveID];
|
|
||||||
WaveFrontMaterial mat = materials.m[matIdx];
|
|
||||||
|
|
||||||
|
|
||||||
// Diffuse
|
|
||||||
vec3 diffuse = computeDiffuse(mat, L, worldNrm);
|
|
||||||
if(mat.textureId >= 0)
|
|
||||||
{
|
|
||||||
uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
|
|
||||||
vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
|
|
||||||
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 specular = vec3(0);
|
|
||||||
float attenuation = 1;
|
|
||||||
|
|
||||||
// Tracing shadow ray only if the light is visible from the surface
|
|
||||||
if(dot(worldNrm, L) > 0)
|
|
||||||
{
|
|
||||||
float tMin = 0.001;
|
|
||||||
float tMax = lightDistance;
|
|
||||||
vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
|
|
||||||
vec3 rayDir = L;
|
|
||||||
uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT;
|
|
||||||
isShadowed = true;
|
|
||||||
traceRayEXT(topLevelAS, // acceleration structure
|
|
||||||
flags, // rayFlags
|
|
||||||
0xFF, // cullMask
|
|
||||||
0, // sbtRecordOffset
|
|
||||||
0, // sbtRecordStride
|
|
||||||
1, // missIndex
|
|
||||||
origin, // ray origin
|
|
||||||
tMin, // ray min range
|
|
||||||
rayDir, // ray direction
|
|
||||||
tMax, // ray max range
|
|
||||||
1 // payload (location = 1)
|
|
||||||
);
|
|
||||||
|
|
||||||
if(isShadowed)
|
|
||||||
{
|
|
||||||
attenuation = 0.3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Specular
|
|
||||||
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular));
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "host_device.h"
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
layout(location = 0) rayPayloadEXT hitPayload prd;
|
|
||||||
|
|
||||||
layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
|
|
||||||
layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image;
|
|
||||||
layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; };
|
|
||||||
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
|
|
||||||
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
|
|
||||||
vec2 d = inUV * 2.0 - 1.0;
|
|
||||||
|
|
||||||
vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1);
|
|
||||||
vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1);
|
|
||||||
vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0);
|
|
||||||
|
|
||||||
uint rayFlags = gl_RayFlagsOpaqueEXT;
|
|
||||||
float tMin = 0.001;
|
|
||||||
float tMax = 10000.0;
|
|
||||||
|
|
||||||
traceRayEXT(topLevelAS, // acceleration structure
|
|
||||||
rayFlags, // rayFlags
|
|
||||||
0xFF, // cullMask
|
|
||||||
0, // sbtRecordOffset
|
|
||||||
0, // sbtRecordStride
|
|
||||||
0, // missIndex
|
|
||||||
origin.xyz, // ray origin
|
|
||||||
tMin, // ray min range
|
|
||||||
direction.xyz, // ray direction
|
|
||||||
tMax, // ray max range
|
|
||||||
0 // payload (location = 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0));
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay
|
|
||||||
{
|
|
||||||
PushConstantRay pcRay;
|
|
||||||
};
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
prd.hitValue = pcRay.clearColor.xyz * 0.8;
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
layout(location = 1) rayPayloadInEXT bool isShadowed;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
isShadowed = false;
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
layout(binding = 0) uniform _GlobalUniforms
|
|
||||||
{
|
|
||||||
GlobalUniforms uni;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRaster
|
|
||||||
{
|
|
||||||
PushConstantRaster pcRaster;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 i_position;
|
|
||||||
layout(location = 1) in vec3 i_normal;
|
|
||||||
layout(location = 2) in vec3 i_color;
|
|
||||||
layout(location = 3) in vec2 i_texCoord;
|
|
||||||
|
|
||||||
|
|
||||||
layout(location = 1) out vec3 o_worldPos;
|
|
||||||
layout(location = 2) out vec3 o_worldNrm;
|
|
||||||
layout(location = 3) out vec3 o_viewDir;
|
|
||||||
layout(location = 4) out vec2 o_texCoord;
|
|
||||||
|
|
||||||
out gl_PerVertex
|
|
||||||
{
|
|
||||||
vec4 gl_Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
|
|
||||||
|
|
||||||
o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
|
|
||||||
o_viewDir = vec3(o_worldPos - origin);
|
|
||||||
o_texCoord = i_texCoord;
|
|
||||||
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
|
|
||||||
|
|
||||||
gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "host_device.h"
|
|
||||||
|
|
||||||
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
|
|
||||||
{
|
|
||||||
// Lambertian
|
|
||||||
float dotNL = max(dot(normal, lightDir), 0.0);
|
|
||||||
vec3 c = mat.diffuse * dotNL;
|
|
||||||
if(mat.illum >= 1)
|
|
||||||
c += mat.ambient;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal)
|
|
||||||
{
|
|
||||||
if(mat.illum < 2)
|
|
||||||
return vec3(0);
|
|
||||||
|
|
||||||
// Compute specular only if not in shadow
|
|
||||||
const float kPi = 3.14159265;
|
|
||||||
const float kShininess = max(mat.shininess, 4.0);
|
|
||||||
|
|
||||||
// Specular
|
|
||||||
const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi);
|
|
||||||
vec3 V = normalize(-viewDir);
|
|
||||||
vec3 R = reflect(-lightDir, normal);
|
|
||||||
float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess);
|
|
||||||
|
|
||||||
return vec3(mat.specular * specular);
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
#*****************************************************************************
|
|
||||||
# Copyright 2020 NVIDIA Corporation. All rights reserved.
|
|
||||||
#*****************************************************************************
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Project setting
|
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
|
||||||
message(STATUS "-------------------------------")
|
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# C++ target and defines
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
add_executable(${PROJNAME})
|
|
||||||
_add_project_definitions(${PROJNAME})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Source files for this project
|
|
||||||
#
|
|
||||||
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
|
|
||||||
file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
|
|
||||||
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
|
||||||
include_directories(${TUTO_KHR_DIR}/common)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# GLSL to SPIR-V custom build
|
|
||||||
compile_glsl_directory(
|
|
||||||
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
|
|
||||||
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
|
|
||||||
VULKAN_TARGET "vulkan1.2"
|
|
||||||
DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sources
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sub-folders in Visual Studio
|
|
||||||
#
|
|
||||||
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
|
|
||||||
source_group("Sources" FILES ${SOURCE_FILES})
|
|
||||||
source_group("Headers" FILES ${HEADER_FILES})
|
|
||||||
source_group("Shader Sources" FILES ${GLSL_SOURCES})
|
|
||||||
source_group("Shader Headers" FILES ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Linkage
|
|
||||||
#
|
|
||||||
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core)
|
|
||||||
|
|
||||||
foreach(DEBUGLIB ${LIBRARIES_DEBUG})
|
|
||||||
target_link_libraries(${PROJNAME} debug ${DEBUGLIB})
|
|
||||||
endforeach(DEBUGLIB)
|
|
||||||
|
|
||||||
foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
|
|
||||||
target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
|
|
||||||
endforeach(RELEASELIB)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# copies binaries that need to be put next to the exe files (ZLib, etc.)
|
|
||||||
#
|
|
||||||
_finalize_target( ${PROJNAME} )
|
|
||||||
|
|
||||||
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
|
||||||
|
|
@ -1,277 +0,0 @@
|
||||||
# Advanced Compilation
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
The simplest way of defining ray tracing pipelines is by using monolithic `VkRayTracingPipelineCreateInfoKHR` structures specifying the pipeline stages and shader groups. Even if pipelines share some stages, they are compiled separately. Furthermore, by default `vkCreateRayTracingPipelinesKHR` blocks the current thread until completion:
|
|
||||||

|
|
||||||
|
|
||||||
However, when using multiple pipelines, some of them may have some shader stages in common. Large pipelines may also take a long time to compile on a single thread.
|
|
||||||
|
|
||||||
This sample introduces the [VK_KHR_pipeline_library](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_library.html) extension to create shader libraries that can be separately compiled and reused in ray tracing pipelines. The compilation of the final pipeline is carried out on multiple threads using the [VK_KHR_deferred_host_operations](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_deferred_host_operations.html) extension.
|
|
||||||
|
|
||||||
The code below is based on the [`ray_tracing_specialization`](../ray_tracing_specialization) sample, which introduces compile-time variations of a hit shader.
|
|
||||||
|
|
||||||
## Pipeline Library
|
|
||||||
|
|
||||||
Using monolithic pipeline definitions all stages are compiled for each pipeline, regardless of potential reuse. The shader groups are then referenced in the Shader Binding Table using their indices:
|
|
||||||

|
|
||||||
|
|
||||||
Pipeline libraries are `VkPipeline` objects that cannot be bound directly. Instead, they can be compiled once and linked into as many pipelines as necessary. The Shader Binding Table of the resulting pipeline references the shader groups of the library as if they had been appended to the groups and stages in the main `VkRayTracingPipelineCreateInfo`
|
|
||||||

|
|
||||||
|
|
||||||
We start by adding the device extension in main()
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Following by adding a new member in the `HelloVulkan` class:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Ray tracing shader library
|
|
||||||
VkPipeline m_rtShaderLibrary;
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
In `HelloVulkan::createRtPipeline()` the `StageIndices` enumeration describes the indices of the stages defined in the pipeline creation structure. The hit groups will be moved to our library, hence we remove them from the enumeration:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
enum StageIndices
|
|
||||||
{
|
|
||||||
eRaygen,
|
|
||||||
eMiss,
|
|
||||||
eMiss2,
|
|
||||||
eShaderGroupCount
|
|
||||||
};
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
The shader modules will be referenced partly in the main pipeline, and partly in the pipeline library. To ensure proper deletion of the modules after use, we will store their handles in
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Store the created modules for later cleanup
|
|
||||||
std::vector<VkShaderModule> modules;
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Then, after each call to `nvvk::createShaderModule` we store the resulting module:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
modules.push_back(stage.module);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
The specialization constants sample creates one shader module per specialization. Instead, we load that module once and reuse it for each specialization. Those specializations are then stored in the stages of the pipeline library:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Hit Group - Closest Hit
|
|
||||||
// Create many variation of the closest hit
|
|
||||||
stage.module = nvvk::createShaderModule(
|
|
||||||
m_device, nvh::loadFile("spv/raytrace.rchit.spv", true, defaultSearchPaths, true));
|
|
||||||
|
|
||||||
modules.push_back(stage.module);
|
|
||||||
// Store the hit groups for compilation in a separate pipeline library object
|
|
||||||
std::vector<VkPipelineShaderStageCreateInfo> libraryStages{};
|
|
||||||
for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++)
|
|
||||||
{
|
|
||||||
stage.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
|
||||||
stage.pSpecializationInfo = specializations[s].getSpecialization();
|
|
||||||
libraryStages.push_back(stage);
|
|
||||||
}
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Similarly, the hit groups will be stored in the library by replacing the storage of the hit groups in `m_rtShaderGroups` by:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Shader groups for the pipeline library containing the closest hit shaders
|
|
||||||
std::vector<VkRayTracingShaderGroupCreateInfoKHR> libraryShaderGroups;
|
|
||||||
|
|
||||||
VkRayTracingShaderGroupCreateInfoKHR libraryGroup{VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR};
|
|
||||||
libraryGroup.anyHitShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
libraryGroup.closestHitShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
libraryGroup.generalShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
libraryGroup.intersectionShader = VK_SHADER_UNUSED_KHR;
|
|
||||||
libraryGroup.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
|
||||||
|
|
||||||
// Hit Group - Closest Hit + AnyHit
|
|
||||||
// Creating many Hit groups, one for each specialization
|
|
||||||
for(uint32_t s = 0; s < (uint32_t)specializations.size(); s++)
|
|
||||||
{
|
|
||||||
// The indices of the stages are local to the pipeline library
|
|
||||||
libraryGroup.closestHitShader = s; // Using variation of the closest hit
|
|
||||||
libraryShaderGroups.push_back(libraryGroup);
|
|
||||||
}
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
It is important to note that the stage indices are local to the pipeline library, regardless of where they will be used in the final pipeline. Those indices will be later offset depending on the contents of the pipeline.
|
|
||||||
|
|
||||||
Once the groups and stages are defined we can create the pipeline library. After the creation of the ray tracing pipeline layout, we define the base of the library creation information:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Creation of the pipeline library object
|
|
||||||
VkRayTracingPipelineCreateInfoKHR pipelineLibraryInfo{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
|
|
||||||
// Flag the object as a pipeline library, which is a specific object that cannot be used directly.
|
|
||||||
pipelineLibraryInfo.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
|
|
||||||
// Use the same layout as the target pipeline
|
|
||||||
pipelineLibraryInfo.layout = m_rtPipelineLayout;
|
|
||||||
// As for the interface the maximum recursion depth must also be consistent across the pipeline
|
|
||||||
pipelineLibraryInfo.maxPipelineRayRecursionDepth = 2;
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Pipeline libraries are technically independent from the pipeline they will be linked into. However, linking can only be achieved by enforcing strong consistency constraints, such as having the same pipeline layout and maximum recursion depth. If the recursion depth differs the compilation of the final pipeline will fail.
|
|
||||||
|
|
||||||
In addition, the pipeline libraries need to have the same pipeline interface. This interface defines the maximum amount of data passed across stages:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Pipeline libraries need to define an interface, defined by the maximum hit attribute size (typically 2 for
|
|
||||||
// the built-in triangle intersector) and the maximum payload size (3 floating-point values in this sample).
|
|
||||||
// Pipeline libraries can be linked into a final pipeline only if their interface matches
|
|
||||||
VkRayTracingPipelineInterfaceCreateInfoKHR pipelineInterface{VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR};
|
|
||||||
pipelineInterface.maxPipelineRayHitAttributeSize = sizeof(glm::vec2);
|
|
||||||
pipelineInterface.maxPipelineRayPayloadSize = sizeof(glm::vec3);
|
|
||||||
pipelineLibraryInfo.pLibraryInterface = &pipelineInterface;
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Finally we provide the stage and shader groups information to the library creation information, and create the pipeline library in the same way as any other pipeline:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Shader groups and stages for the library
|
|
||||||
pipelineLibraryInfo.groupCount = static_cast<uint32_t>(libraryShaderGroups.size());
|
|
||||||
pipelineLibraryInfo.pGroups = libraryShaderGroups.data();
|
|
||||||
pipelineLibraryInfo.stageCount = static_cast<uint32_t>(libraryStages.size());
|
|
||||||
pipelineLibraryInfo.pStages = libraryStages.data();
|
|
||||||
|
|
||||||
// Creation of the pipeline library
|
|
||||||
vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &pipelineLibraryInfo, nullptr, &m_rtShaderLibrary);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
The pipeline library is now created, but the application cannot run yet: we still need to indicate that the final pipeline will link with our library. Before calling `vkCreateRayTracingPipelinesKHR` for the final pipeline, we insert the reference to the library:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// The library will be linked into the final pipeline by specifying its handle and shared interface
|
|
||||||
VkPipelineLibraryCreateInfoKHR inputLibrary{VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR};
|
|
||||||
inputLibrary.libraryCount = 1;
|
|
||||||
inputLibrary.pLibraries = &m_rtShaderLibrary;
|
|
||||||
rayPipelineInfo.pLibraryInfo = &inputLibrary;
|
|
||||||
rayPipelineInfo.pLibraryInterface = &pipelineInterface;
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
The pipeline is now built from the specified shader groups and stages as well as the library containing the hit groups. The groups and stages are linked together using indices, and indices are local to each library. To avoid collisions the pipeline creation will consider the stages of the libraries as if they had been appended to the stage list of the original `VkRayTracingPipelineCreateInfoKHR`, in the order in which the libraries are defined in `pLibraries`.
|
|
||||||
|
|
||||||
Therefore, the Shader Binding Table needs to be updated accordingly, by making the wrapper aware of the contents of the library:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// The Shader Binding Table is built accounting for the entire pipeline, including the
|
|
||||||
// stages contained in the library. Passing the library information allows the wrapper
|
|
||||||
// to shift the shader group indices accordingly
|
|
||||||
m_sbtWrapper.create(m_rtPipeline, rayPipelineInfo, {pipelineLibraryInfo});
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
At the end of the function we destroy the shader modules using our vector of modules instead of iterating over the stages of the main pipeline:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Destroy all the created modules, for both libraries and main pipeline
|
|
||||||
for(auto& m : modules)
|
|
||||||
vkDestroyShaderModule(m_device, m, nullptr);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
The pipeline library has the same lifetime as the pipeline that uses it. The final step of this Section is the destruction of the library in the `HelloVulkan::destroy()` method:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Pipeline libraries have the same lifetime as the pipelines that uses them
|
|
||||||
vkDestroyPipeline(m_device, m_rtShaderLibrary, nullptr);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
As an exercise, it is possible to create another library containing the other shader stages, and link those libraries together into the pipeline.
|
|
||||||
|
|
||||||
## Parallel Compilation Using Deferred Host Operations
|
|
||||||
|
|
||||||
By default pipelines compilations are blocking the calling thread until completion:
|
|
||||||

|
|
||||||
|
|
||||||
Ray tracing pipelines are often complex, and can benefit from multithreaded compilation. This can drastically reduce the compilation times of complex pipelines. The deferred host operations extension allows the work involved in `vkCreateRayTracingPipelinesKHR` to be split into multiple threads provided by the application:
|
|
||||||

|
|
||||||
|
|
||||||
We start by including the support of C++ threading using `std::async` at the beginning of the source file:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
#include <future>
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
In this sample we will distribute the compilation of the final ray tracing pipeline using a `VkDeferredOperation`, created just before calling `vkCreateRayTracingPipelinesKHR`:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Deferred operations allow the driver to parallelize the pipeline compilation on several threads
|
|
||||||
// Create a deferred operation
|
|
||||||
VkDeferredOperationKHR deferredOperation;
|
|
||||||
VkResult result = vkCreateDeferredOperationKHR(m_device, nullptr, &deferredOperation);
|
|
||||||
assert(result == VK_SUCCESS);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Then we modify the pipeline creation to indicate we defer the operation:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// The pipeline creation is called with the deferred operation. Instead of blocking until
|
|
||||||
// the compilation is done, the call returns immediately
|
|
||||||
vkCreateRayTracingPipelinesKHR(m_device, deferredOperation, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Instead of immediately launching the compilation and blocking execution until completion, this call will return immediately with value `VK_OPERATION_DEFERRED_KHR` if deferred operations are supported by the system.
|
|
||||||
|
|
||||||
Threading control is left to the application. Therefore, our application will allocate a number of threads for compilation:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// The compilation will be split into a maximum of 8 threads, or the maximum supported by the
|
|
||||||
// driver for that operation
|
|
||||||
uint32_t maxThreads{8};
|
|
||||||
uint32_t threadCount = std::min(vkGetDeferredOperationMaxConcurrencyKHR(m_device, deferredOperation), maxThreads);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
We then launch those threads using `std::async`:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
std::vector<std::future<void>> joins;
|
|
||||||
for(uint32_t i = 0; i < threadCount; i++)
|
|
||||||
{
|
|
||||||
VkDevice device{m_device};
|
|
||||||
joins.emplace_back(std::async(std::launch::async, [device, deferredOperation]() {
|
|
||||||
// Wait until the thread has finished its work
|
|
||||||
VkResult result = vkDeferredOperationJoinKHR(device, deferredOperation);
|
|
||||||
// A return value of SUCCESS means the pipeline compilation is done.
|
|
||||||
// THREAD_DONE indicates that thread has no work to do for this task
|
|
||||||
// (e.g. the operation could not be split into that many threads)
|
|
||||||
// THREAD_IDLE indicates the thread has finished its task, but the overall pipeline
|
|
||||||
// compilation is not finished.
|
|
||||||
// In the last two cases, more work could be performed by the thread, such as waiting
|
|
||||||
// for another deferred operation
|
|
||||||
assert(result == VK_SUCCESS || result == VK_THREAD_DONE_KHR || result == VK_THREAD_IDLE_KHR);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Each thread executes a blocking function taking care of a subset of the compilation. When a thread has finished its task, the pipeline compilation may be complete (`VK_SUCCESS`) or there may be no more work for this thread. In this case one could consider executing more work using those threads, such as compiling another pipeline.
|
|
||||||
|
|
||||||
Since there is only one pipeline to compile, we wait for all threads to finish and check whether the pipeline compilation succeeded:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Wait for all threads to finish
|
|
||||||
for(auto& f : joins)
|
|
||||||
{
|
|
||||||
f.get();
|
|
||||||
}
|
|
||||||
// Once the deferred operation is complete, check for compilation success
|
|
||||||
result = vkGetDeferredOperationResultKHR(m_device, deferredOperation);
|
|
||||||
assert(result == VK_SUCCESS);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Once the compilation is finished we can destroy the deferred operation:
|
|
||||||
|
|
||||||
~~~~ C
|
|
||||||
// Destroy the deferred operation
|
|
||||||
vkDestroyDeferredOperationKHR(m_device, deferredOperation, nullptr);
|
|
||||||
~~~~
|
|
||||||
|
|
||||||
Congratulations! The ray tracing pipeline is now built using explicit stages and a pipeline library, and the final compilation is executed on multiple threads. As an exercise, the pipeline library described at the beginning of this tutorial can also be compiled in parallel.
|
|
||||||
This approach can be extended to compile multiple pipelines sharing some components using multiple threads:
|
|
||||||

|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
* [VK_KHR_pipeline_library](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_library.html)
|
|
||||||
* [VK_KHR_deferred_host_operations](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_deferred_host_operations.html)
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "nvvkhl/appbase_vk.hpp"
|
|
||||||
#include "nvvk/debug_util_vk.hpp"
|
|
||||||
#include "nvvk/descriptorsets_vk.hpp"
|
|
||||||
#include "nvvk/memallocator_dma_vk.hpp"
|
|
||||||
#include "nvvk/resourceallocator_vk.hpp"
|
|
||||||
#include "shaders/host_device.h"
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
#include "nvvk/raytraceKHR_vk.hpp"
|
|
||||||
#include "nvvk/sbtwrapper_vk.hpp"
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Simple rasterizer of OBJ objects
|
|
||||||
// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance`
|
|
||||||
// - It is possible to have many `ObjInstance` referencing the same `ObjModel`
|
|
||||||
// - Rendering is done in an offscreen framebuffer
|
|
||||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
|
||||||
//
|
|
||||||
class HelloVulkan : public nvvkhl::AppBaseVk
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void setup(const VkInstance& instance, const VkDevice& device, const VkPhysicalDevice& physicalDevice, uint32_t queueFamily) override;
|
|
||||||
void createDescriptorSetLayout();
|
|
||||||
void createGraphicsPipeline();
|
|
||||||
void loadModel(const std::string& filename, glm::mat4 transform = glm::mat4(1));
|
|
||||||
void updateDescriptorSet();
|
|
||||||
void createUniformBuffer();
|
|
||||||
void createObjDescriptionBuffer();
|
|
||||||
void createTextureImages(const VkCommandBuffer& cmdBuf, const std::vector<std::string>& textures);
|
|
||||||
void updateUniformBuffer(const VkCommandBuffer& cmdBuf);
|
|
||||||
void onResize(int /*w*/, int /*h*/) override;
|
|
||||||
void destroyResources();
|
|
||||||
void rasterize(const VkCommandBuffer& cmdBuff);
|
|
||||||
|
|
||||||
// The OBJ model
|
|
||||||
struct ObjModel
|
|
||||||
{
|
|
||||||
uint32_t nbIndices{0};
|
|
||||||
uint32_t nbVertices{0};
|
|
||||||
nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex'
|
|
||||||
nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles
|
|
||||||
nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material'
|
|
||||||
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ObjInstance
|
|
||||||
{
|
|
||||||
glm::mat4 transform; // Matrix of the instance
|
|
||||||
uint32_t objIndex{0}; // Model index reference
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Information pushed at each draw call
|
|
||||||
PushConstantRaster m_pcRaster{
|
|
||||||
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, // Identity matrix
|
|
||||||
{10.f, 15.f, 8.f}, // light position
|
|
||||||
0, // instance Id
|
|
||||||
100.f, // light intensity
|
|
||||||
0 // light type
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Array of objects and instances in the scene
|
|
||||||
std::vector<ObjModel> m_objModel; // Model on host
|
|
||||||
std::vector<ObjDesc> m_objDesc; // Model description for device access
|
|
||||||
std::vector<ObjInstance> m_instances; // Scene model instances
|
|
||||||
|
|
||||||
|
|
||||||
// Graphic pipeline
|
|
||||||
VkPipelineLayout m_pipelineLayout;
|
|
||||||
VkPipeline m_graphicsPipeline;
|
|
||||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
|
||||||
VkDescriptorPool m_descPool;
|
|
||||||
VkDescriptorSetLayout m_descSetLayout;
|
|
||||||
VkDescriptorSet m_descSet;
|
|
||||||
|
|
||||||
nvvk::Buffer m_bGlobals; // Device-Host of the camera matrices
|
|
||||||
nvvk::Buffer m_bObjDesc; // Device buffer of the OBJ instances
|
|
||||||
nvvk::Buffer m_bufReference; // Buffer references of the OBJ
|
|
||||||
|
|
||||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
|
||||||
|
|
||||||
|
|
||||||
nvvk::ResourceAllocatorDma m_alloc; // Allocator for buffer, images, acceleration structures
|
|
||||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
|
||||||
|
|
||||||
|
|
||||||
// #Post - Draw the rendered image on a quad using a tonemapper
|
|
||||||
void createOffscreenRender();
|
|
||||||
void createPostPipeline();
|
|
||||||
void createPostDescriptor();
|
|
||||||
void updatePostDescriptorSet();
|
|
||||||
void drawPost(VkCommandBuffer cmdBuf);
|
|
||||||
|
|
||||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
|
||||||
VkDescriptorPool m_postDescPool{VK_NULL_HANDLE};
|
|
||||||
VkDescriptorSetLayout m_postDescSetLayout{VK_NULL_HANDLE};
|
|
||||||
VkDescriptorSet m_postDescSet{VK_NULL_HANDLE};
|
|
||||||
VkPipeline m_postPipeline{VK_NULL_HANDLE};
|
|
||||||
VkPipelineLayout m_postPipelineLayout{VK_NULL_HANDLE};
|
|
||||||
VkRenderPass m_offscreenRenderPass{VK_NULL_HANDLE};
|
|
||||||
VkFramebuffer m_offscreenFramebuffer{VK_NULL_HANDLE};
|
|
||||||
nvvk::Texture m_offscreenColor;
|
|
||||||
nvvk::Texture m_offscreenDepth;
|
|
||||||
VkFormat m_offscreenColorFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
|
|
||||||
VkFormat m_offscreenDepthFormat{VK_FORMAT_X8_D24_UNORM_PACK32};
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
void initRayTracing();
|
|
||||||
auto objectToVkGeometryKHR(const ObjModel& model);
|
|
||||||
void createBottomLevelAS();
|
|
||||||
void createTopLevelAS();
|
|
||||||
void createRtDescriptorSet();
|
|
||||||
void updateRtDescriptorSet();
|
|
||||||
void createRtPipeline();
|
|
||||||
void raytrace(const VkCommandBuffer& cmdBuf, const glm::vec4& clearColor);
|
|
||||||
|
|
||||||
|
|
||||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
|
|
||||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
|
||||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
|
||||||
VkDescriptorPool m_rtDescPool;
|
|
||||||
VkDescriptorSetLayout m_rtDescSetLayout;
|
|
||||||
VkDescriptorSet m_rtDescSet;
|
|
||||||
std::vector<VkRayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
|
||||||
VkPipelineLayout m_rtPipelineLayout;
|
|
||||||
VkPipeline m_rtPipeline;
|
|
||||||
nvvk::SBTWrapper m_sbtWrapper;
|
|
||||||
// Push constant for ray tracer
|
|
||||||
VkPipeline m_rtShaderLibrary;
|
|
||||||
|
|
||||||
|
|
||||||
PushConstantRay m_pcRay{{}, {}, 0, 0, 7};
|
|
||||||
};
|
|
||||||
|
Before Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
|
@ -1,303 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// ImGui - standalone example application for Glfw + Vulkan, using programmable
|
|
||||||
// pipeline If you are new to ImGui, see examples/README.txt and documentation
|
|
||||||
// at the top of imgui.cpp.
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
|
||||||
#include "backends/imgui_impl_glfw.h"
|
|
||||||
#include "backends/imgui_impl_vulkan.h"
|
|
||||||
#include "imgui.h"
|
|
||||||
#include "imgui/imgui_helper.h"
|
|
||||||
|
|
||||||
#include "hello_vulkan.h"
|
|
||||||
#include "imgui/imgui_camera_widget.h"
|
|
||||||
#include "nvh/cameramanipulator.hpp"
|
|
||||||
#include "nvh/fileoperations.hpp"
|
|
||||||
#include "nvpsystem.hpp"
|
|
||||||
#include "nvvk/commands_vk.hpp"
|
|
||||||
#include "nvvk/context_vk.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
#define UNUSED(x) (void)(x)
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Default search path for shaders
|
|
||||||
std::vector<std::string> defaultSearchPaths;
|
|
||||||
|
|
||||||
|
|
||||||
// GLFW Callback functions
|
|
||||||
static void onErrorCallback(int error, const char* description)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extra UI
|
|
||||||
void renderUI(HelloVulkan& helloVk)
|
|
||||||
{
|
|
||||||
ImGuiH::CameraWidget();
|
|
||||||
if(ImGui::CollapsingHeader("Light"))
|
|
||||||
{
|
|
||||||
ImGui::RadioButton("Point", &helloVk.m_pcRaster.lightType, 0);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("Infinite", &helloVk.m_pcRaster.lightType, 1);
|
|
||||||
|
|
||||||
ImGui::SliderFloat3("Position", &helloVk.m_pcRaster.lightPosition.x, -20.f, 20.f);
|
|
||||||
ImGui::SliderFloat("Intensity", &helloVk.m_pcRaster.lightIntensity, 0.f, 150.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specialization
|
|
||||||
ImGui::SliderInt("Specialization", &helloVk.m_pcRay.specialization, 0, 7);
|
|
||||||
int s = helloVk.m_pcRay.specialization;
|
|
||||||
int a = ((s >> 2) % 2) == 1;
|
|
||||||
int b = ((s >> 1) % 2) == 1;
|
|
||||||
int c = ((s >> 0) % 2) == 1;
|
|
||||||
ImGui::Checkbox("Use Diffuse", (bool*)&a);
|
|
||||||
ImGui::Checkbox("Use Specular", (bool*)&b);
|
|
||||||
ImGui::Checkbox("Trace shadow", (bool*)&c);
|
|
||||||
helloVk.m_pcRay.specialization = (a << 2) + (b << 1) + c;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
static int const SAMPLE_WIDTH = 1280;
|
|
||||||
static int const SAMPLE_HEIGHT = 720;
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
|
||||||
// Application Entry
|
|
||||||
//
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
UNUSED(argc);
|
|
||||||
|
|
||||||
// Setup GLFW window
|
|
||||||
glfwSetErrorCallback(onErrorCallback);
|
|
||||||
if(!glfwInit())
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
||||||
GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr);
|
|
||||||
|
|
||||||
// Setup camera
|
|
||||||
CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
||||||
CameraManip.setLookat(glm::vec3(5, 4, -4), glm::vec3(0, 1, 0), glm::vec3(0, 1, 0));
|
|
||||||
|
|
||||||
// Setup Vulkan
|
|
||||||
if(!glfwVulkanSupported())
|
|
||||||
{
|
|
||||||
printf("GLFW: Vulkan Not Supported\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup some basic things for the sample, logging file for example
|
|
||||||
NVPSystem system(PROJECT_NAME);
|
|
||||||
|
|
||||||
// Search path for shaders and other media
|
|
||||||
defaultSearchPaths = {
|
|
||||||
NVPSystem::exePath() + PROJECT_RELDIRECTORY,
|
|
||||||
NVPSystem::exePath() + PROJECT_RELDIRECTORY "..",
|
|
||||||
std::string(PROJECT_NAME),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Vulkan required extensions
|
|
||||||
assert(glfwVulkanSupported() == 1);
|
|
||||||
uint32_t count{0};
|
|
||||||
auto reqExtensions = glfwGetRequiredInstanceExtensions(&count);
|
|
||||||
|
|
||||||
// Requesting Vulkan extensions and layers
|
|
||||||
nvvk::ContextCreateInfo contextInfo;
|
|
||||||
contextInfo.setVersion(1, 2); // Using Vulkan 1.2
|
|
||||||
for(uint32_t ext_id = 0; ext_id < count; ext_id++) // Adding required extensions (surface, win32, linux, ..)
|
|
||||||
contextInfo.addInstanceExtension(reqExtensions[ext_id]);
|
|
||||||
contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); // FPS in titlebar
|
|
||||||
contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); // Allow debug names
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); // Enabling ability to present rendering
|
|
||||||
|
|
||||||
// #VKRay: Activate the ray tracing extension
|
|
||||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR};
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); // To build acceleration structures
|
|
||||||
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR};
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // To use vkCmdTraceRaysKHR
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // Required by ray tracing pipeline
|
|
||||||
contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME);
|
|
||||||
|
|
||||||
// Creating Vulkan base application
|
|
||||||
nvvk::Context vkctx{};
|
|
||||||
vkctx.initInstance(contextInfo);
|
|
||||||
// Find all compatible devices
|
|
||||||
auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo);
|
|
||||||
assert(!compatibleDevices.empty());
|
|
||||||
// Use a compatible device
|
|
||||||
vkctx.initDevice(compatibleDevices[0], contextInfo);
|
|
||||||
|
|
||||||
// Create example
|
|
||||||
HelloVulkan helloVk;
|
|
||||||
|
|
||||||
// Window need to be opened to get the surface on which to draw
|
|
||||||
const VkSurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window);
|
|
||||||
vkctx.setGCTQueueWithPresent(surface);
|
|
||||||
|
|
||||||
helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
|
|
||||||
helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT);
|
|
||||||
helloVk.createDepthBuffer();
|
|
||||||
helloVk.createRenderPass();
|
|
||||||
helloVk.createFrameBuffers();
|
|
||||||
|
|
||||||
// Setup Imgui
|
|
||||||
helloVk.initGUI(0); // Using sub-pass 0
|
|
||||||
|
|
||||||
// Creation of the example
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
|
|
||||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
|
||||||
|
|
||||||
helloVk.createOffscreenRender();
|
|
||||||
helloVk.createDescriptorSetLayout();
|
|
||||||
helloVk.createGraphicsPipeline();
|
|
||||||
helloVk.createUniformBuffer();
|
|
||||||
helloVk.createObjDescriptionBuffer();
|
|
||||||
helloVk.updateDescriptorSet();
|
|
||||||
|
|
||||||
// #VKRay
|
|
||||||
helloVk.initRayTracing();
|
|
||||||
helloVk.createBottomLevelAS();
|
|
||||||
helloVk.createTopLevelAS();
|
|
||||||
helloVk.createRtDescriptorSet();
|
|
||||||
helloVk.createRtPipeline();
|
|
||||||
|
|
||||||
helloVk.createPostDescriptor();
|
|
||||||
helloVk.createPostPipeline();
|
|
||||||
helloVk.updatePostDescriptorSet();
|
|
||||||
|
|
||||||
|
|
||||||
glm::vec4 clearColor = glm::vec4(1, 1, 1, 1.00f);
|
|
||||||
bool useRaytracer = true;
|
|
||||||
|
|
||||||
|
|
||||||
helloVk.setupGlfwCallbacks(window);
|
|
||||||
ImGui_ImplGlfw_InitForVulkan(window, true);
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
while(!glfwWindowShouldClose(window))
|
|
||||||
{
|
|
||||||
glfwPollEvents();
|
|
||||||
if(helloVk.isMinimized())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
|
||||||
ImGui_ImplGlfw_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
|
|
||||||
|
|
||||||
// Show UI window.
|
|
||||||
if(helloVk.showGui())
|
|
||||||
{
|
|
||||||
ImGuiH::Panel::Begin();
|
|
||||||
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
|
||||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
|
||||||
|
|
||||||
renderUI(helloVk);
|
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
|
||||||
ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled);
|
|
||||||
ImGuiH::Panel::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start rendering the scene
|
|
||||||
helloVk.prepareFrame();
|
|
||||||
|
|
||||||
// Start command buffer of this frame
|
|
||||||
auto curFrame = helloVk.getCurFrame();
|
|
||||||
const VkCommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame];
|
|
||||||
|
|
||||||
VkCommandBufferBeginInfo beginInfo{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
|
||||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
||||||
vkBeginCommandBuffer(cmdBuf, &beginInfo);
|
|
||||||
|
|
||||||
// Updating camera buffer
|
|
||||||
helloVk.updateUniformBuffer(cmdBuf);
|
|
||||||
|
|
||||||
// Clearing screen
|
|
||||||
std::array<VkClearValue, 2> clearValues{};
|
|
||||||
clearValues[0].color = {{clearColor[0], clearColor[1], clearColor[2], clearColor[3]}};
|
|
||||||
clearValues[1].depthStencil = {1.0f, 0};
|
|
||||||
|
|
||||||
// Offscreen render pass
|
|
||||||
{
|
|
||||||
VkRenderPassBeginInfo offscreenRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
|
||||||
offscreenRenderPassBeginInfo.clearValueCount = 2;
|
|
||||||
offscreenRenderPassBeginInfo.pClearValues = clearValues.data();
|
|
||||||
offscreenRenderPassBeginInfo.renderPass = helloVk.m_offscreenRenderPass;
|
|
||||||
offscreenRenderPassBeginInfo.framebuffer = helloVk.m_offscreenFramebuffer;
|
|
||||||
offscreenRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
|
||||||
|
|
||||||
// Rendering Scene
|
|
||||||
if(useRaytracer)
|
|
||||||
{
|
|
||||||
helloVk.raytrace(cmdBuf, clearColor);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vkCmdBeginRenderPass(cmdBuf, &offscreenRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
helloVk.rasterize(cmdBuf);
|
|
||||||
vkCmdEndRenderPass(cmdBuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2nd rendering pass: tone mapper, UI
|
|
||||||
{
|
|
||||||
VkRenderPassBeginInfo postRenderPassBeginInfo{VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
|
|
||||||
postRenderPassBeginInfo.clearValueCount = 2;
|
|
||||||
postRenderPassBeginInfo.pClearValues = clearValues.data();
|
|
||||||
postRenderPassBeginInfo.renderPass = helloVk.getRenderPass();
|
|
||||||
postRenderPassBeginInfo.framebuffer = helloVk.getFramebuffers()[curFrame];
|
|
||||||
postRenderPassBeginInfo.renderArea = {{0, 0}, helloVk.getSize()};
|
|
||||||
|
|
||||||
// Rendering tonemapper
|
|
||||||
vkCmdBeginRenderPass(cmdBuf, &postRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
|
||||||
helloVk.drawPost(cmdBuf);
|
|
||||||
// Rendering UI
|
|
||||||
ImGui::Render();
|
|
||||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf);
|
|
||||||
vkCmdEndRenderPass(cmdBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submit for display
|
|
||||||
vkEndCommandBuffer(cmdBuf);
|
|
||||||
helloVk.submitFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
vkDeviceWaitIdle(helloVk.getDevice());
|
|
||||||
|
|
||||||
helloVk.destroyResources();
|
|
||||||
helloVk.destroy();
|
|
||||||
vkctx.deinit();
|
|
||||||
|
|
||||||
glfwDestroyWindow(window);
|
|
||||||
glfwTerminate();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRaster
|
|
||||||
{
|
|
||||||
PushConstantRaster pcRaster;
|
|
||||||
};
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
// Incoming
|
|
||||||
layout(location = 1) in vec3 i_worldPos;
|
|
||||||
layout(location = 2) in vec3 i_worldNrm;
|
|
||||||
layout(location = 3) in vec3 i_viewDir;
|
|
||||||
layout(location = 4) in vec2 i_texCoord;
|
|
||||||
// Outgoing
|
|
||||||
layout(location = 0) out vec4 o_color;
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {uint i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
|
|
||||||
layout(binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
layout(binding = eTextures) uniform sampler2D[] textureSamplers;
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Material of the object
|
|
||||||
ObjDesc objResource = objDesc.i[pcRaster.objIndex];
|
|
||||||
MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
|
|
||||||
int matIndex = matIndices.i[gl_PrimitiveID];
|
|
||||||
WaveFrontMaterial mat = materials.m[matIndex];
|
|
||||||
|
|
||||||
vec3 N = normalize(i_worldNrm);
|
|
||||||
|
|
||||||
// Vector toward light
|
|
||||||
vec3 L;
|
|
||||||
float lightIntensity = pcRaster.lightIntensity;
|
|
||||||
if(pcRaster.lightType == 0)
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRaster.lightPosition - i_worldPos;
|
|
||||||
float d = length(lDir);
|
|
||||||
lightIntensity = pcRaster.lightIntensity / (d * d);
|
|
||||||
L = normalize(lDir);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
L = normalize(pcRaster.lightPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Diffuse
|
|
||||||
vec3 diffuse = computeDiffuse(mat, L, N);
|
|
||||||
if(mat.textureId >= 0)
|
|
||||||
{
|
|
||||||
int txtOffset = objDesc.i[pcRaster.objIndex].txtOffset;
|
|
||||||
uint txtId = txtOffset + mat.textureId;
|
|
||||||
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], i_texCoord).xyz;
|
|
||||||
diffuse *= diffuseTxt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specular
|
|
||||||
vec3 specular = computeSpecular(mat, i_viewDir, L, N);
|
|
||||||
|
|
||||||
// Result
|
|
||||||
o_color = vec4(lightIntensity * (diffuse + specular), 1);
|
|
||||||
}
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef COMMON_HOST_DEVICE
|
|
||||||
#define COMMON_HOST_DEVICE
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
// GLSL Type
|
|
||||||
using vec2 = glm::vec2;
|
|
||||||
using vec3 = glm::vec3;
|
|
||||||
using vec4 = glm::vec4;
|
|
||||||
using mat4 = glm::mat4;
|
|
||||||
using uint = unsigned int;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
|
|
||||||
#define START_BINDING(a) enum a {
|
|
||||||
#define END_BINDING() }
|
|
||||||
#else
|
|
||||||
#define START_BINDING(a) const uint
|
|
||||||
#define END_BINDING()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
START_BINDING(SceneBindings)
|
|
||||||
eGlobals = 0, // Global uniform containing camera matrices
|
|
||||||
eObjDescs = 1, // Access to the object descriptions
|
|
||||||
eTextures = 2 // Access to textures
|
|
||||||
END_BINDING();
|
|
||||||
|
|
||||||
START_BINDING(RtxBindings)
|
|
||||||
eTlas = 0, // Top-level acceleration structure
|
|
||||||
eOutImage = 1 // Ray tracer output image
|
|
||||||
END_BINDING();
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
// Information of a obj model when referenced in a shader
|
|
||||||
struct ObjDesc
|
|
||||||
{
|
|
||||||
int txtOffset; // Texture index offset in the array of textures
|
|
||||||
uint64_t vertexAddress; // Address of the Vertex buffer
|
|
||||||
uint64_t indexAddress; // Address of the index buffer
|
|
||||||
uint64_t materialAddress; // Address of the material buffer
|
|
||||||
uint64_t materialIndexAddress; // Address of the triangle material index buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
// Uniform buffer set at each frame
|
|
||||||
struct GlobalUniforms
|
|
||||||
{
|
|
||||||
mat4 viewProj; // Camera view * projection
|
|
||||||
mat4 viewInverse; // Camera inverse view matrix
|
|
||||||
mat4 projInverse; // Camera inverse projection matrix
|
|
||||||
};
|
|
||||||
|
|
||||||
// Push constant structure for the raster
|
|
||||||
struct PushConstantRaster
|
|
||||||
{
|
|
||||||
mat4 modelMatrix; // matrix of the instance
|
|
||||||
vec3 lightPosition;
|
|
||||||
uint objIndex;
|
|
||||||
float lightIntensity;
|
|
||||||
int lightType;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Push constant structure for the ray tracer
|
|
||||||
struct PushConstantRay
|
|
||||||
{
|
|
||||||
vec4 clearColor;
|
|
||||||
vec3 lightPosition;
|
|
||||||
float lightIntensity;
|
|
||||||
int lightType;
|
|
||||||
int specialization;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vertex // See ObjLoader, copy of VertexObj, could be compressed for device
|
|
||||||
{
|
|
||||||
vec3 pos;
|
|
||||||
vec3 nrm;
|
|
||||||
vec3 color;
|
|
||||||
vec2 texCoord;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WaveFrontMaterial // See ObjLoader, copy of MaterialObj, could be compressed for device
|
|
||||||
{
|
|
||||||
vec3 ambient;
|
|
||||||
vec3 diffuse;
|
|
||||||
vec3 specular;
|
|
||||||
vec3 transmittance;
|
|
||||||
vec3 emission;
|
|
||||||
float shininess;
|
|
||||||
float ior; // index of refraction
|
|
||||||
float dissolve; // 1 == opaque; 0 == fully transparent
|
|
||||||
int illum; // illumination model (see http://www.fileformat.info/format/material/)
|
|
||||||
int textureId;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(location = 0) out vec2 outUV;
|
|
||||||
|
|
||||||
|
|
||||||
out gl_PerVertex
|
|
||||||
{
|
|
||||||
vec4 gl_Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
|
||||||
gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(location = 0) in vec2 outUV;
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform sampler2D noisyTxt;
|
|
||||||
|
|
||||||
layout(push_constant) uniform shaderInformation
|
|
||||||
{
|
|
||||||
float aspectRatio;
|
|
||||||
}
|
|
||||||
pushc;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec2 uv = outUV;
|
|
||||||
float gamma = 1. / 2.2;
|
|
||||||
fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma));
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct hitPayload
|
|
||||||
{
|
|
||||||
vec3 hitValue;
|
|
||||||
};
|
|
||||||
|
|
@ -1,160 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
#extension GL_EXT_buffer_reference2 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
hitAttributeEXT vec2 attribs;
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
|
||||||
layout(location = 1) rayPayloadEXT bool isShadowed;
|
|
||||||
|
|
||||||
layout(buffer_reference, scalar) buffer Vertices {Vertex v[]; }; // Positions of an object
|
|
||||||
layout(buffer_reference, scalar) buffer Indices {ivec3 i[]; }; // Triangle indices
|
|
||||||
layout(buffer_reference, scalar) buffer Materials {WaveFrontMaterial m[]; }; // Array of all materials on an object
|
|
||||||
layout(buffer_reference, scalar) buffer MatIndices {int i[]; }; // Material ID for each triangle
|
|
||||||
layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
|
|
||||||
layout(set = 1, binding = eObjDescs, scalar) buffer ObjDesc_ { ObjDesc i[]; } objDesc;
|
|
||||||
layout(set = 1, binding = eTextures) uniform sampler2D textureSamplers[];
|
|
||||||
layout(constant_id = 0) const int USE_DIFFUSE = 1;
|
|
||||||
layout(constant_id = 1) const int USE_SPECULAR = 1;
|
|
||||||
layout(constant_id = 2) const int TRACE_SHADOW = 1;
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
// Object data
|
|
||||||
ObjDesc objResource = objDesc.i[gl_InstanceCustomIndexEXT];
|
|
||||||
MatIndices matIndices = MatIndices(objResource.materialIndexAddress);
|
|
||||||
Materials materials = Materials(objResource.materialAddress);
|
|
||||||
Indices indices = Indices(objResource.indexAddress);
|
|
||||||
Vertices vertices = Vertices(objResource.vertexAddress);
|
|
||||||
|
|
||||||
// Indices of the triangle
|
|
||||||
ivec3 ind = indices.i[gl_PrimitiveID];
|
|
||||||
|
|
||||||
// Vertex of the triangle
|
|
||||||
Vertex v0 = vertices.v[ind.x];
|
|
||||||
Vertex v1 = vertices.v[ind.y];
|
|
||||||
Vertex v2 = vertices.v[ind.z];
|
|
||||||
|
|
||||||
const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
|
|
||||||
|
|
||||||
// Computing the coordinates of the hit position
|
|
||||||
const vec3 pos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
|
|
||||||
const vec3 worldPos = vec3(gl_ObjectToWorldEXT * vec4(pos, 1.0)); // Transforming the position to world space
|
|
||||||
|
|
||||||
// Computing the normal at hit position
|
|
||||||
const vec3 nrm = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
|
|
||||||
const vec3 worldNrm = normalize(vec3(nrm * gl_WorldToObjectEXT)); // Transforming the normal to world space
|
|
||||||
|
|
||||||
// Vector toward the light
|
|
||||||
vec3 L;
|
|
||||||
float lightIntensity = pcRay.lightIntensity;
|
|
||||||
float lightDistance = 100000.0;
|
|
||||||
// Point light
|
|
||||||
if(pcRay.lightType == 0)
|
|
||||||
{
|
|
||||||
vec3 lDir = pcRay.lightPosition - worldPos;
|
|
||||||
lightDistance = length(lDir);
|
|
||||||
lightIntensity = pcRay.lightIntensity / (lightDistance * lightDistance);
|
|
||||||
L = normalize(lDir);
|
|
||||||
}
|
|
||||||
else // Directional light
|
|
||||||
{
|
|
||||||
L = normalize(pcRay.lightPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Material of the object
|
|
||||||
int matIdx = matIndices.i[gl_PrimitiveID];
|
|
||||||
WaveFrontMaterial mat = materials.m[matIdx];
|
|
||||||
|
|
||||||
|
|
||||||
// Diffuse
|
|
||||||
vec3 diffuse = vec3(0);
|
|
||||||
if(USE_DIFFUSE == 1)
|
|
||||||
{
|
|
||||||
diffuse = computeDiffuse(mat, L, worldNrm);
|
|
||||||
if(mat.textureId >= 0)
|
|
||||||
{
|
|
||||||
uint txtId = mat.textureId + objDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
|
|
||||||
vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
|
|
||||||
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 specular = vec3(0);
|
|
||||||
float attenuation = 1;
|
|
||||||
|
|
||||||
// Tracing shadow ray only if the light is visible from the surface
|
|
||||||
if(dot(worldNrm, L) > 0)
|
|
||||||
{
|
|
||||||
if(TRACE_SHADOW == 1)
|
|
||||||
{
|
|
||||||
float tMin = 0.001;
|
|
||||||
float tMax = lightDistance;
|
|
||||||
vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
|
|
||||||
vec3 rayDir = L;
|
|
||||||
uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT;
|
|
||||||
isShadowed = true;
|
|
||||||
traceRayEXT(topLevelAS, // acceleration structure
|
|
||||||
flags, // rayFlags
|
|
||||||
0xFF, // cullMask
|
|
||||||
0, // sbtRecordOffset
|
|
||||||
0, // sbtRecordStride
|
|
||||||
1, // missIndex
|
|
||||||
origin, // ray origin
|
|
||||||
tMin, // ray min range
|
|
||||||
rayDir, // ray direction
|
|
||||||
tMax, // ray max range
|
|
||||||
1 // payload (location = 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
isShadowed = false;
|
|
||||||
|
|
||||||
if(isShadowed)
|
|
||||||
{
|
|
||||||
attenuation = 0.3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Specular
|
|
||||||
if(USE_SPECULAR == 1)
|
|
||||||
{
|
|
||||||
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, worldNrm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prd.hitValue = vec3(lightIntensity * attenuation * (diffuse + specular));
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
layout(location = 0) rayPayloadEXT hitPayload prd;
|
|
||||||
|
|
||||||
layout(set = 0, binding = eTlas) uniform accelerationStructureEXT topLevelAS;
|
|
||||||
layout(set = 0, binding = eOutImage, rgba32f) uniform image2D image;
|
|
||||||
layout(set = 1, binding = eGlobals) uniform _GlobalUniforms { GlobalUniforms uni; };
|
|
||||||
layout(push_constant) uniform _PushConstantRay { PushConstantRay pcRay; };
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
|
|
||||||
const vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
|
|
||||||
vec2 d = inUV * 2.0 - 1.0;
|
|
||||||
|
|
||||||
vec4 origin = uni.viewInverse * vec4(0, 0, 0, 1);
|
|
||||||
vec4 target = uni.projInverse * vec4(d.x, d.y, 1, 1);
|
|
||||||
vec4 direction = uni.viewInverse * vec4(normalize(target.xyz), 0);
|
|
||||||
|
|
||||||
uint rayFlags = gl_RayFlagsOpaqueEXT;
|
|
||||||
float tMin = 0.001;
|
|
||||||
float tMax = 10000.0;
|
|
||||||
|
|
||||||
traceRayEXT(topLevelAS, // acceleration structure
|
|
||||||
rayFlags, // rayFlags
|
|
||||||
0xFF, // cullMask
|
|
||||||
pcRay.specialization, // sbtRecordOffset
|
|
||||||
0, // sbtRecordStride
|
|
||||||
0, // missIndex
|
|
||||||
origin.xyz, // ray origin
|
|
||||||
tMin, // ray min range
|
|
||||||
direction.xyz, // ray direction
|
|
||||||
tMax, // ray max range
|
|
||||||
0 // payload (location = 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(prd.hitValue, 1.0));
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "raycommon.glsl"
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRay
|
|
||||||
{
|
|
||||||
PushConstantRay pcRay;
|
|
||||||
};
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
prd.hitValue = pcRay.clearColor.xyz * 0.8;
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 460
|
|
||||||
#extension GL_EXT_ray_tracing : require
|
|
||||||
|
|
||||||
layout(location = 1) rayPayloadInEXT bool isShadowed;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
isShadowed = false;
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
|
||||||
#extension GL_EXT_scalar_block_layout : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : enable
|
|
||||||
|
|
||||||
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
|
|
||||||
|
|
||||||
#include "wavefront.glsl"
|
|
||||||
|
|
||||||
layout(binding = 0) uniform _GlobalUniforms
|
|
||||||
{
|
|
||||||
GlobalUniforms uni;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(push_constant) uniform _PushConstantRaster
|
|
||||||
{
|
|
||||||
PushConstantRaster pcRaster;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 i_position;
|
|
||||||
layout(location = 1) in vec3 i_normal;
|
|
||||||
layout(location = 2) in vec3 i_color;
|
|
||||||
layout(location = 3) in vec2 i_texCoord;
|
|
||||||
|
|
||||||
|
|
||||||
layout(location = 1) out vec3 o_worldPos;
|
|
||||||
layout(location = 2) out vec3 o_worldNrm;
|
|
||||||
layout(location = 3) out vec3 o_viewDir;
|
|
||||||
layout(location = 4) out vec2 o_texCoord;
|
|
||||||
|
|
||||||
out gl_PerVertex
|
|
||||||
{
|
|
||||||
vec4 gl_Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec3 origin = vec3(uni.viewInverse * vec4(0, 0, 0, 1));
|
|
||||||
|
|
||||||
o_worldPos = vec3(pcRaster.modelMatrix * vec4(i_position, 1.0));
|
|
||||||
o_viewDir = vec3(o_worldPos - origin);
|
|
||||||
o_texCoord = i_texCoord;
|
|
||||||
o_worldNrm = mat3(pcRaster.modelMatrix) * i_normal;
|
|
||||||
|
|
||||||
gl_Position = uni.viewProj * vec4(o_worldPos, 1.0);
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "host_device.h"
|
|
||||||
|
|
||||||
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
|
|
||||||
{
|
|
||||||
// Lambertian
|
|
||||||
float dotNL = max(dot(normal, lightDir), 0.0);
|
|
||||||
vec3 c = mat.diffuse * dotNL;
|
|
||||||
if(mat.illum >= 1)
|
|
||||||
c += mat.ambient;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal)
|
|
||||||
{
|
|
||||||
if(mat.illum < 2)
|
|
||||||
return vec3(0);
|
|
||||||
|
|
||||||
// Compute specular only if not in shadow
|
|
||||||
const float kPi = 3.14159265;
|
|
||||||
const float kShininess = max(mat.shininess, 4.0);
|
|
||||||
|
|
||||||
// Specular
|
|
||||||
const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi);
|
|
||||||
vec3 V = normalize(-viewDir);
|
|
||||||
vec3 R = reflect(-lightDir, normal);
|
|
||||||
float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess);
|
|
||||||
|
|
||||||
return vec3(mat.specular * specular);
|
|
||||||
}
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
#*****************************************************************************
|
|
||||||
# Copyright 2020 NVIDIA Corporation. All rights reserved.
|
|
||||||
#*****************************************************************************
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Project setting
|
|
||||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
||||||
set(PROJNAME vk_${PROJNAME}_KHR)
|
|
||||||
project(${PROJNAME} LANGUAGES C CXX)
|
|
||||||
message(STATUS "-------------------------------")
|
|
||||||
message(STATUS "Processing Project ${PROJNAME}:")
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# C++ target and defines
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
add_executable(${PROJNAME})
|
|
||||||
_add_project_definitions(${PROJNAME})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Source files for this project
|
|
||||||
#
|
|
||||||
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
|
|
||||||
file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
|
|
||||||
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
|
||||||
include_directories(${TUTO_KHR_DIR}/common)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# GLSL to SPIR-V custom build
|
|
||||||
compile_glsl_directory(
|
|
||||||
SRC "${CMAKE_CURRENT_SOURCE_DIR}/shaders"
|
|
||||||
DST "${CMAKE_CURRENT_SOURCE_DIR}/spv"
|
|
||||||
VULKAN_TARGET "vulkan1.2"
|
|
||||||
DEPENDENCY ${VULKAN_BUILD_DEPENDENCIES}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sources
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
|
|
||||||
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES} ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Sub-folders in Visual Studio
|
|
||||||
#
|
|
||||||
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
|
|
||||||
source_group("Sources" FILES ${SOURCE_FILES})
|
|
||||||
source_group("Headers" FILES ${HEADER_FILES})
|
|
||||||
source_group("Shader Sources" FILES ${GLSL_SOURCES})
|
|
||||||
source_group("Shader Headers" FILES ${GLSL_HEADERS})
|
|
||||||
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# Linkage
|
|
||||||
#
|
|
||||||
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} nvpro_core)
|
|
||||||
|
|
||||||
foreach(DEBUGLIB ${LIBRARIES_DEBUG})
|
|
||||||
target_link_libraries(${PROJNAME} debug ${DEBUGLIB})
|
|
||||||
endforeach(DEBUGLIB)
|
|
||||||
|
|
||||||
foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
|
|
||||||
target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
|
|
||||||
endforeach(RELEASELIB)
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------------------------------------
|
|
||||||
# copies binaries that need to be put next to the exe files (ZLib, etc.)
|
|
||||||
#
|
|
||||||
_finalize_target( ${PROJNAME} )
|
|
||||||
|
|
||||||
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/spv")
|
|
||||||
install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/spv")
|
|
||||||