diff --git a/Build/deploycommon.bat b/Build/deploycommon.bat index 6cd27dcc8..ecd5087b4 100644 --- a/Build/deploycommon.bat +++ b/Build/deploycommon.bat @@ -25,7 +25,6 @@ robocopy %ExtDir%\FreeImage %OutDir% freeimage.dll /r:0 >nul robocopy %ExtDir%\assimp\bin\%2 %OutDir% *.dll /r:0 >nul robocopy %ExtDir%\FFMpeg\bin\%2 %OutDir% *.dll /r:0 >nul rem robocopy %ExtDir%\dxcompiler\%2 %OutDir% dxcompiler.dll /r:0 >nul -robocopy %ExtDir%\OptiX\bin64 %OutDir% *.dll /r:0 >nul robocopy %ExtDir%\openvr\bin\win64 %OutDir% openvr_api.dll /r:0 >nul robocopy %ExtDir%\Slang\bin\windows-x64\release %OutDir% *.dll /r:0 >nul robocopy %ExtDir%\GLFW\lib %OutDir% *.dll /r:0 >nul diff --git a/Docs/Tutorials/04-Writing-Shaders.md b/Docs/Tutorials/04-Writing-Shaders.md index c2a2d9249..0a2c6b317 100644 --- a/Docs/Tutorials/04-Writing-Shaders.md +++ b/Docs/Tutorials/04-Writing-Shaders.md @@ -77,7 +77,7 @@ This function will need to perform several operations: create and bind an FBO fo We can create and bind an FBO for our renderer to render to by first calling `Fbo::create()` on our output texture, clearing it to remove any data from previous executions (preventing it from leaving permanent trails if you try to move the camera), and calling `GraphicsState::setFbo()` to bind it. This step looks like this: ```c++ auto pTargetFbo = Fbo::create({ renderData["output"]->asTexture() }); -const glm::vec4 clearColor(0, 0, 0, 1); +const float4 clearColor(0, 0, 0, 1); pRenderContext->clearFbo(pTargetFbo.get(), clearColor, 1.0f, 0, FboAttachmentType::All); mpGraphicsState->setFbo(pTargetFbo); ``` @@ -86,7 +86,7 @@ mpGraphicsState->setFbo(pTargetFbo); We need to perform two operations here: indicate that we want to use a custom `RasterizerState` and bind all necessary values to our shader. We can indicate that we're using a custom `RasterizerState` by creating a `Scene::Renderflags` object and setting the flag `Scene::RenderFlags::UserRasterizerState`. Binding shader values is also fairly straightforward as Falcor allows you to set shader values in the `GraphicsVars` object in the same way as you would set values in an array. Our shader requires a single color value, `gColor`, which is located inside the `perFrameCB` constant buffer. This step should look like this: ```c++ Scene::RenderFlags renderFlags = Scene::RenderFlags::UserRasterizerState; -mpVars["perFrameCB"]["gColor"] = vec4(0, 1, 0, 1); +mpVars["perFrameCB"]["gColor"] = float4(0, 1, 0, 1); ``` #### Rendering a Scene Using the Shader @@ -99,13 +99,13 @@ Your `execute()` function should now look like this: void WireframePass::execute(RenderContext* pRenderContext, const RenderData& renderData) { auto pTargetFbo = Fbo::create({ renderData["output"]->asTexture() }); - const glm::vec4 clearColor(0, 0, 0, 1); + const float4 clearColor(0, 0, 0, 1); pRenderContext->clearFbo(pTargetFbo.get(), clearColor, 1.0f, 0, FboAttachmentType::All); mpGraphicsState->setFbo(pTargetFbo); // Set render state Scene::RenderFlags renderFlags = Scene::RenderFlags::UserRasterizerState; - mpVars["PerFrameCB"]["gColor"] = vec4(0, 1, 0, 1); + mpVars["PerFrameCB"]["gColor"] = float4(0, 1, 0, 1); mpScene->render(pRenderContext, mpGraphicsState.get(), mpVars.get(), renderFlags); } @@ -113,4 +113,4 @@ void WireframePass::execute(RenderContext* pRenderContext, const RenderData& ren Using the Render Graph Editor, create a graph solely containing this pass then launch it in Mogwai. Don't worry about needing to load a scene; Mogwai will load the Arcade scene by default. You should see something similar to this: -![WireframePass](./images/WireframePass.png) \ No newline at end of file +![WireframePass](./images/WireframePass.png) diff --git a/Docs/Tutorials/index.md b/Docs/Tutorials/index.md index 1d3b5b863..674fa266f 100644 --- a/Docs/Tutorials/index.md +++ b/Docs/Tutorials/index.md @@ -6,5 +6,5 @@ 1. [Mogwai Usage](./01-Mogwai-Usage.md) 2. [Implementing Render Passes](./02-Implementing-a-Render-Pass.md) -3. [Creating and Editing Render Graphs](./03-Creating-And-Editing-Render-Graphs.md) +3. [Creating and Editing Render Graphs](./03-Creating-and-Editing-Render-Graphs.md) 4. [Writing Shaders](./04-Writing-Shaders.md) \ No newline at end of file diff --git a/Docs/Usage/Render-Passes.md b/Docs/Usage/Render-Passes.md index ffa3ea6a7..6080cb62e 100644 --- a/Docs/Usage/Render-Passes.md +++ b/Docs/Usage/Render-Passes.md @@ -123,6 +123,7 @@ static void regExampleClass(ScriptBindings::Module& m) { auto c = m.regClass(SomeClass); c.property("property", &SomeClass::getProperty, &SomeClass::setProperty); + c.roProperty("readOnlyProperty", &SomeClass::getReadOnlyProperty); } ``` This allows you to access the bound properties of your pass the same way you would access properties for any given instance of a Python class. diff --git a/Docs/Usage/Scene-Creation.md b/Docs/Usage/Scene-Creation.md index d54a31934..e648449d2 100644 --- a/Docs/Usage/Scene-Creation.md +++ b/Docs/Usage/Scene-Creation.md @@ -20,8 +20,8 @@ Scene::SharedPtr pScene = pBuilder->getScene(); Model loading functions also provide an optional parameter for creating multiple instances of a model from file. The following example loads a model from file and creates two instances at positions [-5, 0, 0] and [5, 0, 0]. ```c++ SceneBuilder::InstanceMatrices instances = { - glm::translate(vec3(-5.0f, 0.0f, 0.0f)), - glm::translate(vec3(5.0f, 0.0f, 0.0f)) + glm::translate(float3(-5.0f, 0.0f, 0.0f)), + glm::translate(float3(5.0f, 0.0f, 0.0f)) }; SceneBuilder::SharedPtr pBuilder = SceneBuilder::create("path/to/model.file", SceneBuilder::Flags::Default. instances); diff --git a/Docs/Usage/Scene-Formats.md b/Docs/Usage/Scene-Formats.md new file mode 100644 index 000000000..6beb0b29d --- /dev/null +++ b/Docs/Usage/Scene-Formats.md @@ -0,0 +1,66 @@ +### [Index](../index.md) | [Usage](./index.md) | Scene Formats + +-------- + +# Scene Formats + +Falcor uses [Assimp](https://github.com/assimp/assimp) as its core asset loader and can load all file formats Assimp supports by default. + +From assets, Falcor will import: +- Scene Graph +- Meshes +- Materials + - Diffuse Texture + - Metal-Rough Shading Model (Default) + - RGB: Base Color + - Spec-Gloss Shading Model (Default for OBJ only) + - RGB: Diffuse Color + - Specular Parameters Texture + - Metal-Rough Shading Model (Default) + - R: Occlusion + - G: Roughness + - B: Metallic + - Spec-Gloss Shading Model (Default for OBJ only) + - RGB: Specular Color + - A: Glossiness + - Normals Texture + - Occlusion Texture (Used for Spec-Gloss shading model only) + - Emissive Color/Texture +- The first camera +- Point lights +- Directional lights +- Keyframe animations +- Skinned animations + + +## Python Scene Files + +You can also leverage Falcor's scripting system to set values in the scene on load that are not supported by standard file formats. These are also written in Python, but are formatted differently than normal Falcor scripts. + +### Usage + +The first line must be a Python comment containing only a path to the base asset to be loaded. File paths in Python scene files may be relative to the file itself, in addition to standard Falcor data directories. + +```python +# BistroInterior.fbx +``` + +The asset will be loaded and will be bound to an object called `scene`. Through this object, you have access to any script bindings accessible through Scenes. See the [scripting documentation](./Scripting) for a full list of functions and properties. + +Example: + +```python +# BistroInterior.fbx +# Line above loads BistroInterior.fbx from the same folder as the script + +scene.setEnvMap("BistroInterior.hdr") # Set the environment map to "BistroInterior.hdr" located in the same folder as the script + +bottle_wine = scene.getMaterial("TransparentGlassWine") # Get a material from the scene by name + +# Set material properties +bottle_wine.indexOfRefraction = 1.55 +bottle_wine.specularTransmission = 1 +bottle_wine.doubleSided = True +bottle_wine.nestedPriority = 2 +bottle_wine.volumeAbsorption = float3(0.7143, 1.1688, 1.7169) +``` \ No newline at end of file diff --git a/Docs/Usage/Scripting.md b/Docs/Usage/Scripting.md index 7d5eb10c0..7d008849f 100644 --- a/Docs/Usage/Scripting.md +++ b/Docs/Usage/Scripting.md @@ -8,12 +8,14 @@ #### Global functions -| Function | Description | -|-------------------------------|--------------------------------------------------------------------------| -| `loadRenderPassLibrary(name)` | Load a render pass library. | -| `renderFrame()` | Render a frame. If the clock is not paused, it will advance by one tick. | -| `exit()` | Terminate the application. | -| `cls()` | Clear the console. | +| Function | Description | +|----------------------------------|--------------------------------------------------------------------------| +| `loadRenderPassLibrary(name)` | Load a render pass library. | +| `renderFrame()` | Render a frame. If the clock is not paused, it will advance by one tick. | +| `setWindowPos(x, y)` | Set the window's position in pixels. | +| `resizeSwapChain(width, height)` | Resize the window/swapchain. | +| `exit(errorCode=0)` | Terminate the application with the given error code. | +| `cls()` | Clear the console. | #### Global variables @@ -43,38 +45,43 @@ class falcor.**Renderer** +| Property | Type | Description | +|---------------|---------------|---------------------------------| +| `scene` | `Scene` | Active scene (readonly). | +| `activeGraph` | `RenderGraph` | Active render graph (readonly). | +| `ui` | `bool` | Show/hide the UI. | + | Method | Description | |----------------------------------|-----------------------------------------------------------------| | `script(filename)` | Run a script. | | `loadScene(filename)` | Load a scene. | -| `scene()` | Get the scene. | -| `envMap(filename)` | Load an environment map (temporary workaround). | | `saveConfig(filename)` | Save the current state to a config file. | | `addGraph(graph)` | Add a render graph. | | `removeGraph(graph)` | Remove a render graph. `graph` can be a render graph or a name. | -| `graph(name)` | Get a render graph by name. | -| `activeGraph()` | Get the currently active render graph. | -| `resizeSwapChain(width, height)` | Resize the window/swapchain. | -| `ui(show)` | Show/hide the UI. | +| `getGraph(name)` | Get a render graph by name. | +| `graph(name)` | **DEPRECATED:** Use `getGraph` instead. | +| `resizeSwapChain(width, height)` | **DEPRECATED:** Use global `resizeSwapChain` instead. | +| `envMap(filename)` | **DEPRECATED:** Use `setEnvMap` on `Scene`. | #### Clock class falcor.**Clock** -| Method | Description | -|------------------------|------------------------------------| -| `now()` | Get the current time in _seconds_. | -| `now(seconds)` | Set the current time in _seconds_. | -| `frame()` | Get the current frame number. | -| `frame(frameID)` | Set the current frame number. | -| `pause()` | Pause the clock. | -| `play()` | Resume the clock. | -| `stop()` | Stop the clock (pause and reset) | -| `step(frames = 1)` | Stop forward or backward in time. | -| `framerate()` | Get the framerate. | -| `framerate(framerate)` | Set the framerate. | -| `exitTime(seconds)` | Exit at specific time. | -| `exitFrame(n)` | Exit at specific frame. | +| Property | Type | Description | +|-------------|---------|---------------------------------------------------------------------------------| +| `time` | `float` | Current time in _seconds_. | +| `frame` | `int` | Current frame number. | +| `framerate` | `int` | Frame rate in _frames per second_. | +| `timeScale` | `float` | Time scale factor. | +| `exitTime` | `float` | Time in _seconds_ at which to terminate the application. Set to `0` to disable. | +| `exitFrame` | `int` | Frame at which to terminate the application. Set to `0` to disable. | + +| Method | Description | +|------------------|-----------------------------------| +| `pause()` | Pause the clock. | +| `play()` | Resume the clock. | +| `stop()` | Stop the clock (pause and reset) | +| `step(frames=1)` | Step forward or backward in time. | #### FrameCapture @@ -82,41 +89,45 @@ The frame capture will always dump the marked graph output. You can use `graph.m The frame counter starts at zero in Falcor (it starts by default at one in Maya, so the frame numbers may be offset by one frame). -By default, the captures frames are stored to the executable directory. This can be changed by `fc.outputDir()`. +By default, the captures frames are stored to the executable directory. This can be changed by setting `fc.outputDir`. **Note:** The frame counter is not advanced when time is paused. If you capture with time paused, the captured frame will be overwritten for every rendered frame. The workaround is to change the base filename between captures with `fc.capture()`, see example below. - class falcor.**FrameCapture** -| Method | Description | -|-------------------------|----------------------------------------------------------------------------| -| `outputDir(dir)` | Set the output directory. | -| `baseFilename(name)` | Set the base filename. The frameID and output name will be appended to it. | -| `capture()` | Capture the current frame. | -| `frames(graph, frames)` | Set a list of frames to capture for the given graph. | -| `print()` | Print the requested frames to capture for all available graphs. | -| `print(graph)` | Print the requested frames to capture for the specified graph. | -| `ui(show)` | Show/hide the UI. | +| Property | Type | Description | +|----------------|----------|------------------------------------------------------------------------------| +| `outputDir` | `string` | Capture output directory. | +| `baseFilename` | `string` | Capture base filename. The frameID and output name will be appended to this. | +| `ui` | `bool` | Show/hide the UI. | + +| Method | Description | +|----------------------------|-----------------------------------------------------------------------------| +| `reset(graph)` | Reset frame capturing for the given graph (or all graphs if set to `None`). | +| `capture()` | Capture the current frame. | +| `addFrames(graph, frames)` | Add a list of frames to capture for the given graph. | +| `print()` | Print the requested frames to capture for all available graphs. | +| `print(graph)` | Print the requested frames to capture for the specified graph. | +| `frames(graph, frames)` | **DEPRECATED:** Use `addFrames` instead. | **Example:** *Capture list of frames with clock running and then exit* ```python t.exitFrame(101) -fc.outputDir("../../../Output") -fc.baseFilename("Mogwai") -fc.frames(m.activeGraph(), [20, 50, 100]) +fc.outputDir = "../../../Output" +fc.baseFilename = "Mogwai" +fc.addFrames(m.activeGraph, [20, 50, 100]) ``` **Example:** *Capture frames with clock paused and then exit* ```python t.pause() -fc.outputDir("../../../Output") +fc.outputDir = "../../../Output" frames = [20, 50, 100] for i in range(101): renderFrame() if i in frames: - fc.baseFilename(f"Mogwai-{i:04d}") + fc.baseFilename = f"Mogwai-{i:04d}" fc.capture() exit() ``` @@ -131,34 +142,34 @@ enum falcor.**Codec** class falcor.**VideoCapture** -| Method | Description | -|-------------------------|-------------------------------------------------------------------------------------------------------| -| `outputDir(dir)` | Set the output directory. | -| `baseFilename(name)` | Set the base filename. The output name will be appended to it. | -| `codec(codec)` | Set the codec (`Raw`, `H264`, `HVEC`, `MPEG2`, `MPEG4`). | -| `codec()` | Get the codec. | -| `fps(fps)` | Set tha framerate. | -| `fps()` | Get the framerate. | -| `bitrate(bitrate)` | Set the bitrate in Mpbs. | -| `bitrate()` | Get the bitrate. | -| `gopSize(size)` | Set the GOP size. | -| `gopSize()` | Get the GOP size. | -| `ranges(graph, ranges)` | Set a list of frame ranges to capture for a given graph. `ranges` is a list of `(start, end)` tuples. | -| `print()` | Print the requested frames to capture for all available graphs. | -| `print(graph)` | Print the requested frames to capture for the specified graph. | -| `ui(show)` | Show/hide the UI. | +| Property | Type | Description | +|----------------|----------|------------------------------------------------------------------| +| `outputDir` | `string` | Capture output directory. | +| `baseFilename` | `string` | Capture base filename. The output name will be appended to this. | +| `ui` | `bool` | Show/hide the UI. | +| `codec` | `Codec` | Video codec (`Raw`, `H264`, `HVEC`, `MPEG2`, `MPEG4`). | +| `fps` | `int` | Video frame rate. | +| `bitrate` | `float` | Video bitrate in Mpbs. | +| `gopSize` | `int` | Video GOP size. | + +| Method | Description | +|----------------------------|-------------------------------------------------------------------------------------------------------| +| `reset(graph)` | Reset video capturing for the given graph (or all graphs if set to `None`). | +| `addRanges(graph, ranges)` | Add a list of frame ranges to capture for a given graph. `ranges` is a list of `(start, end)` tuples. | +| `print()` | Print the requested ranges to capture for all available graphs. | +| `print(graph)` | Print the requested ranges to capture for the specified graph. | +| `ranges(graph, ranges)` | **DEPRECATED:** Use `addRanges` instead. | Example: ```python # Video Capture -vc.outputDir(".") -vc.baseFilename("Mogwai") -vc.codec(Codec.H264) -vc.fps(60) -vc.bitrate(4.0) -vc.gopSize(10) -g = m.activeGraph() -vc.ranges(g, [[30, 300]]) +vc.outputDir = "." +vc.baseFilename = "Mogwai" +vc.codec = Codec.H264 +vc.fps = 60 +vc.bitrate = 4.0 +vc.gopSize = 10 +vc.addRanges(m.activeGraph, [[30, 300]]) ``` #### TimingCapture @@ -169,6 +180,12 @@ class falcor.**TimingCapture** |------------------------------|--------------------------------------------------| | `captureFrameTime(filename)` | Start writing frame times to the given filename. | +Example: +```python +# Timing Capture +tc.captureFrameTime("timecapture.csv") +``` + ### Core API module **falcor** @@ -190,11 +207,13 @@ enum falcor.**ResourceFormat** class falcor.**RenderGraph** +| Property | Type | Description | +|----------|----------|---------------------------| +| `name` | `string` | Name of the render graph. | + | Method | Description | |--------------------------------|------------------------------------------------------------------------------------| | `RenderGraph(name)` | Create a new render graph. | -| `name()` | Get the name. | -| `name(name)` | Set the name. | | `addPass(pass, name)` | Add a render pass to the graph. | | `removePass(name)` | Remove a render pass from the graph. | | `updatePass(name, dict)` | Update a render pass with new configuration options in `dict`. | @@ -239,96 +258,107 @@ class falcor.**Texture** class falcor.**Scene** -| Method | Description | -|--------------------------------|-----------------------------------| -| `animate(enable)` | Enable/disable scene animations. | -| `animateCamera(enabled)` | Enable/disable camera animations. | -| `animateLight(index, enabled)` | Enable/disable light animations. | -| `camera()` | Return the camera. | -| `light(index)` | Return a light by index. | -| `light(name)` | Return a light by name. | -| `material(index)` | Return a material by index. | -| `material(name)` | Return a material by name. | -| `removeViewpoint(index)` | Remove a viewpoint. | -| `viewpoint()` | Create a new viewpoint. | -| `viewpoint(index)` | Load a viewpoint. | +| Property | Type | Description | +|----------|----------|-------------| +| `camera` | `Camera` | Camera. | + +| Method | Description | +|--------------------------------------|--------------------------------------------------------| +| `animate(enable)` | Enable/disable scene animations. | +| `animateCamera(enabled)` | Enable/disable camera animations. | +| `animateLight(index, enabled)` | Enable/disable light animations. | +| `setEnvMap(filename)` | Load an environment map from an image. | +| `getLight(index)` | Return a light by index. | +| `getLight(name)` | Return a light by name. | +| `light(index)` | **DEPRECATED:** Use `getLight` instead. | +| `light(name)` | **DEPRECATED:** Use `getLight` instead. | +| `getMaterial(index)` | Return a material by index. | +| `getMaterial(name)` | Return a material by name. | +| `material(index)` | **DEPRECATED:** Use `getMaterial` instead. | +| `material(name)` | **DEPRECATED:** Use `getMaterial` instead. | +| `addViewpoint()` | Add current camera's viewpoint to the viewpoint list. | +| `addViewpoint(position, target, up)` | Add a viewpoint to the viewpoint list. | +| `removeViewpoint()` | Remove selected viewpoint. | +| `selectViewpoint(index)` | Select a specific viewpoint and move the camera to it. | +| `viewpoint()` | **DEPRECATED:** Use `addViewpoint` instead. | +| `viewpoint(index)` | **DEPRECATED:** Use `selectViewpoint` instead. | #### Camera class falcor.**Camera** -| Property | Type | Description | -|------------------|---------|----------------------------------------------| -| `name` | `str` | Name of the camera (readonly). | -| `aspectRatio` | `float` | Image aspect ratio. | -| `focalLength` | `float` | Focal length in millimeters. | -| `frameHeight` | `float` | Frame height in millimeters. | -| `focalDistance` | `float` | Focal distance in scene units. | -| `apertureRadius` | `float` | Apeture radius in scene units. | -| `shutterSpeed` | `float` | Shutter speed in seconds (not implemented). | -| `ISOSpeed` | `float` | Film speed (not implemented). | -| `nearPlane` | `float` | Near plane distance in scene units. | -| `farPlane` | `float` | Far plane distance in scene units. | -| `position` | `vec3` | Camera position in world space. | -| `target` | `vec3` | Camera target in world space. | -| `up` | `vec` | Camera up vector in world space. | +| Property | Type | Description | +|------------------|----------|----------------------------------------------| +| `name` | `str` | Name of the camera (readonly). | +| `aspectRatio` | `float` | Image aspect ratio. | +| `focalLength` | `float` | Focal length in millimeters. | +| `frameHeight` | `float` | Frame height in millimeters. | +| `focalDistance` | `float` | Focal distance in scene units. | +| `apertureRadius` | `float` | Apeture radius in scene units. | +| `shutterSpeed` | `float` | Shutter speed in seconds (not implemented). | +| `ISOSpeed` | `float` | Film speed (not implemented). | +| `nearPlane` | `float` | Near plane distance in scene units. | +| `farPlane` | `float` | Far plane distance in scene units. | +| `position` | `float3` | Camera position in world space. | +| `target` | `float3` | Camera target in world space. | +| `up` | `float3` | Camera up vector in world space. | #### Material class falcor.**Material** -| Property | Type | Description | -|------------------------|---------|-------------------------------------------------------| -| `name` | `str` | Name of the material (readonly). | -| `baseColor` | `vec4` | Base color (linear RGB) and opacity. | -| `specularParams` | `vec4` | Specular parameters (occlusion, roughness, metallic). | -| `specularTransmission` | `float` | Specular transmission (0 = opaque, 1 = transparent). | -| `indexOfRefraction` | `float` | Index of refraction. | -| `emissiveColor` | `vec3` | Emissive color (linear RGB). | -| `emissiveFactor` | `float` | Multiplier for emissive color. | -| `alphaMode` | `int` | Alpha mode (0 = opaque, 1 = masked). | -| `alphaThreshold` | `float` | Alpha masking threshold (0-1). | -| `doubleSided` | `bool` | Enable double sided rendering. | -| `nestedPriority` | `int` | Nested priority for nested dielectrics. | +| Property | Type | Description | +|------------------------|----------|-------------------------------------------------------| +| `name` | `str` | Name of the material (readonly). | +| `baseColor` | `float4` | Base color (linear RGB) and opacity. | +| `specularParams` | `float4` | Specular parameters (occlusion, roughness, metallic). | +| `specularTransmission` | `float` | Specular transmission (0 = opaque, 1 = transparent). | +| `indexOfRefraction` | `float` | Index of refraction. | +| `emissiveColor` | `float3` | Emissive color (linear RGB). | +| `emissiveFactor` | `float` | Multiplier for emissive color. | +| `alphaMode` | `int` | Alpha mode (0 = opaque, 1 = masked). | +| `alphaThreshold` | `float` | Alpha masking threshold (0-1). | +| `doubleSided` | `bool` | Enable double sided rendering. | +| `nestedPriority` | `int` | Nested priority for nested dielectrics. | #### Light class falcor.**Light** -| Property | Type | Description | -|-------------|---------|-------------------------------| -| `name` | `str` | Name of the light (readonly). | -| `color` | `vec3` | Color of the light. | -| `intensity` | `float` | Intensity of the light. | +| Property | Type | Description | +|-------------|----------|-------------------------------| +| `name` | `str` | Name of the light (readonly). | +| `color` | `float3` | Color of the light. | +| `intensity` | `float` | Intensity of the light. | class falcor.**DirectionalLight** -| Property | Type | Description | -|-------------|---------|----------------------------------------| -| `name` | `str` | Name of the light (readonly). | -| `color` | `vec3` | Color of the light. | -| `intensity` | `float` | Intensity of the light. | -| `direction` | `vec3` | Direction of the light in world space. | +| Property | Type | Description | +|-------------|----------|----------------------------------------| +| `name` | `str` | Name of the light (readonly). | +| `color` | `float3` | Color of the light. | +| `intensity` | `float` | Intensity of the light. | +| `direction` | `float3` | Direction of the light in world space. | class falcor.**PointLight** -| Property | Type | Description | -|-----------------|---------|----------------------------------------| -| `name` | `str` | Name of the light (readonly). | -| `color` | `vec3` | Color of the light. | -| `intensity` | `float` | Intensity of the light. | -| `position` | `vec3` | Position of the light in world space. | -| `direction` | `vec3` | Direction of the light in world space. | -| `openingAngle` | `float` | Opening half-angle in radians. | -| `penumbraAngle` | `float` | Penumbra half-angle in radians. | +| Property | Type | Description | +|-----------------|----------|----------------------------------------| +| `name` | `str` | Name of the light (readonly). | +| `color` | `float3` | Color of the light. | +| `intensity` | `float` | Intensity of the light. | +| `position` | `float3` | Position of the light in world space. | +| `direction` | `float3` | Direction of the light in world space. | +| `openingAngle` | `float` | Opening half-angle in radians. | +| `penumbraAngle` | `float` | Penumbra half-angle in radians. | class falcor.**AnalyticAreaLight** -| Property | Type | Description | -|-------------|---------|-------------------------------| -| `name` | `str` | Name of the light (readonly). | -| `color` | `vec3` | Color of the light. | -| `intensity` | `float` | Intensity of the light. | +| Property | Type | Description | +|-------------|----------|-------------------------------| +| `name` | `str` | Name of the light (readonly). | +| `color` | `float3` | Color of the light. | +| `intensity` | `float` | Intensity of the light. | ### Render Passes @@ -386,7 +416,7 @@ class falcor.**CSM** | Property | Type | Description | |----------------------|---------|-------------| | `cascadeCount` | `int` | | -| `mapSize` | `uvec2` | | +| `mapSize` | `uint2` | | | `visibilityBitCount` | `int` | | | `filter` | `int` | | | `sdsmLatency` | `int` | | diff --git a/Docs/Usage/index.md b/Docs/Usage/index.md index 6d549c6f5..b333e2bb2 100644 --- a/Docs/Usage/index.md +++ b/Docs/Usage/index.md @@ -7,6 +7,7 @@ - [Environment Variables](./Environment-Variables.md) - [Scene Creation](./Scene-Creation.md) - [Scenes](./Scenes.md) +- [Scene Formats](./Scene-Formats.md) - [Scripting](./Scripting.md) - [Render Passes](./Render-Passes.md) - [Path Tracer](./Path-Tracer.md) \ No newline at end of file diff --git a/Falcor.sln b/Falcor.sln index d48bba851..2ec2c30ef 100644 --- a/Falcor.sln +++ b/Falcor.sln @@ -82,6 +82,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageCompare", "Source\Tool EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MegakernelPathTracer", "Source\RenderPasses\MegakernelPathTracer\MegakernelPathTracer.vcxproj", "{873F13CA-A9C7-47BA-857D-8848C5E7F07E}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WhittedRayTracer", "Source\RenderPasses\WhittedRayTracer\WhittedRayTracer.vcxproj", "{431C3127-E613-424C-B964-FB53DAA87789}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution DebugD3D12|x64 = DebugD3D12|x64 @@ -208,6 +210,10 @@ Global {873F13CA-A9C7-47BA-857D-8848C5E7F07E}.DebugD3D12|x64.Build.0 = Debug|x64 {873F13CA-A9C7-47BA-857D-8848C5E7F07E}.ReleaseD3D12|x64.ActiveCfg = Release|x64 {873F13CA-A9C7-47BA-857D-8848C5E7F07E}.ReleaseD3D12|x64.Build.0 = Release|x64 + {431C3127-E613-424C-B964-FB53DAA87789}.DebugD3D12|x64.ActiveCfg = Debug|x64 + {431C3127-E613-424C-B964-FB53DAA87789}.DebugD3D12|x64.Build.0 = Debug|x64 + {431C3127-E613-424C-B964-FB53DAA87789}.ReleaseD3D12|x64.ActiveCfg = Release|x64 + {431C3127-E613-424C-B964-FB53DAA87789}.ReleaseD3D12|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -242,6 +248,7 @@ Global {E484AEEC-ED88-408E-ADA5-66DF6301D75B} = {D16038A7-B031-4181-B4A1-2C416C02330C} {8F6B5FAB-30FA-45C6-B5EA-BCD1D26781C0} = {935D7586-B55D-431A-A0ED-338383DE1A1E} {873F13CA-A9C7-47BA-857D-8848C5E7F07E} = {D16038A7-B031-4181-B4A1-2C416C02330C} + {431C3127-E613-424C-B964-FB53DAA87789} = {D16038A7-B031-4181-B4A1-2C416C02330C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {357B2AE0-FE30-4AC6-8D41-B580232BC0DE} diff --git a/README.md b/README.md index 40409c8fd..d97ffd15b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Falcor 4.0 +# Falcor 4.1 Falcor is a real-time rendering framework supporting DirectX 12. It aims to improve productivity of research and prototype projects. diff --git a/Source/Falcor/Core/API/BlendState.h b/Source/Falcor/Core/API/BlendState.h index a943b9d9a..78d17c90e 100644 --- a/Source/Falcor/Core/API/BlendState.h +++ b/Source/Falcor/Core/API/BlendState.h @@ -82,9 +82,9 @@ namespace Falcor /** Set the constant blend factor \param[in] factor Blend factor */ - Desc& setBlendFactor(const glm::vec4& factor) { mBlendFactor = factor; return *this; } + Desc& setBlendFactor(const float4& factor) { mBlendFactor = factor; return *this; } - /** Enable/disable independent blend modes for different render target. Only used when multiple render-targets are bound. + /** Enable/disable independent blend modes for different render target. Only used when multiple render-targets are bound. \param[in] enabled True If false, will use RenderTargetDesc[0] for all the bound render-targets. Otherwise, will use the entire RenderTargetDesc[] array. */ Desc& setIndependentBlend(bool enabled) { mEnableIndependentBlend = enabled; return *this; } @@ -136,7 +136,7 @@ namespace Falcor std::vector mRtDesc; bool mEnableIndependentBlend = false; bool mAlphaToCoverageEnabled = false; - glm::vec4 mBlendFactor = glm::vec4(0, 0, 0, 0); + float4 mBlendFactor = float4(0, 0, 0, 0); }; ~BlendState(); @@ -149,7 +149,7 @@ namespace Falcor /** Get the constant blend factor color */ - const glm::vec4& getBlendFactor() const { return mDesc.mBlendFactor; } + const float4& getBlendFactor() const { return mDesc.mBlendFactor; } /** Get the RGB blend operation */ diff --git a/Source/Falcor/Core/API/Buffer.h b/Source/Falcor/Core/API/Buffer.h index c16a860cd..0052d8946 100644 --- a/Source/Falcor/Core/API/Buffer.h +++ b/Source/Falcor/Core/API/Buffer.h @@ -62,7 +62,7 @@ namespace Falcor Write, ///< Map the buffer for write access. Buffer had to be created with CpuAccess::Write flag. WriteDiscard, ///< Map the buffer for write access, discarding the previous content of the entire buffer. Buffer had to be created with CpuAccess::Write flag. }; - + ~Buffer(); /** Create a new buffer. @@ -314,9 +314,9 @@ namespace Falcor CASE(int32_t, ResourceFormat::R32Int); // Optionally supported formats as a set on D3D12. If one is supported all are supported. - CASE(vec4, ResourceFormat::RGBA32Float); - CASE(uvec4, ResourceFormat::RGBA32Uint); - CASE(ivec4, ResourceFormat::RGBA32Int); + CASE(float4, ResourceFormat::RGBA32Float); + CASE(uint4, ResourceFormat::RGBA32Uint); + CASE(int4, ResourceFormat::RGBA32Int); //R16G16B16A16_FLOAT //R16G16B16A16_UINT //R16G16B16A16_SINT @@ -333,9 +333,9 @@ namespace Falcor // Optionally and individually supported formats on D3D12. Query for support individually. //R16G16B16A16_UNORM //R16G16B16A16_SNORM - CASE(vec2, ResourceFormat::RG32Float); - CASE(uvec2, ResourceFormat::RG32Uint); - CASE(ivec2, ResourceFormat::RG32Int); + CASE(float2, ResourceFormat::RG32Float); + CASE(uint2, ResourceFormat::RG32Uint); + CASE(int2, ResourceFormat::RG32Int); //R10G10B10A2_UNORM //R10G10B10A2_UINT //R11G11B10_FLOAT @@ -358,7 +358,7 @@ namespace Falcor //B4G4R4A4_UNORM // Additional formats that may be supported on some hardware. - CASE(vec3, ResourceFormat::RGB32Float); + CASE(float3, ResourceFormat::RGB32Float); #undef CASE }; diff --git a/Source/Falcor/Core/API/ComputeContext.h b/Source/Falcor/Core/API/ComputeContext.h index 111eb3966..3dfa400fd 100644 --- a/Source/Falcor/Core/API/ComputeContext.h +++ b/Source/Falcor/Core/API/ComputeContext.h @@ -49,7 +49,7 @@ namespace Falcor /** Dispatch a compute task \param[in] dispatchSize 3D dispatch group size */ - void dispatch(ComputeState* pState, ComputeVars* pVars, const uvec3& dispatchSize); + void dispatch(ComputeState* pState, ComputeVars* pVars, const uint3& dispatchSize); /** Executes a dispatch call. Args to the dispatch call are contained in pArgBuffer */ @@ -59,20 +59,20 @@ namespace Falcor \param[in] pUav The UAV to clear \param[in] value The clear value */ - void clearUAV(const UnorderedAccessView* pUav, const vec4& value); + void clearUAV(const UnorderedAccessView* pUav, const float4& value); /** Clear an unordered-access view \param[in] pUav The UAV to clear \param[in] value The clear value */ - void clearUAV(const UnorderedAccessView* pUav, const uvec4& value); + void clearUAV(const UnorderedAccessView* pUav, const uint4& value); /** Clear a structured buffer's UAV counter \param[in] pBuffer Structured Buffer containing UAV counter \param[in] value Value to clear counter to */ void clearUAVCounter(Buffer::ConstSharedPtrRef& pBuffer, uint32_t value); - + /** Submit the command list */ virtual void flush(bool wait = false) override; diff --git a/Source/Falcor/Core/API/CopyContext.cpp b/Source/Falcor/Core/API/CopyContext.cpp index 02d58aa28..36581cddb 100644 --- a/Source/Falcor/Core/API/CopyContext.cpp +++ b/Source/Falcor/Core/API/CopyContext.cpp @@ -73,7 +73,7 @@ namespace Falcor return CopyContext::ReadTextureTask::create(this, pTexture, subresourceIndex); } - std::vector CopyContext::readTextureSubresource(const Texture* pTexture, uint32_t subresourceIndex) + std::vector CopyContext::readTextureSubresource(const Texture* pTexture, uint32_t subresourceIndex) { CopyContext::ReadTextureTask::SharedPtr pTask = asyncReadTextureSubresource(pTexture, subresourceIndex); return pTask->getData(); @@ -154,7 +154,7 @@ namespace Falcor updateTextureSubresources(pTexture, 0, subresourceCount, pData); } - void CopyContext::updateSubresourceData(const Texture* pDst, uint32_t subresource, const void* pData, const uvec3& offset, const uvec3& size) + void CopyContext::updateSubresourceData(const Texture* pDst, uint32_t subresource, const void* pData, const uint3& offset, const uint3& size) { mCommandsPending = true; updateTextureSubresources(pDst, subresource, 1, pData, offset, size); diff --git a/Source/Falcor/Core/API/CopyContext.h b/Source/Falcor/Core/API/CopyContext.h index ab8d7a7ba..561a68100 100644 --- a/Source/Falcor/Core/API/CopyContext.h +++ b/Source/Falcor/Core/API/CopyContext.h @@ -44,7 +44,7 @@ namespace Falcor public: using SharedPtr = std::shared_ptr; static SharedPtr create(CopyContext* pCtx, const Texture* pTexture, uint32_t subresourceIndex); - std::vector getData(); + std::vector getData(); private: ReadTextureTask() = default; GpuFence::SharedPtr mpFence; @@ -105,13 +105,13 @@ namespace Falcor /** Copy a region of a subresource from one texture to another `srcOffset`, `dstOffset` and `size` describe the source and destination regions. For any channel of `extent` that is -1, the source texture dimension will be used */ - void copySubresourceRegion(const Texture* pDst, uint32_t dstSubresource, const Texture* pSrc, uint32_t srcSubresource, const uvec3& dstOffset = uvec3(0), const uvec3& srcOffset = uvec3(0), const uvec3& size = uvec3(-1)); + void copySubresourceRegion(const Texture* pDst, uint32_t dstSubresource, const Texture* pSrc, uint32_t srcSubresource, const uint3& dstOffset = uint3(0), const uint3& srcOffset = uint3(0), const uint3& size = uint3(-1)); /** Update a texture's subresource data `offset` and `size` describe a region to update. For any channel of `extent` that is -1, the texture dimension will be used. pData can't be null. The size of the pointed buffer must be equal to a single texel size times the size of the region we are updating */ - void updateSubresourceData(const Texture* pDst, uint32_t subresource, const void* pData, const uvec3& offset = uvec3(0), const uvec3& size = uvec3(-1)); + void updateSubresourceData(const Texture* pDst, uint32_t subresource, const void* pData, const uint3& offset = uint3(0), const uint3& size = uint3(-1)); /** Update an entire texture */ @@ -123,7 +123,7 @@ namespace Falcor /** Read texture data synchronously. Calling this command will flush the pipeline and wait for the GPU to finish execution */ - std::vector readTextureSubresource(const Texture* pTexture, uint32_t subresourceIndex); + std::vector readTextureSubresource(const Texture* pTexture, uint32_t subresourceIndex); /** Read texture data Asynchronously */ @@ -148,7 +148,7 @@ namespace Falcor bool bufferBarrier(const Buffer* pBuffer, Resource::State newState); bool subresourceBarriers(const Texture* pTexture, Resource::State newState, const ResourceViewInfo* pViewInfo); void apiSubresourceBarrier(const Texture* pTexture, Resource::State newState, Resource::State oldState, uint32_t arraySlice, uint32_t mipLevel); - void updateTextureSubresources(const Texture* pTexture, uint32_t firstSubresource, uint32_t subresourceCount, const void* pData, const uvec3& offset = uvec3(0), const uvec3& size = uvec3(-1)); + void updateTextureSubresources(const Texture* pTexture, uint32_t firstSubresource, uint32_t subresourceCount, const void* pData, const uint3& offset = uint3(0), const uint3& size = uint3(-1)); bool mCommandsPending = false; LowLevelContextData::SharedPtr mpLowLevelData; diff --git a/Source/Falcor/Core/API/D3D12/D3D12ComputeContext.cpp b/Source/Falcor/Core/API/D3D12/D3D12ComputeContext.cpp index 2ca0ab107..77f6347a1 100644 --- a/Source/Falcor/Core/API/D3D12/D3D12ComputeContext.cpp +++ b/Source/Falcor/Core/API/D3D12/D3D12ComputeContext.cpp @@ -85,7 +85,7 @@ namespace Falcor auto pCSO = pState->getCSO(pVars); - // Apply the vars. Must be first because applyComputeVars() might cause a flush + // Apply the vars. Must be first because applyComputeVars() might cause a flush if (pVars) { if (applyComputeVars(pVars, pCSO->getDesc().getProgramKernels()->getRootSignature().get()) == false) return false; @@ -98,7 +98,7 @@ namespace Falcor return true; } - void ComputeContext::dispatch(ComputeState* pState, ComputeVars* pVars, const uvec3& dispatchSize) + void ComputeContext::dispatch(ComputeState* pState, ComputeVars* pVars, const uint3& dispatchSize) { // Check dispatch dimensions. TODO: Should be moved into Falcor. if (dispatchSize.x > D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION || @@ -119,11 +119,11 @@ namespace Falcor { pContext->resourceBarrier(pUav->getResource(), Resource::State::UnorderedAccess); UavHandle uav = pUav->getApiHandle(); - if (typeid(ClearType) == typeid(vec4)) + if (typeid(ClearType) == typeid(float4)) { pList->ClearUnorderedAccessViewFloat(uav->getGpuHandle(0), uav->getCpuHandle(0), pUav->getResource()->getApiHandle(), (float*)value_ptr(clear), 0, nullptr); } - else if (typeid(ClearType) == typeid(uvec4)) + else if (typeid(ClearType) == typeid(uint4)) { pList->ClearUnorderedAccessViewUint(uav->getGpuHandle(0), uav->getCpuHandle(0), pUav->getResource()->getApiHandle(), (uint32_t*)value_ptr(clear), 0, nullptr); } @@ -133,13 +133,13 @@ namespace Falcor } } - void ComputeContext::clearUAV(const UnorderedAccessView* pUav, const vec4& value) + void ComputeContext::clearUAV(const UnorderedAccessView* pUav, const float4& value) { clearUavCommon(this, pUav, value, mpLowLevelData->getCommandList().GetInterfacePtr()); mCommandsPending = true; } - void ComputeContext::clearUAV(const UnorderedAccessView* pUav, const uvec4& value) + void ComputeContext::clearUAV(const UnorderedAccessView* pUav, const uint4& value) { clearUavCommon(this, pUav, value, mpLowLevelData->getCommandList().GetInterfacePtr()); mCommandsPending = true; @@ -149,7 +149,7 @@ namespace Falcor { if (pBuffer->getUAVCounter()) { - clearUAV(pBuffer->getUAVCounter()->getUAV().get(), uvec4(value)); + clearUAV(pBuffer->getUAVCounter()->getUAV().get(), uint4(value)); } } diff --git a/Source/Falcor/Core/API/D3D12/D3D12CopyContext.cpp b/Source/Falcor/Core/API/D3D12/D3D12CopyContext.cpp index b67911d50..55873737f 100644 --- a/Source/Falcor/Core/API/D3D12/D3D12CopyContext.cpp +++ b/Source/Falcor/Core/API/D3D12/D3D12CopyContext.cpp @@ -71,9 +71,9 @@ namespace Falcor } } - void CopyContext::updateTextureSubresources(const Texture* pTexture, uint32_t firstSubresource, uint32_t subresourceCount, const void* pData, const uvec3& offset, const uvec3& size) + void CopyContext::updateTextureSubresources(const Texture* pTexture, uint32_t firstSubresource, uint32_t subresourceCount, const void* pData, const uint3& offset, const uint3& size) { - bool copyRegion = (offset != uvec3(0)) || (size != uvec3(-1)); + bool copyRegion = (offset != uint3(0)) || (size != uint3(-1)); assert(subresourceCount == 1 || (copyRegion == false)); mCommandsPending = true; @@ -154,7 +154,7 @@ namespace Falcor ID3D12Device* pDevice = gpDevice->getApiHandle(); pDevice->GetCopyableFootprints(&texDesc, subresourceIndex, 1, 0, &footprint, &pThis->mRowCount, &rowSize, &size); - //Create buffer + //Create buffer pThis->mpBuffer = Buffer::create(size, Buffer::BindFlags::None, Buffer::CpuAccess::Read, nullptr); //Copy from texture to buffer @@ -178,10 +178,10 @@ namespace Falcor D3D12_PLACED_SUBRESOURCE_FOOTPRINT& footprint = mFootprint; //Get buffer data - std::vector result; + std::vector result; uint32_t actualRowSize = footprint.Footprint.Width * getFormatBytesPerBlock(mTextureFormat); result.resize(mRowCount * actualRowSize); - uint8* pData = reinterpret_cast(mpBuffer->map(Buffer::MapType::Read)); + uint8_t* pData = reinterpret_cast(mpBuffer->map(Buffer::MapType::Read)); for (uint32_t z = 0; z < footprint.Footprint.Depth; z++) { @@ -312,7 +312,7 @@ namespace Falcor mCommandsPending = true; } - void CopyContext::copySubresourceRegion(const Texture* pDst, uint32_t dstSubresource, const Texture* pSrc, uint32_t srcSubresource, const uvec3& dstOffset, const uvec3& srcOffset, const uvec3& size) + void CopyContext::copySubresourceRegion(const Texture* pDst, uint32_t dstSubresource, const Texture* pSrc, uint32_t srcSubresource, const uint3& dstOffset, const uint3& srcOffset, const uint3& size) { resourceBarrier(pDst, Resource::State::CopyDest); resourceBarrier(pSrc, Resource::State::CopySource); diff --git a/Source/Falcor/Core/API/D3D12/D3D12GpuTimer.cpp b/Source/Falcor/Core/API/D3D12/D3D12GpuTimer.cpp index 56de3af67..8bf4b2618 100644 --- a/Source/Falcor/Core/API/D3D12/D3D12GpuTimer.cpp +++ b/Source/Falcor/Core/API/D3D12/D3D12GpuTimer.cpp @@ -43,7 +43,7 @@ namespace Falcor void GpuTimer::apiResolve(uint64_t result[2]) { mpLowLevelData->getCommandList()->ResolveQueryData(spHeap.lock()->getApiHandle(), D3D12_QUERY_TYPE_TIMESTAMP, mStart, 2, mpResolveBuffer->getApiHandle(), 0); - uint64_t* pRes = (uint64*)mpResolveBuffer->map(Buffer::MapType::Read); + uint64_t* pRes = (uint64_t*)mpResolveBuffer->map(Buffer::MapType::Read); result[0] = pRes[0]; result[1] = pRes[1]; mpResolveBuffer->unmap(); diff --git a/Source/Falcor/Core/API/D3D12/D3D12RenderContext.cpp b/Source/Falcor/Core/API/D3D12/D3D12RenderContext.cpp index fcde77c5e..52cb88895 100644 --- a/Source/Falcor/Core/API/D3D12/D3D12RenderContext.cpp +++ b/Source/Falcor/Core/API/D3D12/D3D12RenderContext.cpp @@ -54,8 +54,8 @@ namespace Falcor Sampler::SharedPtr pPointSampler; ParameterBlock::SharedPtr pSrcRectBuffer; - vec2 prevSrcRectOffset = vec2(0, 0); - vec2 prevSrcReftScale = vec2(0, 0); + float2 prevSrcRectOffset = float2(0, 0); + float2 prevSrcReftScale = float2(0, 0); // Variable offsets in constant buffer UniformShaderVarOffset offsetVarOffset; @@ -85,8 +85,8 @@ namespace Falcor blitData.pSrcRectBuffer = blitData.pPass->getVars()->getParameterBlock("SrcRectCB"); blitData.offsetVarOffset = blitData.pSrcRectBuffer->getVariableOffset("gOffset"); blitData.scaleVarOffset = blitData.pSrcRectBuffer->getVariableOffset("gScale"); - blitData.prevSrcRectOffset = vec2(-1.0f); - blitData.prevSrcReftScale = vec2(-1.0f); + blitData.prevSrcRectOffset = float2(-1.0f); + blitData.prevSrcReftScale = float2(-1.0f); Sampler::Desc desc; desc.setFilterMode(Sampler::Filter::Linear, Sampler::Filter::Linear, Sampler::Filter::Point).setAddressingMode(Sampler::AddressMode::Clamp, Sampler::AddressMode::Clamp, Sampler::AddressMode::Clamp); @@ -137,7 +137,7 @@ namespace Falcor RenderContextApiData::release(); } - void RenderContext::clearRtv(const RenderTargetView* pRtv, const glm::vec4& color) + void RenderContext::clearRtv(const RenderTargetView* pRtv, const float4& color) { resourceBarrier(pRtv->getResource(), Resource::State::RenderTarget); mpLowLevelData->getCommandList()->ClearRenderTargetView(pRtv->getApiHandle()->getCpuHandle(0), glm::value_ptr(color), 0, nullptr); @@ -415,7 +415,7 @@ namespace Falcor pList4->DispatchRays(&raytraceDesc); } - void RenderContext::blit(ShaderResourceView::SharedPtr pSrc, RenderTargetView::SharedPtr pDst, const uvec4& srcRect, const uvec4& dstRect, Sampler::Filter filter) + void RenderContext::blit(ShaderResourceView::SharedPtr pSrc, RenderTargetView::SharedPtr pDst, const uint4& srcRect, const uint4& dstRect, Sampler::Filter filter) { auto& blitData = sApiData.blitData; blitData.pPass->getVars()->setSampler("gSampler", (filter == Sampler::Filter::Linear) ? blitData.pLinearSampler : blitData.pPointSampler); @@ -427,8 +427,8 @@ namespace Falcor const Texture* pDstTexture = dynamic_cast(pDst->getResource()); assert(pSrcTexture != nullptr && pDstTexture != nullptr); - vec2 srcRectOffset(0.0f); - vec2 srcRectScale(1.0f); + float2 srcRectOffset(0.0f); + float2 srcRectScale(1.0f); uint32_t srcMipLevel = pSrc->getViewInfo().mostDetailedMip; uint32_t dstMipLevel = pDst->getViewInfo().mostDetailedMip; GraphicsState::Viewport dstViewport(0.0f, 0.0f, (float)pDstTexture->getWidth(dstMipLevel), (float)pDstTexture->getHeight(dstMipLevel), 0.0f, 1.0f); @@ -436,9 +436,9 @@ namespace Falcor // If src rect specified if (srcRect.x != (uint32_t)-1) { - const vec2 srcSize(pSrcTexture->getWidth(srcMipLevel), pSrcTexture->getHeight(srcMipLevel)); - srcRectOffset = vec2(srcRect.x, srcRect.y) / srcSize; - srcRectScale = vec2(srcRect.z - srcRect.x, srcRect.w - srcRect.y) / srcSize; + const float2 srcSize(pSrcTexture->getWidth(srcMipLevel), pSrcTexture->getHeight(srcMipLevel)); + srcRectOffset = float2(srcRect.x, srcRect.y) / srcSize; + srcRectScale = float2(srcRect.z - srcRect.x, srcRect.w - srcRect.y) / srcSize; } // If dest rect specified diff --git a/Source/Falcor/Core/API/D3D12/D3D12State.cpp b/Source/Falcor/Core/API/D3D12/D3D12State.cpp index 7f6fa7e04..ddf49ef7a 100644 --- a/Source/Falcor/Core/API/D3D12/D3D12State.cpp +++ b/Source/Falcor/Core/API/D3D12/D3D12State.cpp @@ -362,7 +362,7 @@ namespace Falcor desc.MinLOD = pSampler->getMinLod(); desc.MaxLOD = pSampler->getMaxLod(); - const glm::vec4& borderColor = pSampler->getBorderColor(); + const float4& borderColor = pSampler->getBorderColor(); memcpy(desc.BorderColor, glm::value_ptr(borderColor), sizeof(borderColor)); } diff --git a/Source/Falcor/Core/API/DescriptorPool.h b/Source/Falcor/Core/API/DescriptorPool.h index b39946835..68d33e660 100644 --- a/Source/Falcor/Core/API/DescriptorPool.h +++ b/Source/Falcor/Core/API/DescriptorPool.h @@ -63,7 +63,7 @@ namespace Falcor Count }; - static const uint32_t kTypeCount = uint32(Type::Count); + static const uint32_t kTypeCount = uint32_t(Type::Count); class dlldecl Desc { diff --git a/Source/Falcor/Core/API/FBO.cpp b/Source/Falcor/Core/API/FBO.cpp index 7bf262963..fd1bcdc46 100644 --- a/Source/Falcor/Core/API/FBO.cpp +++ b/Source/Falcor/Core/API/FBO.cpp @@ -299,9 +299,9 @@ namespace Falcor mIsLayered = (attachment.arraySize > 1); } - mWidth = min(mWidth, pTexture->getWidth(attachment.mipLevel)); - mHeight = min(mHeight, pTexture->getHeight(attachment.mipLevel)); - mDepth = min(mDepth, pTexture->getDepth(attachment.mipLevel)); + mWidth = std::min(mWidth, pTexture->getWidth(attachment.mipLevel)); + mHeight = std::min(mHeight, pTexture->getHeight(attachment.mipLevel)); + mDepth = std::min(mDepth, pTexture->getDepth(attachment.mipLevel)); { if ( (pTexture->getSampleCount() > mTempDesc.getSampleCount()) && isDepthStencilFormat(pTexture->getFormat()) ) diff --git a/Source/Falcor/Core/API/FBO.h b/Source/Falcor/Core/API/FBO.h index d11171914..8d4911491 100644 --- a/Source/Falcor/Core/API/FBO.h +++ b/Source/Falcor/Core/API/FBO.h @@ -219,8 +219,8 @@ namespace Falcor struct SamplePosition { - int8 xOffset = 0; - int8 yOffset = 0; + int8_t xOffset = 0; + int8_t yOffset = 0; }; /** Configure the sample positions used by multi-sampled buffers. diff --git a/Source/Falcor/Core/API/RenderContext.cpp b/Source/Falcor/Core/API/RenderContext.cpp index 2cd320ff7..4dffb4106 100644 --- a/Source/Falcor/Core/API/RenderContext.cpp +++ b/Source/Falcor/Core/API/RenderContext.cpp @@ -37,7 +37,7 @@ namespace Falcor return SharedPtr(new RenderContext(queue)); } - void RenderContext::clearFbo(const Fbo* pFbo, const glm::vec4& color, float depth, uint8_t stencil, FboAttachmentType flags) + void RenderContext::clearFbo(const Fbo* pFbo, const float4& color, float depth, uint8_t stencil, FboAttachmentType flags) { bool hasDepthStencilTexture = pFbo->getDepthStencilTexture() != nullptr; ResourceFormat depthStencilFormat = hasDepthStencilTexture ? pFbo->getDepthStencilTexture()->getFormat() : ResourceFormat::Unknown; @@ -64,7 +64,7 @@ namespace Falcor } - void RenderContext::clearTexture(Texture* pTexture, const vec4& clearColor) + void RenderContext::clearTexture(Texture* pTexture, const float4& clearColor) { assert(pTexture); diff --git a/Source/Falcor/Core/API/RenderContext.h b/Source/Falcor/Core/API/RenderContext.h index a83e8b4f8..5b262ac4a 100644 --- a/Source/Falcor/Core/API/RenderContext.h +++ b/Source/Falcor/Core/API/RenderContext.h @@ -83,13 +83,13 @@ namespace Falcor \param[in] flags Optional. Which components of the FBO to clear. By default will clear all attached resource. If you'd like to clear a specific color target, you can use RenderContext#clearFboColorTarget(). */ - void clearFbo(const Fbo* pFbo, const glm::vec4& color, float depth, uint8_t stencil, FboAttachmentType flags = FboAttachmentType::All); + void clearFbo(const Fbo* pFbo, const float4& color, float depth, uint8_t stencil, FboAttachmentType flags = FboAttachmentType::All); /** Clear a render-target view. \param[in] pRtv The RTV to clear \param[in] color The clear color */ - void clearRtv(const RenderTargetView* pRtv, const glm::vec4& color); + void clearRtv(const RenderTargetView* pRtv, const float4& color); /** Clear a depth-stencil view. \param[in] pDsv The DSV to clear @@ -105,7 +105,7 @@ namespace Falcor \param[in] clearColor The clear color The function only support floating-point and normalized color-formats and depth. For depth buffers, `clearColor.x` will be used. If there's a stencil-channel, `clearColor.y` must be zero */ - void clearTexture(Texture* pTexture, const vec4& clearColor = vec4(0, 0, 0, 1)); + void clearTexture(Texture* pTexture, const float4& clearColor = float4(0, 0, 0, 1)); /** Ordered draw call. \param[in] vertexCount Number of vertices to draw @@ -161,7 +161,7 @@ namespace Falcor \param[in] srcRect Source rectangle to blit from, specified by [left, up, right, down] \param[in] dstRect Target rectangle to blit to, specified by [left, up, right, down] */ - void blit(ShaderResourceView::SharedPtr pSrc, RenderTargetView::SharedPtr pDst, const uvec4& srcRect = uvec4(-1), const uvec4& dstRect = uvec4(-1), Sampler::Filter = Sampler::Filter::Linear); + void blit(ShaderResourceView::SharedPtr pSrc, RenderTargetView::SharedPtr pDst, const uint4& srcRect = uint4(-1), const uint4& dstRect = uint4(-1), Sampler::Filter = Sampler::Filter::Linear); /** Submit the command list */ diff --git a/Source/Falcor/Core/API/Sampler.cpp b/Source/Falcor/Core/API/Sampler.cpp index 49f8b4665..2e62c03d0 100644 --- a/Source/Falcor/Core/API/Sampler.cpp +++ b/Source/Falcor/Core/API/Sampler.cpp @@ -41,7 +41,7 @@ namespace Falcor { gSamplerData.objectCount++; } - + Sampler::~Sampler() { gSamplerData.objectCount--; @@ -75,7 +75,7 @@ namespace Falcor mComparisonMode = mode; return *this; } - + Sampler::Desc& Sampler::Desc::setAddressingMode(AddressMode modeU, AddressMode modeV, AddressMode modeW) { mModeU = modeU; @@ -84,7 +84,7 @@ namespace Falcor return *this; } - Sampler::Desc& Sampler::Desc::setBorderColor(const glm::vec4& borderColor) + Sampler::Desc& Sampler::Desc::setBorderColor(const float4& borderColor) { mBorderColor = borderColor; return *this; diff --git a/Source/Falcor/Core/API/Sampler.h b/Source/Falcor/Core/API/Sampler.h index 4aaf41e30..9ffe4b12a 100644 --- a/Source/Falcor/Core/API/Sampler.h +++ b/Source/Falcor/Core/API/Sampler.h @@ -54,7 +54,7 @@ namespace Falcor Wrap, ///< Wrap around Mirror, ///< Wrap around and mirror on every integer junction Clamp, ///< Clamp the normalized coordinates to [0, 1] - Border, ///< If out-of-bound, use the sampler's border color + Border, ///< If out-of-bound, use the sampler's border color MirrorOnce ///< Same as Mirror, but mirrors only once around 0 }; @@ -100,7 +100,7 @@ namespace Falcor /** Set the border color. Only applies when the addressing mode is ClampToBorder */ - Desc& setBorderColor(const glm::vec4& borderColor); + Desc& setBorderColor(const float4& borderColor); protected: Filter mMagFilter = Filter::Linear; @@ -114,7 +114,7 @@ namespace Falcor AddressMode mModeU = AddressMode::Wrap; AddressMode mModeV = AddressMode::Wrap; AddressMode mModeW = AddressMode::Wrap; - glm::vec4 mBorderColor = glm::vec4(0, 0, 0, 0); + float4 mBorderColor = float4(0, 0, 0, 0); }; ~Sampler(); @@ -175,7 +175,7 @@ namespace Falcor /** Get the border color */ - const glm::vec4& getBorderColor() const { return mDesc.mBorderColor; } + const float4& getBorderColor() const { return mDesc.mBorderColor; } /** Get the descriptor that was used to create the sampler. */ diff --git a/Source/Falcor/Core/API/Texture.cpp b/Source/Falcor/Core/API/Texture.cpp index 5d941e11a..5763c80d5 100644 --- a/Source/Falcor/Core/API/Texture.cpp +++ b/Source/Falcor/Core/API/Texture.cpp @@ -253,7 +253,7 @@ namespace Falcor // Handle the special case where we have an HDR texture with less then 3 channels FormatType type = getFormatType(mFormat); uint32_t channels = getFormatChannelCount(mFormat); - std::vector textureData; + std::vector textureData; ResourceFormat resourceFormat = mFormat; if (type == FormatType::Float && channels < 3) @@ -364,6 +364,6 @@ namespace Falcor { return gpDevice->getRenderContext()->readTextureSubresource(pTexture, subresource); }; - c.func_("data", data); + c.func_("data", data, "subresource"_a); } } diff --git a/Source/Falcor/Core/API/Texture.h b/Source/Falcor/Core/API/Texture.h index 509e53970..704f6c654 100644 --- a/Source/Falcor/Core/API/Texture.h +++ b/Source/Falcor/Core/API/Texture.h @@ -52,15 +52,15 @@ namespace Falcor /** Get a mip-level width */ - uint32_t getWidth(uint32_t mipLevel = 0) const { return (mipLevel == 0) || (mipLevel < mMipLevels) ? max(1U, mWidth >> mipLevel) : 0; } + uint32_t getWidth(uint32_t mipLevel = 0) const { return (mipLevel == 0) || (mipLevel < mMipLevels) ? std::max(1U, mWidth >> mipLevel) : 0; } /** Get a mip-level height */ - uint32_t getHeight(uint32_t mipLevel = 0) const { return (mipLevel == 0) || (mipLevel < mMipLevels) ? max(1U, mHeight >> mipLevel) : 0; } + uint32_t getHeight(uint32_t mipLevel = 0) const { return (mipLevel == 0) || (mipLevel < mMipLevels) ? std::max(1U, mHeight >> mipLevel) : 0; } /** Get a mip-level depth */ - uint32_t getDepth(uint32_t mipLevel = 0) const { return (mipLevel == 0) || (mipLevel < mMipLevels) ? max(1U, mDepth >> mipLevel) : 0; } + uint32_t getDepth(uint32_t mipLevel = 0) const { return (mipLevel == 0) || (mipLevel < mMipLevels) ? std::max(1U, mDepth >> mipLevel) : 0; } /** Get the number of mip-levels */ @@ -164,7 +164,7 @@ namespace Falcor \return A pointer to a new texture, or throws an exception if creation failed. */ static SharedPtr create2DMS(uint32_t width, uint32_t height, ResourceFormat format, uint32_t sampleCount, uint32_t arraySize = 1, BindFlags bindFlags = BindFlags::ShaderResource); - + /** Create a new texture object from a file. \param[in] filename Filename of the image. Can also include a full path or relative path from a data directory. \param[in] generateMipLevels Whether the mip-chain should be generated. @@ -224,11 +224,11 @@ namespace Falcor */ void generateMips(RenderContext* pContext); - /** In case the texture was loaded from a file, use this to set the filename + /** In case the texture was loaded from a file, use this to set the file path */ void setSourceFilename(const std::string& filename) { mSourceFilename = filename; } - /** In case the texture was loaded from a file, get the source filename + /** In case the texture was loaded from a file, get the source file path */ const std::string& getSourceFilename() const { return mSourceFilename; } @@ -252,7 +252,7 @@ namespace Falcor uint32_t mArraySize = 0; ResourceFormat mFormat = ResourceFormat::Unknown; bool mIsSparse = false; - glm::i32vec3 mSparsePageRes = glm::i32vec3(0); + int3 mSparsePageRes = int3(0); friend class Device; }; diff --git a/Source/Falcor/Core/API/TextureLoader.cpp b/Source/Falcor/Core/API/TextureLoader.cpp index f0b33f89c..e3729c2a5 100644 --- a/Source/Falcor/Core/API/TextureLoader.cpp +++ b/Source/Falcor/Core/API/TextureLoader.cpp @@ -505,8 +505,8 @@ namespace Falcor for (uint32_t mipCounter = 0; mipCounter < mipDepth; ++mipCounter) { - uint32_t heightPitch = max(width >> mipCounter, 1U) * getFormatBytesPerBlock(format); - uint32_t currentMipHeight = max(height >> mipCounter, 1U); + uint32_t heightPitch = std::max(width >> mipCounter, 1U) * getFormatBytesPerBlock(format); + uint32_t currentMipHeight = std::max(height >> mipCounter, 1U); uint32_t depthPitch = currentMipHeight * heightPitch; for (uint32_t depthCounter = 0; depthCounter < depth; ++depthCounter) @@ -540,14 +540,7 @@ namespace Falcor bool loadDDSDataFromFile(const std::string filename, DdsData& ddsData) { - std::string fullpath; - if (findFileInDataDirectories(filename, fullpath) == false) - { - logError("Error when loading DDS file. Can't find texture file " + filename); - return false; - } - - BinaryFileStream stream(fullpath, BinaryFileStream::Mode::Read); + BinaryFileStream stream(filename, BinaryFileStream::Mode::Read); // Check the dds identifier uint32_t ddsIdentifier; @@ -680,7 +673,7 @@ namespace Falcor uint32_t mipLevels; if (generateMips == false || isCompressedFormat(format)) { - mipLevels = (ddsData.header.flags & DdsHeader::kMipCountMask) ? max(ddsData.header.mipCount, 1U) : 1; + mipLevels = (ddsData.header.flags & DdsHeader::kMipCountMask) ? std::max(ddsData.header.mipCount, 1U) : 1; } else { @@ -699,14 +692,21 @@ namespace Falcor Texture::SharedPtr Texture::createFromFile(const std::string& filename, bool generateMipLevels, bool loadAsSrgb, Texture::BindFlags bindFlags) { + std::string fullpath; + if (findFileInDataDirectories(filename, fullpath) == false) + { + logError("Error when loading image file. Can't find image file " + filename); + return nullptr; + } + Texture::SharedPtr pTex; if (hasSuffix(filename, ".dds")) { - pTex = createTextureFromDDSFile(filename, generateMipLevels, loadAsSrgb, bindFlags); + pTex = createTextureFromDDSFile(fullpath, generateMipLevels, loadAsSrgb, bindFlags); } else { - Bitmap::UniqueConstPtr pBitmap = Bitmap::createFromFile(filename, kTopDown); + Bitmap::UniqueConstPtr pBitmap = Bitmap::createFromFile(fullpath, kTopDown); if (pBitmap) { ResourceFormat texFormat = pBitmap->getFormat(); @@ -721,7 +721,7 @@ namespace Falcor if (pTex != nullptr) { - pTex->setSourceFilename(stripDataDirectories(filename)); + pTex->setSourceFilename(fullpath); } return pTex; diff --git a/Source/Falcor/Core/API/VertexLayout.h b/Source/Falcor/Core/API/VertexLayout.h index 39cf22e2b..c7fb0cefc 100644 --- a/Source/Falcor/Core/API/VertexLayout.h +++ b/Source/Falcor/Core/API/VertexLayout.h @@ -194,27 +194,6 @@ namespace Falcor */ size_t getBufferCount() const { return mpBufferLayouts.size(); } - /** Add defines to notify a shader program about vertex what input properties have associated buffer data - */ - void addVertexAttribDclToProg(Program* pProg) const - { - pProg->removeDefine("HAS_LIGHTMAP_UV"); - - for (const auto& l : mpBufferLayouts) - { - if(l) - { - for (uint32_t i = 0; i < l->getElementCount(); i++) - { - if (l->getElementShaderLocation(i) == VERTEX_LIGHTMAP_UV_LOC) - { - pProg->addDefine("HAS_LIGHTMAP_UV"); - } - } - } - } - } - private: VertexLayout() { mpBufferLayouts.reserve(16); } std::vector mpBufferLayouts; diff --git a/Source/Falcor/Core/API/Vulkan/VKComputeContext.cpp b/Source/Falcor/Core/API/Vulkan/VKComputeContext.cpp index bf768e132..4a338f949 100644 --- a/Source/Falcor/Core/API/Vulkan/VKComputeContext.cpp +++ b/Source/Falcor/Core/API/Vulkan/VKComputeContext.cpp @@ -76,15 +76,15 @@ namespace Falcor vkCmdClearColorImage(pCtx->getLowLevelData()->getCommandList(), pView->getResource()->getApiHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &colVal, 1, &range); } - template void clearColorImageCommon(CopyContext* pCtx, const RenderTargetView* pView, const vec4& clearVal); + template void clearColorImageCommon(CopyContext* pCtx, const RenderTargetView* pView, const float4& clearVal); - void ComputeContext::clearUAV(const UnorderedAccessView* pUav, const vec4& value) + void ComputeContext::clearUAV(const UnorderedAccessView* pUav, const float4& value) { clearColorImageCommon(this, pUav, value); mCommandsPending = true; } - void ComputeContext::clearUAV(const UnorderedAccessView* pUav, const uvec4& value) + void ComputeContext::clearUAV(const UnorderedAccessView* pUav, const uint4& value) { if(pUav->getApiHandle().getType() == VkResourceType::Buffer) { @@ -106,7 +106,7 @@ namespace Falcor { if (pBuffer->hasUAVCounter()) { - clearUAV(pBuffer->getUAVCounter()->getUAV().get(), uvec4(value)); + clearUAV(pBuffer->getUAVCounter()->getUAV().get(), uint4(value)); } } diff --git a/Source/Falcor/Core/API/Vulkan/VKCopyContext.cpp b/Source/Falcor/Core/API/Vulkan/VKCopyContext.cpp index 57438c493..1cf3744ea 100644 --- a/Source/Falcor/Core/API/Vulkan/VKCopyContext.cpp +++ b/Source/Falcor/Core/API/Vulkan/VKCopyContext.cpp @@ -165,7 +165,7 @@ namespace Falcor { } - static void initTexAccessParams(const Texture* pTexture, uint32_t subresourceIndex, VkBufferImageCopy& vkCopy, Buffer::SharedPtr& pStaging, const void* pSrcData, const uvec3& offset, const uvec3& size, size_t& dataSize) + static void initTexAccessParams(const Texture* pTexture, uint32_t subresourceIndex, VkBufferImageCopy& vkCopy, Buffer::SharedPtr& pStaging, const void* pSrcData, const uint3& offset, const uint3& size, size_t& dataSize) { assert(isDepthStencilFormat(pTexture->getFormat()) == false); // #VKTODO Nothing complicated here, just that Vulkan doesn't support writing to both depth and stencil, which may be confusing to the user uint32_t mipLevel = pTexture->getSubresourceMipLevel(subresourceIndex); @@ -189,7 +189,7 @@ namespace Falcor vkCopy.bufferOffset = pStaging->getGpuAddressOffset(); } - static void updateTextureSubresource(CopyContext* pCtx, const Texture* pTexture, uint32_t subresourceIndex, const void* pData, const uvec3& offset, const uvec3& size) + static void updateTextureSubresource(CopyContext* pCtx, const Texture* pTexture, uint32_t subresourceIndex, const void* pData, const uint3& offset, const uint3& size) { VkBufferImageCopy vkCopy; Buffer::SharedPtr pStaging; @@ -202,9 +202,9 @@ namespace Falcor vkCmdCopyBufferToImage(pCtx->getLowLevelData()->getCommandList(), pStaging->getApiHandle(), pTexture->getApiHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &vkCopy); } - void CopyContext::updateTextureSubresources(const Texture* pTexture, uint32_t firstSubresource, uint32_t subresourceCount, const void* pData, const uvec3& offset, const uvec3& size) + void CopyContext::updateTextureSubresources(const Texture* pTexture, uint32_t firstSubresource, uint32_t subresourceCount, const void* pData, const uint3& offset, const uint3& size) { - bool copyRegion = (offset != uvec3(0)) || (size != uvec3(-1)); + bool copyRegion = (offset != uint3(0)) || (size != uint3(-1)); assert(subresourceCount == 1 || (copyRegion == false)); mCommandsPending = true; @@ -225,7 +225,7 @@ namespace Falcor pThis->mpContext = pCtx; VkBufferImageCopy vkCopy; - initTexAccessParams(pTexture, subresourceIndex, vkCopy, pThis->mpBuffer, nullptr, {}, uvec3(-1, -1, -1), pThis->mDataSize); + initTexAccessParams(pTexture, subresourceIndex, vkCopy, pThis->mpBuffer, nullptr, {}, uint3(-1, -1, -1), pThis->mDataSize); // Execute the copy pCtx->resourceBarrier(pTexture, Resource::State::CopySource); @@ -415,7 +415,7 @@ namespace Falcor mCommandsPending = true; } - void CopyContext::copySubresourceRegion(const Texture* pDst, uint32_t dstSubresource, const Texture* pSrc, uint32_t srcSubresource, const uvec3& dstOffset, const uvec3& srcOffset, const uvec3& size) + void CopyContext::copySubresourceRegion(const Texture* pDst, uint32_t dstSubresource, const Texture* pSrc, uint32_t srcSubresource, const uint3& dstOffset, const uint3& srcOffset, const uint3& size) { resourceBarrier(pDst, Resource::State::CopyDest); resourceBarrier(pSrc, Resource::State::CopySource); diff --git a/Source/Falcor/Core/API/Vulkan/VKGpuFence.cpp b/Source/Falcor/Core/API/Vulkan/VKGpuFence.cpp index 97e5300b2..fd594502e 100644 --- a/Source/Falcor/Core/API/Vulkan/VKGpuFence.cpp +++ b/Source/Falcor/Core/API/Vulkan/VKGpuFence.cpp @@ -148,7 +148,7 @@ namespace Falcor pFence->mCpuValue = 1; return pFence; } - + uint64_t GpuFence::gpuSignal(CommandQueueHandle pQueue) { assert(pQueue); @@ -203,7 +203,7 @@ namespace Falcor vk_call(vkQueueSubmit(pQueue, 1, &submit, nullptr)); mpApiData->semaphoreWaitList.clear(); } - + void releaseSemaphores(FenceApiData* pApiData) { size_t sems = pApiData->semaphoreQueue.getActiveObjects().size(); @@ -214,7 +214,7 @@ namespace Falcor size_t wait = pApiData->semaphoreWaitList.size(); assert(wait <= sems); size_t waitDelta = sems - wait; - size_t count = min(waitDelta, fenceDelta); + size_t count = std::minwaitDelta, fenceDelta); pApiData->semaphoreQueue.popFront(count); } diff --git a/Source/Falcor/Core/API/Vulkan/VKRenderContext.cpp b/Source/Falcor/Core/API/Vulkan/VKRenderContext.cpp index 735f36ced..1f6165797 100644 --- a/Source/Falcor/Core/API/Vulkan/VKRenderContext.cpp +++ b/Source/Falcor/Core/API/Vulkan/VKRenderContext.cpp @@ -47,7 +47,7 @@ namespace Falcor template void clearColorImageCommon(CopyContext* pCtx, const ViewType* pView, const ClearType& clearVal); - void RenderContext::clearRtv(const RenderTargetView* pRtv, const glm::vec4& color) + void RenderContext::clearRtv(const RenderTargetView* pRtv, const float4& color) { clearColorImageCommon(this, pRtv, color); mCommandsPending = true; @@ -262,7 +262,7 @@ namespace Falcor } template - void initBlitData(const ViewType* pView, const uvec4& rect, VkImageSubresourceLayers& layer, VkOffset3D offset[offsetCount]) + void initBlitData(const ViewType* pView, const uint4& rect, VkImageSubresourceLayers& layer, VkOffset3D offset[offsetCount]) { const Texture* pTex = dynamic_cast(pView->getResource()); @@ -285,7 +285,7 @@ namespace Falcor } } - void RenderContext::blit(ShaderResourceView::SharedPtr pSrc, RenderTargetView::SharedPtr pDst, const uvec4& srcRect, const uvec4& dstRect, Sampler::Filter filter) + void RenderContext::blit(ShaderResourceView::SharedPtr pSrc, RenderTargetView::SharedPtr pDst, const uint4& srcRect, const uint4& dstRect, Sampler::Filter filter) { const Texture* pTexture = dynamic_cast(pSrc->getResource()); resourceBarrier(pSrc->getResource(), Resource::State::CopySource, &pSrc->getViewInfo()); @@ -301,7 +301,7 @@ namespace Falcor resolve.extent.width = pTexture->getWidth(viewInfo.mostDetailedMip); resolve.extent.height = pTexture->getHeight(viewInfo.mostDetailedMip); resolve.extent.depth = 1; - + vkCmdResolveImage(mpLowLevelData->getCommandList(), pSrc->getResource()->getApiHandle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, pDst->getResource()->getApiHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &resolve); } else diff --git a/Source/Falcor/Core/API/Vulkan/VKRootSignature.cpp b/Source/Falcor/Core/API/Vulkan/VKRootSignature.cpp index 4a13bae91..75f8afb64 100644 --- a/Source/Falcor/Core/API/Vulkan/VKRootSignature.cpp +++ b/Source/Falcor/Core/API/Vulkan/VKRootSignature.cpp @@ -64,7 +64,7 @@ namespace Falcor } return flags; } - + VkDescriptorSetLayout createDescriptorSetLayout(const DescriptorSet::Layout& layout) { std::vector bindings(layout.getRangeCount()); @@ -98,7 +98,7 @@ namespace Falcor uint32_t maxIndex = 0; for (const auto& set : mDesc.mSets) { - maxIndex = max(set.getRange(0).regSpace, maxIndex); + maxIndex = std::max(set.getRange(0).regSpace, maxIndex); } static VkDescriptorSetLayout emptyLayout = createDescriptorSetLayout({}); // #VKTODO This gets deleted multiple times on exit diff --git a/Source/Falcor/Core/API/Vulkan/VKState.cpp b/Source/Falcor/Core/API/Vulkan/VKState.cpp index a362c4110..0d77df7d2 100644 --- a/Source/Falcor/Core/API/Vulkan/VKState.cpp +++ b/Source/Falcor/Core/API/Vulkan/VKState.cpp @@ -186,7 +186,7 @@ namespace Falcor infoOut.info.attachmentCount = (uint32_t)infoOut.attachmentStates.size(); infoOut.info.pAttachments = infoOut.attachmentStates.data(); - const vec4 blendColor = pState->getBlendFactor(); + const float4 blendColor = pState->getBlendFactor(); infoOut.info.blendConstants[0] = blendColor.r; infoOut.info.blendConstants[1] = blendColor.g; infoOut.info.blendConstants[2] = blendColor.b; @@ -445,11 +445,11 @@ namespace Falcor } } - VkBorderColor getVkBorderColor(const glm::vec4& color) + VkBorderColor getVkBorderColor(const float4& color) { - if (color == vec4(0)) return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - if (color == vec4(0, 0, 0, 1)) return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - if (color == vec4(1)) return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + if (color == float4(0)) return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + if (color == float4(0, 0, 0, 1)) return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + if (color == float4(1)) return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; logWarning("Unsupported Vulkan border color. Vulkan only supports transparent black, opaque black or opaque white. Defaulting to opaque black"); return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; } diff --git a/Source/Falcor/Core/API/Vulkan/VKTexture.cpp b/Source/Falcor/Core/API/Vulkan/VKTexture.cpp index 585f97f6f..227d1ba0f 100644 --- a/Source/Falcor/Core/API/Vulkan/VKTexture.cpp +++ b/Source/Falcor/Core/API/Vulkan/VKTexture.cpp @@ -139,7 +139,7 @@ namespace Falcor imageInfo.format = getVkFormat(mFormat); imageInfo.imageType = getVkImageType(mType); imageInfo.initialLayout = pData ? VK_IMAGE_LAYOUT_PREINITIALIZED : VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.mipLevels = min(mMipLevels, getMaxMipCount(imageInfo.extent)); + imageInfo.mipLevels = std::min(mMipLevels, getMaxMipCount(imageInfo.extent)); imageInfo.pQueueFamilyIndices = nullptr; imageInfo.queueFamilyIndexCount = 0; imageInfo.samples = (VkSampleCountFlagBits)mSampleCount; @@ -162,7 +162,7 @@ namespace Falcor throw std::exception("Failed to create texture."); } - // Allocate the GPU memory + // Allocate the GPU memory VkMemoryRequirements memRequirements; vkGetImageMemoryRequirements(gpDevice->getApiHandle(), image, &memRequirements); VkDeviceMemory deviceMem = allocateDeviceMemory(Device::MemoryType::Default, memRequirements.memoryTypeBits, memRequirements.size); diff --git a/Source/Falcor/Core/BufferTypes/ParameterBlock.cpp b/Source/Falcor/Core/BufferTypes/ParameterBlock.cpp index dd49550ed..976194da6 100644 --- a/Source/Falcor/Core/BufferTypes/ParameterBlock.cpp +++ b/Source/Falcor/Core/BufferTypes/ParameterBlock.cpp @@ -246,7 +246,7 @@ namespace Falcor return false; } } - + ParameterBlock::~ParameterBlock() = default; ParameterBlock::SharedPtr ParameterBlock::create(const std::shared_ptr& pProgramVersion, const ReflectionType::SharedConstPtr& pElementType) @@ -888,24 +888,24 @@ namespace Falcor { #define c_to_prog(cType, progType) if(typeid(VarType) == typeid(cType)) return ReflectionBasicType::Type::progType; c_to_prog(bool, Bool); - c_to_prog(bvec2, Bool2); - c_to_prog(bvec3, Bool3); - c_to_prog(bvec4, Bool4); + c_to_prog(bool2, Bool2); + c_to_prog(bool3, Bool3); + c_to_prog(bool4, Bool4); c_to_prog(int32_t, Int); - c_to_prog(ivec2, Int2); - c_to_prog(ivec3, Int3); - c_to_prog(ivec4, Int4); + c_to_prog(int2, Int2); + c_to_prog(int3, Int3); + c_to_prog(int4, Int4); c_to_prog(uint32_t, Uint); - c_to_prog(uvec2, Uint2); - c_to_prog(uvec3, Uint3); - c_to_prog(uvec4, Uint4); + c_to_prog(uint2, Uint2); + c_to_prog(uint3, Uint3); + c_to_prog(uint4, Uint4); - c_to_prog(float, Float); - c_to_prog(glm::vec2, Float2); - c_to_prog(glm::vec3, Float3); - c_to_prog(glm::vec4, Float4); + c_to_prog(float, Float); + c_to_prog(float2, Float2); + c_to_prog(float3, Float3); + c_to_prog(float4, Float4); c_to_prog(glm::mat2, Float2x2); c_to_prog(glm::mat2x3, Float2x3); @@ -915,7 +915,7 @@ namespace Falcor c_to_prog(glm::mat3x2, Float3x2); c_to_prog(glm::mat3x4, Float3x4); - c_to_prog(glm::mat4, Float4x4); + c_to_prog(glm::mat4, Float4x4); c_to_prog(glm::mat4x2, Float4x2); c_to_prog(glm::mat4x3, Float4x3); @@ -1198,24 +1198,24 @@ namespace Falcor #define set_constant_by_offset(_t) template dlldecl bool ParameterBlock::setVariable(UniformShaderVarOffset offset, const _t& value) set_constant_by_offset(bool); - set_constant_by_offset(glm::bvec2); - set_constant_by_offset(glm::bvec3); - set_constant_by_offset(glm::bvec4); + set_constant_by_offset(bool2); + set_constant_by_offset(bool3); + set_constant_by_offset(bool4); set_constant_by_offset(uint32_t); - set_constant_by_offset(glm::uvec2); - set_constant_by_offset(glm::uvec3); - set_constant_by_offset(glm::uvec4); + set_constant_by_offset(uint2); + set_constant_by_offset(uint3); + set_constant_by_offset(uint4); set_constant_by_offset(int32_t); - set_constant_by_offset(glm::ivec2); - set_constant_by_offset(glm::ivec3); - set_constant_by_offset(glm::ivec4); + set_constant_by_offset(int2); + set_constant_by_offset(int3); + set_constant_by_offset(int4); set_constant_by_offset(float); - set_constant_by_offset(glm::vec2); - set_constant_by_offset(glm::vec3); - set_constant_by_offset(glm::vec4); + set_constant_by_offset(float2); + set_constant_by_offset(float3); + set_constant_by_offset(float4); set_constant_by_offset(glm::mat2); set_constant_by_offset(glm::mat2x3); @@ -1276,7 +1276,7 @@ namespace Falcor pContext->resourceBarrier(pBuffer->getUAVCounter().get(), Resource::State::UnorderedAccess); pContext->uavBarrier(pBuffer->getUAVCounter().get()); } - + bool insertBarrier = true; #ifdef FALCOR_D3D12 insertBarrier = (is_set(pResource->getBindFlags(), Resource::BindFlags::AccelerationStructure) == false); diff --git a/Source/Falcor/Core/BufferTypes/VariablesBufferUI.cpp b/Source/Falcor/Core/BufferTypes/VariablesBufferUI.cpp index 584d87bbf..9709a71a5 100644 --- a/Source/Falcor/Core/BufferTypes/VariablesBufferUI.cpp +++ b/Source/Falcor/Core/BufferTypes/VariablesBufferUI.cpp @@ -55,13 +55,13 @@ namespace Falcor switch (type) { case ReflectionBasicType::Type::Bool4: - to_gui_widget_bvec(checkbox, glm::bvec4); + to_gui_widget_bvec(checkbox, bool4); break; case ReflectionBasicType::Type::Bool3: - to_gui_widget_bvec(checkbox, glm::bvec3); + to_gui_widget_bvec(checkbox, bool3); break; case ReflectionBasicType::Type::Bool2: - to_gui_widget_bvec(checkbox, glm::bvec2); + to_gui_widget_bvec(checkbox, bool2); break; case ReflectionBasicType::Type::Bool: to_gui_widget(checkbox, bool); @@ -70,19 +70,19 @@ namespace Falcor case ReflectionBasicType::Type::Uint64_4: case ReflectionBasicType::Type::Int4: case ReflectionBasicType::Type::Int64_4: - to_gui_widget(var, glm::ivec4); + to_gui_widget(var, int4); break; case ReflectionBasicType::Type::Uint3: case ReflectionBasicType::Type::Uint64_3: case ReflectionBasicType::Type::Int3: case ReflectionBasicType::Type::Int64_3: - to_gui_widget(var, glm::ivec3); + to_gui_widget(var, int3); break; case ReflectionBasicType::Type::Uint2: case ReflectionBasicType::Type::Uint64_2: case ReflectionBasicType::Type::Int2: case ReflectionBasicType::Type::Int64_2: - to_gui_widget(var, glm::ivec2); + to_gui_widget(var, int2); break; case ReflectionBasicType::Type::Uint: case ReflectionBasicType::Type::Uint64: @@ -94,13 +94,13 @@ namespace Falcor to_gui_widget(var, float); break; case ReflectionBasicType::Type::Float2: - to_gui_widget(var, glm::vec2); + to_gui_widget(var, float2); break; case ReflectionBasicType::Type::Float3: - to_gui_widget(var, glm::vec3); + to_gui_widget(var, float3); break; case ReflectionBasicType::Type::Float4: - to_gui_widget(var, glm::vec4); + to_gui_widget(var, float4); break; case ReflectionBasicType::Type::Float2x2: to_gui_widget_matrix(matrix, glm::mat2x2); diff --git a/Source/Falcor/Core/Framework.h b/Source/Falcor/Core/Framework.h index e073af726..946ea66db 100644 --- a/Source/Falcor/Core/Framework.h +++ b/Source/Falcor/Core/Framework.h @@ -53,6 +53,7 @@ #include #include #include +#include #include "Utils/Logger.h" #include "Utils/Math/Vector.h" @@ -193,7 +194,7 @@ namespace Falcor template inline T clamp(const T& val, const T& minVal, const T& maxVal) { - return min(max(val, minVal), maxVal); + return std::min(std::max(val, minVal), maxVal); } /** Returns whether an integer number is a power of two. @@ -320,7 +321,8 @@ namespace Falcor // Required to_string functions using std::to_string; inline std::string to_string(const std::string& s) { return '"' + s + '"'; } // Here for completeness - inline std::string to_string(bool b) { return b ? "true" : "false"; } + // Use upper case True/False for compatibility with Python + inline std::string to_string(bool b) { return b ? "True" : "False"; } template std::string to_string(const std::pair& p) @@ -355,12 +357,12 @@ namespace Falcor #if defined(_MSC_VER) // Enable Windows visual styles #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") -#define deprecate(_ver_, _msg_) __declspec(deprecated("This function is deprecated and will be removed in Falcor " ## _ver_ ## ". " ## _msg_)) +#define deprecate(_ver_, _msg_) __declspec(deprecated("This function has been deprecated in " ## _ver_ ## ". " ## _msg_)) #define forceinline __forceinline using DllHandle = HMODULE; #define suppress_deprecation __pragma(warning(suppress : 4996)); #elif defined(__GNUC__) -#define deprecate(_ver_, _msg_) __attribute__ ((deprecated("This function is deprecated and will be removed in Falcor " _ver_ ". " _msg_))) +#define deprecate(_ver_, _msg_) __attribute__ ((deprecated("This function has been deprecated in " _ver_ ". " _msg_))) #define forceinline __attribute__((always_inline)) using DllHandle = void*; #define suppress_deprecation _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") diff --git a/Source/Falcor/Core/Platform/Linux/Linux.cpp b/Source/Falcor/Core/Platform/Linux/Linux.cpp index 073c93148..c5324c96b 100644 --- a/Source/Falcor/Core/Platform/Linux/Linux.cpp +++ b/Source/Falcor/Core/Platform/Linux/Linux.cpp @@ -240,6 +240,12 @@ namespace Falcor return std::string(); } + const std::string getAppDataDirectory() + { + assert(0); + return std::string(); + } + const std::string& getExecutableName() { static std::string filename = std::filesystem::path(program_invocation_name).filename(); @@ -431,7 +437,7 @@ namespace Falcor cpu_set_t cpuMask; CPU_ZERO(&cpuMask); - uint32_t bitCount = min(sizeof(cpu_set_t), sizeof(uint32_t)) * 8; + uint32_t bitCount = std::min(sizeof(cpu_set_t), sizeof(uint32_t)) * 8; for (uint32_t i = 0; i < bitCount; i++) { if ((affinityMask & (1 << i)) > 0) diff --git a/Source/Falcor/Core/Platform/MonitorInfo.cpp b/Source/Falcor/Core/Platform/MonitorInfo.cpp index d97d20db5..5a90be8c9 100644 --- a/Source/Falcor/Core/Platform/MonitorInfo.cpp +++ b/Source/Falcor/Core/Platform/MonitorInfo.cpp @@ -33,13 +33,13 @@ #include "Utils/StringUtils.h" #pragma comment(lib, "setupapi.lib") - -// With some inspiration from: + +// With some inspiration from: // http://ofekshilon.com/2011/11/13/reading-monitor-physical-dimensions-or-getting-the-edid-the-right-way/ // http://ofekshilon.com/2014/06/19/reading-specific-monitor-dimensions/ #define NAME_SIZE 128 - + namespace Falcor { // Assumes hDevRegKey is valid @@ -129,38 +129,38 @@ namespace Falcor MONITORINFOEX mi; mi.cbSize = sizeof(MONITORINFOEX); GetMonitorInfo(hMonitor, &mi); - + DISPLAY_DEVICE dd; dd.cb = sizeof(dd); DWORD devIdx = 0; // device index - + bool bFoundDevice = false; while (EnumDisplayDevices(0, devIdx, &dd, 0)) { devIdx++; if (0 != wcscmp(dd.DeviceName, mi.szDevice)) continue; - + DISPLAY_DEVICE ddMon; ZeroMemory(&ddMon, sizeof(ddMon)); ddMon.cb = sizeof(ddMon); DWORD MonIdx = 0; - + while (EnumDisplayDevices(dd.DeviceName, MonIdx, &ddMon, 0)) { MonIdx++; - + ddMonOut = ddMon; return TRUE; - + ZeroMemory(&ddMon, sizeof(ddMon)); ddMon.cb = sizeof(ddMon); } - + ZeroMemory(&dd, sizeof(dd)); dd.cb = sizeof(dd); } - + return FALSE; } @@ -191,12 +191,12 @@ namespace Falcor MonitorInfo::MonitorDesc desc; desc.mIdentifier = wstring_2_string(DeviceID); - desc.mResolution = glm::vec2( - abs(info.rcMonitor.left - info.rcMonitor.right), + desc.mResolution = float2( + abs(info.rcMonitor.left - info.rcMonitor.right), abs(info.rcMonitor.top - info.rcMonitor.bottom)); //printf("%fx%f mm\n", WidthMm, HeightMm ); - desc.mPhysicalSize = glm::vec2(wInch, hInch); + desc.mPhysicalSize = float2(wInch, hInch); auto vPpi = desc.mResolution / desc.mPhysicalSize; desc.mPpi = (vPpi.x + vPpi.y) * 0.5f; desc.mIsPrimary = (info.dwFlags & MONITORINFOF_PRIMARY); diff --git a/Source/Falcor/Core/Platform/MonitorInfo.h b/Source/Falcor/Core/Platform/MonitorInfo.h index a14c27039..6e913ef27 100644 --- a/Source/Falcor/Core/Platform/MonitorInfo.h +++ b/Source/Falcor/Core/Platform/MonitorInfo.h @@ -41,8 +41,8 @@ namespace Falcor struct MonitorDesc { std::string mIdentifier; - glm::vec2 mResolution; - glm::vec2 mPhysicalSize; + float2 mResolution; + float2 mPhysicalSize; float mPpi; bool mIsPrimary; }; diff --git a/Source/Falcor/Core/Platform/OS.cpp b/Source/Falcor/Core/Platform/OS.cpp index bf15c58e1..a799c48f5 100644 --- a/Source/Falcor/Core/Platform/OS.cpp +++ b/Source/Falcor/Core/Platform/OS.cpp @@ -150,10 +150,10 @@ namespace Falcor bool findFileInDataDirectories(const std::string& filename, std::string& fullPath) { // Check if this is an absolute path - if (doesFileExist(filename)) + if (fs::path(filename).is_absolute()) { fullPath = canonicalizeFilename(filename); - return true; + return !fullPath.empty(); // Empty fullPath means path doesn't exist } for (const auto& dir : gDataDirectories) diff --git a/Source/Falcor/Core/Platform/OS.h b/Source/Falcor/Core/Platform/OS.h index cefcb707a..6b3eb9540 100644 --- a/Source/Falcor/Core/Platform/OS.h +++ b/Source/Falcor/Core/Platform/OS.h @@ -250,6 +250,10 @@ namespace Falcor */ dlldecl const std::string getWorkingDirectory(); + /** Get the application data directory. + */ + dlldecl const std::string getAppDataDirectory(); + /** Get the content of a system environment variable. \param[in] varName Name of the environment variable \param[out] value On success, will hold the value of the environment variable. diff --git a/Source/Falcor/Core/Platform/Windows/Windows.cpp b/Source/Falcor/Core/Platform/Windows/Windows.cpp index 1b62f6a01..de2ce41de 100644 --- a/Source/Falcor/Core/Platform/Windows/Windows.cpp +++ b/Source/Falcor/Core/Platform/Windows/Windows.cpp @@ -30,6 +30,7 @@ #include #include #include +#include // Always run in Optimus mode on laptops extern "C" @@ -226,6 +227,18 @@ namespace Falcor return std::string(curDir); } + const std::string getAppDataDirectory() + { + PWSTR wpath; + HRESULT result = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &wpath); + if (SUCCEEDED(result)) + { + _bstr_t path(wpath); + return std::string((char*) path); + } + return std::string(); + } + const std::string& getExecutableName() { static std::string filename; diff --git a/Source/Falcor/Core/Program/Program.cpp b/Source/Falcor/Core/Program/Program.cpp index bff9666ed..003ebe797 100644 --- a/Source/Falcor/Core/Program/Program.cpp +++ b/Source/Falcor/Core/Program/Program.cpp @@ -865,7 +865,7 @@ namespace Falcor // and `ProgramReflection`: they are one-to-one. Ideally in a future version // of Falcor they could be the same object. // - ProgramVersion::SharedPtr pVersion = ProgramVersion::createEmpty(const_cast(this)); + ProgramVersion::SharedPtr pVersion = ProgramVersion::createEmpty(const_cast(this), pSlangGlobalScope); // Note: Because of interactions between how `SV_Target` outputs // and `u` register bindings work in Slang today (as a compatibility @@ -892,7 +892,6 @@ namespace Falcor mDefineList, pReflector, getProgramDescString(), - pSlangGlobalScope, pSlangEntryPoints); return pVersion; diff --git a/Source/Falcor/Core/Program/ProgramReflection.cpp b/Source/Falcor/Core/Program/ProgramReflection.cpp index 75a9ec7dc..9d8531825 100644 --- a/Source/Falcor/Core/Program/ProgramReflection.cpp +++ b/Source/Falcor/Core/Program/ProgramReflection.cpp @@ -36,7 +36,7 @@ namespace Falcor { namespace { - const std::string kRootDescriptorPrefix = "__root__"; + const char* kRootDescriptorAttribute = "root"; } TypedShaderVarOffset::TypedShaderVarOffset( @@ -594,12 +594,13 @@ namespace Falcor ReflectionResourceType::ReturnType retType = getReturnType(pSlangType->getType()); ReflectionResourceType::StructuredType structuredType = getStructuredBufferType(pSlangType->getType()); - // Check if resource type represents a root descriptor. - // This is currently encoded using a magic prefix on the variable name. - // TODO: Replace this hack by an annotation of the type itself. assert(pPath->pPrimary && pPath->pPrimary->pVar); std::string name = pPath->pPrimary->pVar->getName(); - bool isRootDescriptor = (name.substr(0, kRootDescriptorPrefix.length()) == kRootDescriptorPrefix); + + // Check if resource type represents a root descriptor. + // In the shader we use a custom [root] attribute to flag resources to map to root descriptors. + auto pVar = pPath->pPrimary->pVar->getVariable(); + bool isRootDescriptor = pVar->findUserAttributeByName(pProgramVersion->getSlangSession()->getGlobalSession(), kRootDescriptorAttribute) != nullptr; // Check that the root descriptor type is supported. if (isRootDescriptor) @@ -967,7 +968,7 @@ namespace Falcor var.type = getVariableType(pTypeLayout->getScalarType(), pTypeLayout->getRowCount(), pTypeLayout->getColumnCount()); uint32_t baseIndex = (uint32_t)getRegisterIndexFromPath(path.pPrimary, category); - for(uint32_t i = 0 ; i < max(count, 1u) ; i++) + for(uint32_t i = 0 ; i < std::max(count, 1u) ; i++) { var.bindLocation = baseIndex + (i*stride); var.semanticName = pVar->getSemanticName(); diff --git a/Source/Falcor/Core/Program/ProgramReflection.h b/Source/Falcor/Core/Program/ProgramReflection.h index aee8c43f7..22eb14ff8 100644 --- a/Source/Falcor/Core/Program/ProgramReflection.h +++ b/Source/Falcor/Core/Program/ProgramReflection.h @@ -605,12 +605,6 @@ namespace Falcor */ Kind getKind() const { return mKind; } - deprecate("4.0", "Use 'Kind' instead.") - typedef Kind Type; - - deprecate("4.0", "Use the 'getKind()' method instead.") - Kind getType() const { return mKind; } - /** Dynamic-cast the current object to ReflectionResourceType */ const ReflectionResourceType* asResourceType() const; @@ -645,9 +639,6 @@ namespace Falcor */ uint32_t getTotalArrayElementCount() const; - deprecate("4.0", "Use the 'getTotalArrayElementCount()' method instead.") - uint32_t getTotalArraySize() const { return getTotalArrayElementCount(); } - /** Type to represent the byte size of a shader type. */ typedef size_t ByteSize; @@ -658,9 +649,6 @@ namespace Falcor */ ByteSize getByteSize() const { return mByteSize; } - deprecate("4.0", "Use the 'getByteSize()' method instead.") - ByteSize getSize() const { return getByteSize(); } - /** Find a field/member of this type with the given `name`. If this type doesn't have fields/members, or doesn't have a field/member matching `name`, then returns null. @@ -674,9 +662,6 @@ namespace Falcor */ TypedShaderVarOffset getMemberOffset(const std::string& name) const; - deprecate("4.0", "Use the 'getMemberOffset()' method instead.") - TypedShaderVarOffset getResourceBinding(const std::string& name) const { return getMemberOffset(name); } - /** Find a typed member/element offset corresponding to the given byte offset. */ TypedShaderVarOffset findMemberByOffset(size_t byteOffset) const; @@ -789,9 +774,6 @@ namespace Falcor */ uint32_t getElementCount() const { return mElementCount; } - deprecate("4.0", "Use 'getElementCount()' instead.") - uint32_t getArraySize() const { return mElementCount; } - /** Get the "stride" in bytes of the array. The stride is the number of bytes between consecutive @@ -802,16 +784,10 @@ namespace Falcor */ uint32_t getElementByteStride() const { return mElementByteStride; } - deprecate("4.0", "Use 'getElementByteStride()' instead.") - uint32_t getArrayStride() const { return mElementByteStride; } - /** Get the type of the array elements. */ const ReflectionType::SharedConstPtr& getElementType() const { return mpElementType; } - deprecate("4.0", "Use 'getElementType()' instead.") - const ReflectionType::SharedConstPtr& getType() const { return mpElementType; } - bool operator==(const ReflectionArrayType& other) const; bool operator==(const ReflectionType& other) const override; @@ -1476,7 +1452,7 @@ namespace Falcor /** For compute-shaders, return the required thread-group size */ - uvec3 getThreadGroupSize() const { return mThreadGroupSize; } + uint3 getThreadGroupSize() const { return mThreadGroupSize; } /** For pixel-shaders, check if we need to run the shader at sample frequency */ @@ -1522,7 +1498,7 @@ namespace Falcor ProgramVersion const* mpProgramVersion; ParameterBlockReflection::SharedPtr mpDefaultBlock; - uvec3 mThreadGroupSize; + uint3 mThreadGroupSize; bool mIsSampleFrequency = false; VariableMap mPsOut; diff --git a/Source/Falcor/Core/Program/ProgramVersion.cpp b/Source/Falcor/Core/Program/ProgramVersion.cpp index 38f077323..06bf4e47c 100644 --- a/Source/Falcor/Core/Program/ProgramVersion.cpp +++ b/Source/Falcor/Core/Program/ProgramVersion.cpp @@ -127,8 +127,9 @@ namespace Falcor } - ProgramVersion::ProgramVersion(Program* pProgram) + ProgramVersion::ProgramVersion(Program* pProgram, slang::IComponentType* pSlangGlobalScope) : mpProgram(pProgram->shared_from_this()) + , mpSlangGlobalScope(pSlangGlobalScope) { assert(pProgram); } @@ -137,20 +138,18 @@ namespace Falcor const DefineList& defineList, const ProgramReflection::SharedPtr& pReflector, const std::string& name, - slang::IComponentType* pSlangGlobalScope, std::vector> const& pSlangEntryPoints) { assert(pReflector); mDefines = defineList, mpReflector = pReflector; mName = name; - mpSlangGlobalScope = pSlangGlobalScope; mpSlangEntryPoints = pSlangEntryPoints; } - ProgramVersion::SharedPtr ProgramVersion::createEmpty(Program* pProgram) + ProgramVersion::SharedPtr ProgramVersion::createEmpty(Program* pProgram, slang::IComponentType* pSlangGlobalScope) { - return SharedPtr(new ProgramVersion(pProgram)); + return SharedPtr(new ProgramVersion(pProgram, pSlangGlobalScope)); } ProgramKernels::SharedConstPtr ProgramVersion::getKernels(ProgramVars const* pVars) const diff --git a/Source/Falcor/Core/Program/ProgramVersion.h b/Source/Falcor/Core/Program/ProgramVersion.h index 6a76b44dd..b0ac1d398 100644 --- a/Source/Falcor/Core/Program/ProgramVersion.h +++ b/Source/Falcor/Core/Program/ProgramVersion.h @@ -159,7 +159,7 @@ namespace Falcor const ProgramVersion* pVersion, const ProgramReflection::SharedPtr& pReflector, const UniqueEntryPointGroups& uniqueEntryPointGroups, - std::string& log, + std::string& log, const std::string& name = ""); virtual ~ProgramKernels() = default; @@ -239,15 +239,14 @@ namespace Falcor friend class Program; friend class RtProgram; - static SharedPtr createEmpty(Program* pProgram); + static SharedPtr createEmpty(Program* pProgram, slang::IComponentType* pSlangGlobalScope); - ProgramVersion(Program* pProgram); + ProgramVersion(Program* pProgram, slang::IComponentType* pSlangGlobalScope); void init( const DefineList& defineList, const ProgramReflection::SharedPtr& pReflector, const std::string& name, - slang::IComponentType* pSlangGlobalScope, std::vector> const& pSlangEntryPoints); std::shared_ptr mpProgram; diff --git a/Source/Falcor/Core/Sample.cpp b/Source/Falcor/Core/Sample.cpp index f0ae0ff29..73ebaed55 100644 --- a/Source/Falcor/Core/Sample.cpp +++ b/Source/Falcor/Core/Sample.cpp @@ -117,7 +117,7 @@ namespace Falcor mVsyncOn = !mVsyncOn; gpDevice->toggleVSync(mVsyncOn); mFrameRate.reset(); - mClock.now(0); + mClock.setTime(0); break; case KeyboardEvent::Key::F2: toggleUI(!mShowUI); @@ -243,7 +243,7 @@ namespace Falcor mSuppressInput = config.suppressInput; mShowUI = config.showUI; - mClock.timeScale(config.timeScale); + mClock.setTimeScale(config.timeScale); if (config.pauseTime) mClock.pause(); mVsyncOn = config.deviceDesc.enableVsync; @@ -303,9 +303,9 @@ namespace Falcor mpRenderer = nullptr; } - void screenSizeUI(Gui::Widgets& widget, uvec2 screenDims) + void screenSizeUI(Gui::Widgets& widget, uint2 screenDims) { - static const uvec2 resolutions[] = + static const uint2 resolutions[] = { {0, 0}, {1280, 720}, @@ -315,7 +315,7 @@ namespace Falcor {3840, 2160}, }; - static const auto initDropDown = [](const uvec2 resolutions[], uint32_t count) -> Gui::DropdownList + static const auto initDropDown = [](const uint2 resolutions[], uint32_t count) -> Gui::DropdownList { Gui::DropdownList list; for (uint32_t i = 0 ; i < count; i++) @@ -326,7 +326,7 @@ namespace Falcor return list; }; - auto initDropDownVal = [](const uvec2 resolutions[], uint32_t count, uvec2 screenDims) + auto initDropDownVal = [](const uint2 resolutions[], uint32_t count, uint2 screenDims) { for (uint32_t i = 0; i < count; i++) { @@ -381,15 +381,15 @@ namespace Falcor auto controlsGroup = Gui::Group(pGui, "Global Controls"); if (controlsGroup.open()) { - float t = (float)mClock.now(); - if (controlsGroup.var("Time", t, 0.f, FLT_MAX)) mClock.now(double(t)); - if (controlsGroup.button("Reset")) mClock.now(0.0); + float t = (float)mClock.getTime(); + if (controlsGroup.var("Time", t, 0.f, FLT_MAX)) mClock.setTime(double(t)); + if (controlsGroup.button("Reset")) mClock.setTime(0.0); bool timePaused = mClock.isPaused(); if (controlsGroup.button(timePaused ? "Play" : "Pause", true)) timePaused ? mClock.pause() : mClock.play(); if (controlsGroup.button("Stop", true)) mClock.stop(); - float scale = (float)mClock.timeScale(); - if (controlsGroup.var("Scale", scale, 0.f, FLT_MAX)) mClock.timeScale(scale); + float scale = (float)mClock.getTimeScale(); + if (controlsGroup.var("Scale", scale, 0.f, FLT_MAX)) mClock.setTimeScale(scale); controlsGroup.separator(); if (controlsGroup.button(mRendererPaused ? "Resume Rendering" : "Pause Rendering")) mRendererPaused = !mRendererPaused; @@ -449,9 +449,12 @@ namespace Falcor { if (gpDevice && gpDevice->isWindowOccluded()) return; + // Check clock exit condition + if (mClock.shouldExit()) postQuitMessage(0); + mClock.tick(); mFrameRate.newFrame(); - if (mVideoCapture.fixedTimeDelta) { mClock.now(mVideoCapture.currentTime); } + if (mVideoCapture.fixedTimeDelta) { mClock.setTime(mVideoCapture.currentTime); } { PROFILE("onFrameRender"); @@ -617,7 +620,7 @@ namespace Falcor c.deviceDesc = gpDevice->getDesc(); c.windowDesc = mpWindow->getDesc(); c.showMessageBoxOnError = Logger::isBoxShownOnError(); - c.timeScale = (float)mClock.timeScale(); + c.timeScale = (float)mClock.getTimeScale(); c.pauseTime = mClock.isPaused(); c.showUI = mShowUI; return c; @@ -648,10 +651,16 @@ namespace Falcor sampleDesc.field(windowDesc).field(deviceDesc).field(showMessageBoxOnError).field(timeScale); sampleDesc.field(pauseTime).field(showUI); #undef field - auto exit = [](int32_t errorCode) {postQuitMessage(errorCode); }; + auto exit = [](int32_t errorCode) { postQuitMessage(errorCode); }; m.func_("exit", exit, "errorCode"_a = 0); auto renderFrame = [this]() {ProgressBar::close(); this->renderFrame(); }; m.func_("renderFrame", renderFrame); + + auto setWindowPos = [this](int32_t x, int32_t y) {getWindow()->setWindowPos(x, y); }; + m.func_("setWindowPos", setWindowPos, "x"_a, "y"_a); + + auto resize = [this](uint32_t width, uint32_t height) {resizeSwapChain(width, height); }; + m.func_("resizeSwapChain", resize, "width"_a, "height"_a); } } diff --git a/Source/Falcor/Core/State/GraphicsState.cpp b/Source/Falcor/Core/State/GraphicsState.cpp index 1ea50fbcb..ddc55d153 100644 --- a/Source/Falcor/Core/State/GraphicsState.cpp +++ b/Source/Falcor/Core/State/GraphicsState.cpp @@ -69,11 +69,6 @@ namespace Falcor GraphicsStateObject::SharedPtr GraphicsState::getGSO(const GraphicsVars* pVars) { - assert(mpVao); - if (mpProgram && mpVao->getVertexLayout() != nullptr) - { - mpVao->getVertexLayout()->addVertexAttribDclToProg(mpProgram.get()); - } auto pProgramKernels = mpProgram ? mpProgram->getActiveVersion()->getKernels(pVars) : nullptr; bool newProgVersion = pProgramKernels.get() != mCachedData.pProgramKernels; if (newProgVersion) diff --git a/Source/Falcor/Core/Window.cpp b/Source/Falcor/Core/Window.cpp index be6b4a76a..8b77ee59d 100644 --- a/Source/Falcor/Core/Window.cpp +++ b/Source/Falcor/Core/Window.cpp @@ -105,7 +105,7 @@ namespace Falcor event.type = MouseEvent::Type::Move; event.pos = calcMousePos(mouseX, mouseY, pWindow->getMouseScale()); event.screenPos = { mouseX, mouseY }; - event.wheelDelta = glm::vec2(0, 0); + event.wheelDelta = float2(0, 0); pWindow->mpCallbacks->handleMouseEvent(event); } @@ -154,7 +154,7 @@ namespace Falcor double x, y; glfwGetCursorPos(pGlfwWindow, &x, &y); event.pos = calcMousePos(x, y, pWindow->getMouseScale()); - event.wheelDelta = (glm::vec2(float(scrollX), float(scrollY))); + event.wheelDelta = (float2(float(scrollX), float(scrollY))); pWindow->mpCallbacks->handleMouseEvent(event); } @@ -320,9 +320,9 @@ namespace Falcor return mods; } - static inline glm::vec2 calcMousePos(double xPos, double yPos, const glm::vec2& mouseScale) + static inline float2 calcMousePos(double xPos, double yPos, const float2& mouseScale) { - glm::vec2 pos = glm::vec2(float(xPos), float(yPos)); + float2 pos = float2(float(xPos), float(yPos)); pos *= mouseScale; return pos; } @@ -494,6 +494,11 @@ namespace Falcor } } + void Window::setWindowPos(int32_t x, int32_t y) + { + glfwSetWindowPos(mpGLFWWindow, x, y); + } + void Window::setWindowTitle(const std::string& title) { glfwSetWindowTitle(mpGLFWWindow, title.c_str()); @@ -506,6 +511,9 @@ namespace Falcor SCRIPT_BINDING(Window) { + auto w = m.class_("Window"); + w.func_("setWindowPos", &Window::setWindowPos); + auto windowMode = m.enum_("WindowMode"); windowMode.regEnumVal(Window::WindowMode::Normal); windowMode.regEnumVal(Window::WindowMode::Fullscreen); diff --git a/Source/Falcor/Core/Window.h b/Source/Falcor/Core/Window.h index eb6ab872b..82e86ca43 100644 --- a/Source/Falcor/Core/Window.h +++ b/Source/Falcor/Core/Window.h @@ -102,6 +102,10 @@ namespace Falcor */ void pollForEvents(); + /** Change the window's position + */ + void setWindowPos(int32_t x, int32_t y); + /** Change the window's title */ void setWindowTitle(const std::string& title); @@ -112,7 +116,7 @@ namespace Falcor /** Get the width of the window's client area */ - uvec2 getClientAreaSize() const { return { mDesc.width, mDesc.height }; } + uint2 getClientAreaSize() const { return { mDesc.width, mDesc.height }; } /** Get the descriptor */ @@ -127,8 +131,8 @@ namespace Falcor Desc mDesc; GLFWwindow* mpGLFWWindow; ApiHandle mApiHandle; - glm::vec2 mMouseScale; - const glm::vec2& getMouseScale() const { return mMouseScale; } + float2 mMouseScale; + const float2& getMouseScale() const { return mMouseScale; } ICallbacks* mpCallbacks = nullptr; }; diff --git a/Source/Falcor/Experimental/Scene/Lights/EnvProbe.cpp b/Source/Falcor/Experimental/Scene/Lights/EnvProbe.cpp index 243c7100c..92a17d49f 100644 --- a/Source/Falcor/Experimental/Scene/Lights/EnvProbe.cpp +++ b/Source/Falcor/Experimental/Scene/Lights/EnvProbe.cpp @@ -54,8 +54,9 @@ namespace Falcor assert(var.isValid()); // Set variables. + float2 invDim = 1.f / float2(mpImportanceMap->getWidth(), mpImportanceMap->getHeight()); if (!var["importanceBaseMip"].set(mpImportanceMap->getMipCount() - 1)) return false; // The base mip is 1x1 texels - if (!var["importanceInvDim"].set(glm::vec2(1.f / mpImportanceMap->getWidth(), 1.f / mpImportanceMap->getHeight()))) return false; + if (!var["importanceInvDim"].set(invDim)) return false; // Bind resources. if (!var["envMap"].setTexture(mpEnvMap) || @@ -124,9 +125,9 @@ namespace Falcor uint32_t samplesY = samples / samplesX; assert(samples == samplesX * samplesY); - mpSetupPass["CB"]["outputDim"] = glm::uvec2(dimension); - mpSetupPass["CB"]["outputDimInSamples"] = glm::uvec2(dimension * samplesX, dimension * samplesY); - mpSetupPass["CB"]["numSamples"] = glm::uvec2(samplesX, samplesY); + mpSetupPass["CB"]["outputDim"] = uint2(dimension); + mpSetupPass["CB"]["outputDimInSamples"] = uint2(dimension * samplesX, dimension * samplesY); + mpSetupPass["CB"]["numSamples"] = uint2(samplesX, samplesY); mpSetupPass["CB"]["invSamples"] = 1.f / (samplesX * samplesY); // Execute setup pass to compute the square importance map (base mip). diff --git a/Source/Falcor/Experimental/Scene/Lights/FinalizeIntegration.cs.slang b/Source/Falcor/Experimental/Scene/Lights/FinalizeIntegration.cs.slang index ac5cb703a..9bdb62d7c 100644 --- a/Source/Falcor/Experimental/Scene/Lights/FinalizeIntegration.cs.slang +++ b/Source/Falcor/Experimental/Scene/Lights/FinalizeIntegration.cs.slang @@ -53,7 +53,7 @@ void finalizeIntegration(uint3 DTid : SV_DispatchThreadID) // Compute the triangle's average emitted radiance (RGB). const MeshLightData lightData = gMeshData[gTriangleData[triIdx].lightIdx]; - const MaterialData materialData = gScene.materials[lightData.materialID]; + const MaterialData materialData = gScene.getMaterial(lightData.materialID); float3 averageEmissiveColor = materialData.emissive; if (gScene.isEmissiveTextured(lightData.materialID)) diff --git a/Source/Falcor/Experimental/Scene/Lights/LightBVH.h b/Source/Falcor/Experimental/Scene/Lights/LightBVH.h index b257cd06a..4c0639bc3 100644 --- a/Source/Falcor/Experimental/Scene/Lights/LightBVH.h +++ b/Source/Falcor/Experimental/Scene/Lights/LightBVH.h @@ -74,13 +74,13 @@ namespace Falcor struct InternalNode { NodeType nodeType = NodeType::Internal; - glm::vec3 aabbMin; + float3 aabbMin; float luminousFlux = 0.f; - glm::vec3 aabbMax; + float3 aabbMax; float cosConeAngle = kInvalidCosConeAngle; // If cosConeAngle == kInvalidCosConeAngle, the cone should not be used. - glm::vec3 coneDirection = { 0.f, 0.f, 0.f }; + float3 coneDirection = { 0.f, 0.f, 0.f }; uint32_t leftNodeOffset = kInvalidOffset; uint32_t rightNodeOffset = kInvalidOffset; @@ -89,13 +89,13 @@ namespace Falcor struct LeafNode { NodeType nodeType = NodeType::Leaf; - glm::vec3 aabbMin; + float3 aabbMin; float luminousFlux = 0.f; - glm::vec3 aabbMax; + float3 aabbMax; float cosConeAngle = kInvalidCosConeAngle; // If cosConeAngle == kInvalidCosConeAngle, the cone should not be used. - glm::vec3 coneDirection = { 0.f, 0.f, 0.f }; + float3 coneDirection = { 0.f, 0.f, 0.f }; uint32_t triangleCount = 0; // The allocator allocates extra space after LeafNodes as needed to allow a larger diff --git a/Source/Falcor/Experimental/Scene/Lights/LightBVHBuilder.cpp b/Source/Falcor/Experimental/Scene/Lights/LightBVHBuilder.cpp index 5da983a69..d43c7a5a4 100644 --- a/Source/Falcor/Experimental/Scene/Lights/LightBVHBuilder.cpp +++ b/Source/Falcor/Experimental/Scene/Lights/LightBVHBuilder.cpp @@ -56,7 +56,7 @@ namespace TODO: Move to utility header and add unit test. \return The cosine of the spread angle for the new cone. */ - float computeCosConeAngle(const glm::vec3& coneDir, const float cosTheta, const glm::vec3& otherConeDir, const float cosOtherTheta) + float computeCosConeAngle(const float3& coneDir, const float cosTheta, const float3& otherConeDir, const float cosOtherTheta) { float cosResult = kInvalidCosConeAngle; if (cosTheta != kInvalidCosConeAngle && cosOtherTheta != kInvalidCosConeAngle) @@ -84,13 +84,13 @@ namespace is what was used previously; the cones it returns aren't as tight as those given by coneUnion(). */ - glm::vec3 coneUnionOld(glm::vec3 aDir, float aCosTheta, glm::vec3 bDir, float bCosTheta, float& cosResult) + float3 coneUnionOld(float3 aDir, float aCosTheta, float3 bDir, float bCosTheta, float& cosResult) { - glm::vec3 dir = aDir + bDir; - if (aCosTheta == kInvalidCosConeAngle || bCosTheta == kInvalidCosConeAngle || dir == glm::vec3(0.0f)) + float3 dir = aDir + bDir; + if (aCosTheta == kInvalidCosConeAngle || bCosTheta == kInvalidCosConeAngle || dir == float3(0.0f)) { cosResult = kInvalidCosConeAngle; - return glm::vec3(0.0f); + return float3(0.0f); } dir = glm::normalize(dir); @@ -105,12 +105,12 @@ namespace their spread angles, returns a cone that bounds both of them. Algorithm 1 in the 2018 Sony EGSR light sampling paper. */ - glm::vec3 coneUnion(glm::vec3 aDir, float aCosTheta, glm::vec3 bDir, float bCosTheta, float& cosResult) + float3 coneUnion(float3 aDir, float aCosTheta, float3 bDir, float bCosTheta, float& cosResult) { if (aCosTheta == kInvalidCosConeAngle || bCosTheta == kInvalidCosConeAngle) { cosResult = kInvalidCosConeAngle; - return glm::vec3(0.0f); + return float3(0.0f); } // Swap if necessary so that aTheta > bTheta. Note that the test is @@ -137,14 +137,14 @@ namespace if (oTheta > glm::pi()) { cosResult = kInvalidCosConeAngle; - return glm::vec3(0.0f); + return float3(0.0f); } // Rotate a's axis toward b just enough so that that oTheta covers // both cones. const float rTheta = oTheta - aTheta; - const glm::vec3 rDir = glm::cross(aDir, bDir); - glm::vec3 dir; + const float3 rDir = glm::cross(aDir, bDir); + float3 dir; if (glm::dot(rDir, rDir) < 1e-8) { // The two vectors are effectively pointing in opposite directions. @@ -154,7 +154,7 @@ namespace const float sign = aDir.z > 0 ? 1.f : -1.f; const float a = -1.f / (sign + aDir.z); const float b = aDir.x * aDir.y * a; - dir = glm::vec3(1.f + sign * aDir.x * aDir.x * a, sign * b, -sign * aDir.x); + dir = float3(1.f + sign * aDir.x * aDir.x * a, sign * b, -sign * aDir.x); // The spread angle needs to be pi/2 to encompass aDir and // bDir, then aTheta / 2 more on top of that. (Recall that // aTheta > bTheta, so we don't need to worry about bTheta). @@ -169,13 +169,13 @@ namespace { // Rotate aDir by an angle of rTheta around the axis rDir. const glm::mat4 rotationMatrix = glm::rotate(glm::mat4(), rTheta, rDir); - dir = rotationMatrix * glm::vec4(aDir, 0); + dir = rotationMatrix * float4(aDir, 0); cosResult = std::cos(oTheta); } // TODO: write a unit test. // Testing code: make sure both a and b are inside the result. - auto checkInside = [&](glm::vec3 d, float theta) { + auto checkInside = [&](float3 d, float theta) { // Make sure that sum of the angle between // the two cone vectors and the spread angle // of the given cone is still within the @@ -415,7 +415,7 @@ namespace Falcor } } - glm::vec3 LightBVHBuilder::computeLightingConesInternal(uint32_t nodesCurrentByteOffset, AlignedAllocator& alignedAllocator, float& cosConeAngle) + float3 LightBVHBuilder::computeLightingConesInternal(uint32_t nodesCurrentByteOffset, AlignedAllocator& alignedAllocator, float& cosConeAngle) { const uintptr_t currentNodeBytePointer = reinterpret_cast(alignedAllocator.getStartPointer()) + nodesCurrentByteOffset; @@ -426,13 +426,13 @@ namespace Falcor assert(currentNode->leftNodeOffset > nodesCurrentByteOffset); float leftNodeCosConeAngle = kInvalidCosConeAngle; - glm::vec3 leftNodeConeDirection = computeLightingConesInternal(currentNode->leftNodeOffset, alignedAllocator, leftNodeCosConeAngle); + float3 leftNodeConeDirection = computeLightingConesInternal(currentNode->leftNodeOffset, alignedAllocator, leftNodeCosConeAngle); float rightNodeCosConeAngle = kInvalidCosConeAngle; - glm::vec3 rightNodeConeDirection = computeLightingConesInternal(currentNode->rightNodeOffset, alignedAllocator, rightNodeCosConeAngle); + float3 rightNodeConeDirection = computeLightingConesInternal(currentNode->rightNodeOffset, alignedAllocator, rightNodeCosConeAngle); // TODO: Asserts in coneUnion - // glm::vec3 coneDirection = coneUnion(leftNodeConeDirection, leftNodeCosConeAngle, - glm::vec3 coneDirection = coneUnionOld(leftNodeConeDirection, leftNodeCosConeAngle, + // float3 coneDirection = coneUnion(leftNodeConeDirection, leftNodeCosConeAngle, + float3 coneDirection = coneUnionOld(leftNodeConeDirection, leftNodeCosConeAngle, rightNodeConeDirection, rightNodeCosConeAngle, cosConeAngle); currentNode->cosConeAngle = cosConeAngle; currentNode->coneDirection = coneDirection; @@ -447,14 +447,14 @@ namespace Falcor } } - glm::vec3 LightBVHBuilder::computeLightingCone(const Range& triangleRange, const BuildingData& data, float& cosTheta) + float3 LightBVHBuilder::computeLightingCone(const Range& triangleRange, const BuildingData& data, float& cosTheta) { - glm::vec3 coneDirection = glm::vec3(0.0f); + float3 coneDirection = float3(0.0f); cosTheta = kInvalidCosConeAngle; // We use the average normal as cone direction and grow the cone to include all light normals. // TODO: Switch to a more sophisticated algorithm to compute tighter bounding cones. - glm::vec3 coneDirectionSum = glm::vec3(0.0f); + float3 coneDirectionSum = float3(0.0f); for (uint32_t triangleIdx = triangleRange.begin; triangleIdx < triangleRange.end; ++triangleIdx) { coneDirectionSum += data.trianglesData[triangleIdx].coneDirection; @@ -475,7 +475,7 @@ namespace Falcor LightBVHBuilder::SplitResult LightBVHBuilder::computeSplitWithEqual(const BuildingData& /*data*/, const Range& triangleRange, const BBox& nodeBounds, const Options& /*parameters*/) { // Find the largest dimension. - const glm::vec3 dimensions = nodeBounds.dimensions(); + const float3 dimensions = nodeBounds.dimensions(); const uint32_t dimension = dimensions[2u] >= dimensions[0u] && dimensions[2u] >= dimensions[1u] ? 2u : (dimensions[1u] >= dimensions[0u] ? 1u : 0u); @@ -593,7 +593,7 @@ namespace Falcor if (parameters.splitAlongLargest) { // Find the largest dimension. - const glm::vec3 dimensions = nodeBounds.dimensions(); + const float3 dimensions = nodeBounds.dimensions(); const uint32_t largestDimension = dimensions[2u] >= dimensions[0u] && dimensions[2u] >= dimensions[1u] ? 2u : (dimensions[1u] >= dimensions[0u] && dimensions[1u] >= dimensions[2u] ? 1u : 0u); @@ -660,7 +660,7 @@ namespace Falcor assert(!overallBestSplit.second.isValid()); // Find the largest dimension. - const glm::vec3 dimensions = nodeBounds.dimensions(); + const float3 dimensions = nodeBounds.dimensions(); const uint32_t largestDimension = dimensions[2u] >= dimensions[0u] && dimensions[2u] >= dimensions[1u] ? 2u : (dimensions[1u] >= dimensions[0u] && dimensions[1u] >= dimensions[2u] ? 1u : 0u); @@ -669,7 +669,7 @@ namespace Falcor BBox bounds = BBox(); uint32_t triangleCount = 0u; float flux = 0.0f; - glm::vec3 coneDirection = glm::vec3(0.0f); + float3 coneDirection = float3(0.0f); float cosConeAngle = 1.0f; Bin() = default; @@ -748,7 +748,7 @@ namespace Falcor if (glm::length(total.coneDirection) >= FLT_MIN) { cosTheta = 1.f; - const glm::vec3 coneDir = glm::normalize(total.coneDirection); + const float3 coneDir = glm::normalize(total.coneDirection); for (std::size_t j = 0u; j <= i; ++j) { cosTheta = computeCosConeAngle(coneDir, cosTheta, bins[j].coneDirection, bins[j].cosConeAngle); @@ -769,7 +769,7 @@ namespace Falcor if (glm::length(total.coneDirection) >= FLT_MIN) { cosTheta = 1.f; - const glm::vec3 coneDir = glm::normalize(total.coneDirection); + const float3 coneDir = glm::normalize(total.coneDirection); for (std::size_t j = i; j <= costs.size(); ++j) { cosTheta = computeCosConeAngle(coneDir, cosTheta, bins[j].coneDirection, bins[j].cosConeAngle); diff --git a/Source/Falcor/Experimental/Scene/Lights/LightBVHBuilder.h b/Source/Falcor/Experimental/Scene/Lights/LightBVHBuilder.h index bf38a0824..044cbf848 100644 --- a/Source/Falcor/Experimental/Scene/Lights/LightBVHBuilder.h +++ b/Source/Falcor/Experimental/Scene/Lights/LightBVHBuilder.h @@ -116,8 +116,8 @@ namespace Falcor struct TriangleSortData { BBox bounds; ///< World-space bounding box for the light source(s). - glm::vec3 center = {}; ///< Center point. - glm::vec3 coneDirection = {}; ///< Light emission normal direction. + float3 center = {}; ///< Center point. + float3 coneDirection = {}; ///< Light emission normal direction. float cosConeAngle = 1.f; ///< Cosine normal bounding cone (half) angle. float flux = 0.f; ///< Precomputed triangle flux (note, this takes doublesidedness into account). uint32_t triangleIndex = kInvalidIndex; ///< Index into global triangle list. @@ -162,7 +162,7 @@ namespace Falcor \param[out] cosConeAngle Cosine of the angle value of the lighting cone for the node located at nodesCurrentByteOffset, or kInvalidCosConeAngle if the cone is invalid. \return direction of the lighting cone for the node loacted at nodesCurrentByteOffset. */ - glm::vec3 computeLightingConesInternal(uint32_t nodesCurrentByteOffset, AlignedAllocator& alignedAllocator, float& cosConeAngle); + float3 computeLightingConesInternal(uint32_t nodesCurrentByteOffset, AlignedAllocator& alignedAllocator, float& cosConeAngle); /** Compute lighting cone for a range of triangles. \param[in] triangleRange Range of triangles to process. @@ -170,7 +170,7 @@ namespace Falcor \param[out] cosTheta Cosine of the cone angle. \return Direction of the lighting cone. */ - static glm::vec3 computeLightingCone(const Range& triangleRange, const BuildingData& data, float& cosTheta); + static float3 computeLightingCone(const Range& triangleRange, const BuildingData& data, float& cosTheta); // See the documentation of SplitHeuristicFunction. static SplitResult computeSplitWithEqual(const BuildingData& /*data*/, const Range& triangleRange, const BBox& nodeBounds, const Options& /*parameters*/); diff --git a/Source/Falcor/Experimental/Scene/Lights/LightCollection.cpp b/Source/Falcor/Experimental/Scene/Lights/LightCollection.cpp index bb7c5b551..5c63e9d57 100644 --- a/Source/Falcor/Experimental/Scene/Lights/LightCollection.cpp +++ b/Source/Falcor/Experimental/Scene/Lights/LightCollection.cpp @@ -33,6 +33,9 @@ namespace Falcor { + static_assert(sizeof(MeshLightData) % 16 == 0, "MeshLightData size should be a multiple of 16"); + static_assert(sizeof(EmissiveTriangle) % 16 == 0, "EmissiveTriangle size should be a multiple of 16"); + namespace { const char kEmissiveIntegratorFile[] = "Experimental/Scene/Lights/EmissiveIntegrator.ps.slang"; @@ -272,8 +275,8 @@ namespace Falcor { // Create GPU buffers. assert(mTriangleCount > 0); - const size_t bufSize = mTriangleCount * 3 * sizeof(glm::vec3); - const size_t uvBufSize = mTriangleCount * 3 * sizeof(glm::vec2); + const size_t bufSize = mTriangleCount * 3 * sizeof(float3); + const size_t uvBufSize = mTriangleCount * 3 * sizeof(float2); mpMeshLightsVertexPos = Buffer::create(bufSize, Resource::BindFlags::ShaderResource | Resource::BindFlags::UnorderedAccess, Buffer::CpuAccess::None); mpMeshLightsVertexPos->setName("LightCollection_MeshLightsVertexPos"); @@ -316,7 +319,7 @@ namespace Falcor } // Create the GPU buffer. - mpPerMeshInstanceOffset = Buffer::createTyped(instanceCount, Resource::BindFlags::ShaderResource); + mpPerMeshInstanceOffset = Buffer::createStructured(sizeof(uint32_t), instanceCount, Resource::BindFlags::ShaderResource); mpPerMeshInstanceOffset->setName("LightCollection_PerMeshInstanceOffset"); const size_t sizeInBytes = triangleOffsets.size() * sizeof(triangleOffsets[0]); @@ -332,7 +335,7 @@ namespace Falcor // 1st pass: Rasterize emissive triangles in texture space to sum up their texels. { // Re-allocate result buffer if needed. - const uint32_t bufSize = mTriangleCount * sizeof(glm::vec4); + const uint32_t bufSize = mTriangleCount * sizeof(float4); if (!mIntegrator.pResultBuffer || mIntegrator.pResultBuffer->getSize() < bufSize) { mIntegrator.pResultBuffer = Buffer::create(bufSize, Resource::BindFlags::ShaderResource | Resource::BindFlags::UnorderedAccess, Buffer::CpuAccess::None); @@ -341,7 +344,7 @@ namespace Falcor } // Clear to zero before we start. - pRenderContext->clearUAV(mIntegrator.pResultBuffer->getUAV().get(), glm::vec4(0.f)); + pRenderContext->clearUAV(mIntegrator.pResultBuffer->getUAV().get(), float4(0.f)); // Specialize the program and re-create the vars. mIntegrator.pVars = GraphicsVars::create(mIntegrator.pProgram.get()); @@ -388,7 +391,7 @@ namespace Falcor // Stats on input data. MeshLightStats stats; stats.meshLightCount = (uint32_t)mMeshLights.size(); - stats.triangleCount = (uint32)mMeshLightTriangles.size(); + stats.triangleCount = (uint32_t)mMeshLightTriangles.size(); uint32_t trianglesTotal = 0; for (const auto& meshLight : mMeshLights) @@ -571,8 +574,8 @@ namespace Falcor assert(mStagingBufferValid); const void* mappedData = mpStagingBuffer->map(Buffer::MapType::Read); - const glm::vec3* vertexPos = reinterpret_cast(mappedData); - const glm::vec2* vertexTexCrd = reinterpret_cast(reinterpret_cast(mappedData) + mpMeshLightsVertexPos->getSize()); + const float3* vertexPos = reinterpret_cast(mappedData); + const float2* vertexTexCrd = reinterpret_cast(reinterpret_cast(mappedData) + mpMeshLightsVertexPos->getSize()); assert(mpTriangleData); if (mpTriangleData->getStructSize() != sizeof(EmissiveTriangle)) throw std::exception("Struct EmissiveTriangle size mismatch between CPU/GPU"); const EmissiveTriangle* triangleData = reinterpret_cast(reinterpret_cast(mappedData) + mpMeshLightsVertexPos->getSize() + mpMeshLightsTexCoords->getSize()); diff --git a/Source/Falcor/Experimental/Scene/Lights/LightCollection.h b/Source/Falcor/Experimental/Scene/Lights/LightCollection.h index 4411d7316..7ec42d70b 100644 --- a/Source/Falcor/Experimental/Scene/Lights/LightCollection.h +++ b/Source/Falcor/Experimental/Scene/Lights/LightCollection.h @@ -78,8 +78,8 @@ namespace Falcor */ struct MeshLightVertex { - glm::vec3 pos; ///< World-space position. - glm::vec2 uv; ///< Texture coordinates in emissive texture (if textured). + float3 pos; ///< World-space position. + float2 uv; ///< Texture coordinates in emissive texture (if textured). }; /** Represents one mesh light triangle. @@ -91,14 +91,14 @@ namespace Falcor uint32_t lightIdx = kInvalidIndex; ///< Per-triangle index into mesh lights array. // Pre-computed quantities. - glm::vec3 normal = glm::vec3(0); ///< Triangle's face normal in world space. - glm::vec3 averageRadiance = glm::vec3(0); ///< Average radiance emitted over triangle. For textured emissive the radiance varies over the surface. + float3 normal = float3(0); ///< Triangle's face normal in world space. + float3 averageRadiance = float3(0); ///< Average radiance emitted over triangle. For textured emissive the radiance varies over the surface. float luminousFlux = 0.f; ///< Pre-integrated luminous flux (lumens) emitted per side of the triangle for double-sided emitters (total flux is 2x this value). float area = 0.f; ///< Triangle area in world space units. /** Returns the center of the triangle in world space. */ - glm::vec3 getCenter() const + float3 getCenter() const { return (vtx[0].pos + vtx[1].pos + vtx[2].pos) / 3.0f; } diff --git a/Source/Falcor/Experimental/Scene/Lights/LightCollection.slang b/Source/Falcor/Experimental/Scene/Lights/LightCollection.slang index da372fb70..942f9c925 100644 --- a/Source/Falcor/Experimental/Scene/Lights/LightCollection.slang +++ b/Source/Falcor/Experimental/Scene/Lights/LightCollection.slang @@ -41,17 +41,16 @@ __exported import Experimental.Scene.Lights.MeshLightData; */ struct LightCollection { - uint triangleCount; ///< Total number of triangles in all mesh lights. - uint meshCount; ///< Total number of mesh lights. - uint _pad[2]; + uint triangleCount; ///< Total number of triangles in all mesh lights. + uint meshCount; ///< Total number of mesh lights. + uint _pad[2]; - ByteAddressBuffer meshLightsVertexPos; ///< Vertex positions in world space for all mesh light triangles. Size: triangleCount * 3 * sizeof(float3). - ByteAddressBuffer meshLightsTexCoords; ///< Texture coordinates for all mesh light triangles. Size: triangleCount * 3 * sizeof(float2). - Buffer perMeshInstanceOffset; ///< Per-mesh instance offset into emissive triangles array. Size: meshInstanceCount * sizeof(uint). - StructuredBuffer triangleData; ///< Per-triangle data for emissive triangles. Size: triangleCount * sizeof(EmissiveTriangle). - StructuredBuffer meshData; ///< Per-mesh data for emissive meshes. Size: meshCount * sizeof(MeshLightData). + ByteAddressBuffer meshLightsVertexPos; ///< Vertex positions in world space for all mesh light triangles. Size: triangleCount * 3 * sizeof(float3). + ByteAddressBuffer meshLightsTexCoords; ///< Texture coordinates for all mesh light triangles. Size: triangleCount * 3 * sizeof(float2). + StructuredBuffer perMeshInstanceOffset; ///< Per-mesh instance offset into emissive triangles array. Size: meshInstanceCount * sizeof(uint). + StructuredBuffer triangleData; ///< Per-triangle data for emissive triangles. Size: triangleCount * sizeof(EmissiveTriangle). + StructuredBuffer meshData; ///< Per-mesh data for emissive meshes. Size: meshCount * sizeof(MeshLightData). - // Accessors /** Returns the total number of emissive triangles. */ diff --git a/Source/Falcor/Experimental/Scene/Lights/LightCollectionShared.slang b/Source/Falcor/Experimental/Scene/Lights/LightCollectionShared.slang index 55984909c..2c68215c1 100644 --- a/Source/Falcor/Experimental/Scene/Lights/LightCollectionShared.slang +++ b/Source/Falcor/Experimental/Scene/Lights/LightCollectionShared.slang @@ -35,11 +35,12 @@ BEGIN_NAMESPACE_FALCOR */ struct EmissiveTriangle { - uint lightIdx; ///< Index into global mesh lights array. float3 normal; ///< Face normal in world space. float area; ///< Triangle area in world space. float3 averageRadiance; ///< Average emitted radiance over the triangle. float flux; ///< Pre-integrated luminous flux for triangle in lumens. + uint lightIdx; ///< Index into global mesh lights array. + uint3 _pad; }; END_NAMESPACE_FALCOR diff --git a/Source/Falcor/Experimental/Scene/Material/BxDF.slang b/Source/Falcor/Experimental/Scene/Material/BxDF.slang index fcda7bf32..58ae49d26 100644 --- a/Source/Falcor/Experimental/Scene/Material/BxDF.slang +++ b/Source/Falcor/Experimental/Scene/Material/BxDF.slang @@ -563,7 +563,7 @@ struct FalcorBSDF : IBxDF if (pSpecularReflection > 0) pdf += pSpecularReflection * specularReflection.evalPdf(wo, wi); if (pSpecularReflectionTransmission > 0) pdf += pSpecularReflectionTransmission * specularReflectionTransmission.evalPdf(wo, wi); } - else if (uSelect < pDiffuseReflection + pSpecularReflection) + else if (pSpecularReflectionTransmission == 0.f || uSelect < pDiffuseReflection + pSpecularReflection) { if (!specularReflection.sample(wo, wi, pdf, weight, lobe, sg)) return false; weight /= pSpecularReflection; diff --git a/Source/Falcor/Experimental/Scene/Material/TexLODHelpers.slang b/Source/Falcor/Experimental/Scene/Material/TexLODHelpers.slang index d57572347..35819bd02 100644 --- a/Source/Falcor/Experimental/Scene/Material/TexLODHelpers.slang +++ b/Source/Falcor/Experimental/Scene/Material/TexLODHelpers.slang @@ -28,167 +28,170 @@ /** Helper functions for the texture level-of-detail (LOD) system. - Supports texture LOD both for ray differentials (Igehy, SIGGRAPH 1999) and a method based on ray cones + Supports texture LOD both for ray differentials (Igehy, SIGGRAPH 1999) and a method based on ray cones, + described in "Strategies for Texture Level-of-Detail for Real-Time Ray Tracing," by + Tomas Akenine-Moller et al., Ray Tracing Gems, 2019. - TODO: This file needs to be updated to the new Scene representation. - See issue #494 + Note that the actual texture lookups are baked into the TextureSampler interfaces. + See WhittedRayTracer.* for an example using these functions. */ -#define CLASSIC_IGEHY +import Experimental.Scene.Material.TexLODTypes; + +#define CLASSIC_IGEHY // if not defined, we use the ray diff method described in Section 20.3.2.2 in the Ray Tracing Gems // ---------------------------------------------------------------------------- // ray cone helpers // ---------------------------------------------------------------------------- -/** Struct representing a ray cone based on width and spread angle. Has both FP32 and FP16 support. +/** Describes a ray cone for texture level-of-detail + + Representing a ray cone based on width and spread angle. Has both FP32 and FP16 support. + Use #define USE_RAYCONES_WITH_FP16_IN_RAYPAYLOAD to use FP16 */ struct RayCone { #ifndef USE_RAYCONES_WITH_FP16_IN_RAYPAYLOAD float width; float spreadAngle; - float getWidth() - { - return width; - } - float getSpreadAngle() - { - return spreadAngle; - } + float getWidth() { return width; } + float getSpreadAngle() { return spreadAngle; } #else uint width_spreadAngle_FP16; - float getWidth() { return f16tof32(width_spreadAngle_FP16 >> 16); } - float getSpreadAngle() { return f16tof32(width_spreadAngle_FP16); } + float getWidth() { return f16tof32(width_spreadAngle_FP16 >> 16); } + float getSpreadAngle() { return f16tof32(width_spreadAngle_FP16); } #endif /** propagate the raycone to the next hit point (hitT distance away) and with the current spreadAngle + update ray cone angle with the surfaceSpreadAngle + + \param[in] surfaceSpreadAngle Surface spread angle, computed using computeScreenSpaceSurfaceSpreadAngle(). + \param[in] hitT Distance to the hit point. */ RayCone propagate(in float surfaceSpreadAngle, in float hitT) // surfaceSpreadAngle = beta in our texLOD paper { float angle = getSpreadAngle(); - return createRayCone(angle * hitT + getWidth(), angle + surfaceSpreadAngle); + return RayCone.create(angle * hitT + getWidth(), angle + surfaceSpreadAngle); } /** compute texture level of details based on ray cone */ + // should really remove this one, but may be good to have for other users, or code readers?!!! float computeLOD(in float triLODConstant, in float hitT, in float3 rayDir, in float3 normal, in float textureWidth, in float textureHeight) // Note: call propagate() before computeLOD() { float lambda = triLODConstant; // constant per triangle float filterWidth = getWidth(); -#if 0 - float distTerm = abs(filterWidth); // keeping this implementation since it is easier to read - float normalTerm = abs(dot(rayDir, normal)); - lambda += 0.5 * log2(textureWidth * textureHeight); // texture size term - lambda += log2(distTerm); // distance term - lambda -= log2(normalTerm); // surface orientation term -#else // this implementation is a tiny bit faster + // keeping this implementation since it is easier to read, but the following three lines that are not commented out are a bit faster + //float distTerm = abs(filterWidth); + //float normalTerm = abs(dot(rayDir, normal)); + //lambda += 0.5 * log2(textureWidth * textureHeight); // texture size term + //lambda += log2(distTerm); // distance term + //lambda -= log2(normalTerm); // surface orientation term float distTerm = filterWidth * filterWidth; float normalTerm = dot(rayDir, normal); lambda += 0.5 * log2(textureWidth * textureHeight * distTerm / (normalTerm * normalTerm)); -#endif return lambda; } + + /** Compute texture level of details based on ray cone + Note that this versions excludes texture dimension dependency, which is instead added back in + using the ExplicitRayConesLodTextureSampler:ITextureSampler in order to support baseColor, specular, etc per surfaces + + \param[in] triLODConstant Value computed by computeRayConeTriangleLODValue(). + \param[in] hitT Distance to the hit point. + \param[in] rayDir Ray direction. + \param[in] normal Normal at the hit point. + */ + float computeLOD(in float triLODConstant, in float hitT, in float3 rayDir, in float3 normal) + { + float lambda = triLODConstant; // constant per triangle + float filterWidth = getWidth(); + + // keeping this implementation since it is easier to read, but the following three lines that are not commented out are a bit faster + //float distTerm = abs(filterWidth); + //float normalTerm = abs(dot(rayDir, normal)); + //lambda += log2(distTerm); // distance term + //lambda -= log2(normalTerm); // surface orientation term + + float distTerm = filterWidth * filterWidth; + float normalTerm = dot(rayDir, normal); + lambda += 0.5 * log2(distTerm / (normalTerm * normalTerm)); + return lambda; + } + + + /** Create a ray cone struct + \param[in] width The width of the ray cone. + \param[in] angle The angle of the ray cone. + */ + static RayCone create(in float width, in float angle) + { + RayCone rc; +#ifndef USE_RAYCONES_WITH_FP16_IN_RAYPAYLOAD + rc.width = width; + rc.spreadAngle = angle; +#else + rc.width_spreadAngle_FP16 = (f32tof16(width) << 16) | f32tof16(angle); +#endif + return rc; + } + }; -/** create a ray cone struct +/** Compute the triangle LOD value based on triangle vertices and texture coordinates, used by ray cones, and + and as a side effect, return the normalized normal as well + \param[in] vertices Triangle vertices + \param[in] txcoords Texture coordinates at triangle vertices. + \param[in] worldMat 3x3 world matrix. + \param[out] normalizedNormalW Normalized normal in world space. + \return Triangle LOD value. */ -RayCone createRayCone(in float w, in float a) +float computeRayConeTriangleLODValue(in float3 vertices[3], in float2 txcoords[3], in float3x3 worldMat, out float3 normalizedNormalW) { - RayCone rc; -#ifndef USE_RAYCONES_WITH_FP16_IN_RAYPAYLOAD - rc.width = w; - rc.spreadAngle = a; -#else - rc.width_spreadAngle_FP16 = (f32tof16(w) << 16) | f32tof16(a); -#endif - return rc; + float2 tx10 = txcoords[1] - txcoords[0]; + float2 tx20 = txcoords[2] - txcoords[0]; + float Ta = abs(tx10.x * tx20.y - tx20.x * tx10.y); + + // we need the area of the triangle, which is length(triangleNormal) in worldspace, and I + // could not figure out a way with fewer than two 3x3 mtx multiplies for ray cones. + float3 edge10 = mul(vertices[1] - vertices[0], worldMat); + float3 edge20 = mul(vertices[2] - vertices[0], worldMat); + + float3 triangleNormal = cross(edge10, edge20); // in world space, by design + float oneDivPa = 1.0 / length(triangleNormal); + normalizedNormalW = triangleNormal * oneDivPa; // normalize face normal with oneDivPa + return 0.5 * log2(Ta * oneDivPa); // value used by texture LOD cones model } -/** based on ddx and ddy of normal and position, compute an estimate of the surface spread angle +/** Compute screen space spread angle at the first hit point based on ddx and ddy of normal and position. + \param[in] positionW Position of the hit point in world space. + \param[in] normalW Normal of the hit point in world space. + \param[in] betaFactorK1 Optional factor, default value = 1. See Ray Tracing Gems, chapter 20. + \param[in] betaFactorK2 Optional factor, default value = 0. See Ray Tracing Gems, chapter 20. + \return Spread angle at hit point. */ -float computeScreenSpaceSurfaceSpreadAngle(in float3 positionW, in float3 normalW, in float3 eyeVectorW, in float betaFactorK1, in float betaFactorK2) +float computeScreenSpaceSurfaceSpreadAngle(in float3 positionW, in float3 normalW, in float betaFactorK1 = 1.0, in float betaFactorK2 = 0.0) { - float beta; float3 dNdx = ddx(normalW); float3 dNdy = ddy(normalW); float3 dPdx = ddx(positionW); float3 dPdy = ddy(positionW); - beta = sqrt(dot(dNdx, dNdx) + dot(dNdy, dNdy)) * sign(dot(dNdx, dPdx) + dot(dNdy, dPdy)); + float beta = sqrt(dot(dNdx, dNdx) + dot(dNdy, dNdy)) * sign(dot(dNdx, dPdx) + dot(dNdy, dPdy)); return 2.0 * beta * betaFactorK1 + betaFactorK2; } -VSOut getVertexAttributesAndTriangleTexLODConstant(in uint triangleIndex, in BuiltInTriangleIntersectionAttributes attribs, out float txLODconstant) -{ - uint3 indices = getIndices(triangleIndex); - float3 barycentrics = float3(1.0 - attribs.barycentrics.x - attribs.barycentrics.y, attribs.barycentrics.x, attribs.barycentrics.y); - - VSOut v; - v.texC = 0; - v.normalW = 0; - v.bitangentW = 0; - v.posW = 0; - v.colorV = 0; - v.prevPosH = 0; - - uint idx[3]; - idx[0] = indices[0] * 3 * 4; - idx[1] = indices[1] * 3 * 4; - idx[2] = indices[2] * 3 * 4; - - // texLOD: compute area of triangle and area in texture coords - float3 vertices[3]; - float2 txcoords[3]; - vertices[0] = asfloat(gPositions.Load3(idx[0])); - vertices[1] = asfloat(gPositions.Load3(idx[1])); - vertices[2] = asfloat(gPositions.Load3(idx[2])); - - vertices[0] = mul(float4(vertices[0], 1.0), gWorldMat[0]).xyz; - vertices[1] = mul(float4(vertices[1], 1.0), gWorldMat[0]).xyz; - vertices[2] = mul(float4(vertices[2], 1.0), gWorldMat[0]).xyz; - float3 e10 = vertices[1] - vertices[0]; - float3 e20 = vertices[2] - vertices[0]; - - float3 triangleNormal = cross(e10, e20); - float oneDivPa = 1.0 / length(triangleNormal); // hopefully no triangles with zero area - - txcoords[0] = asfloat(gTexCrds.Load2(idx[0])); - txcoords[1] = asfloat(gTexCrds.Load2(idx[1])); - txcoords[2] = asfloat(gTexCrds.Load2(idx[2])); - v.texC += txcoords[0] * barycentrics[0]; - v.texC += txcoords[1] * barycentrics[1]; - v.texC += txcoords[2] * barycentrics[2]; - float2 tx1 = txcoords[1] - txcoords[0]; - float2 tx2 = txcoords[2] - txcoords[0]; - float Ta = abs(tx1.x * tx2.y - tx2.x * tx1.y); - - txLODconstant = 0.5 * log2(Ta * oneDivPa); - - [unroll] - for (int i = 0; i < 3; i++) - { - int address = idx[i]; - v.normalW += asfloat(gNormals.Load3(address)) * barycentrics[i]; - v.bitangentW += asfloat(gBitangents.Load3(address)) * barycentrics[i]; - v.posW += vertices[i] * barycentrics[i]; - } - v.posW = mul(float4(v.posW, 1.f), gWorldMat[0]).xyz; - // Transform normal/bitangent to world space - v.normalW = mul(v.normalW, (float3x3)gWorldInvTransposeMat[0]).xyz; - v.bitangentW = mul(v.bitangentW, (float3x3)gWorldMat[0]).xyz; - v.normalW = normalize(v.normalW); - v.bitangentW = normalize(v.bitangentW); - return v; -} // ---------------------------------------------------------------------------- // ray differentials helpers // ---------------------------------------------------------------------------- -/** Struct representing a ray differential +/** Describes a ray differential for texture level-of-detail + + Representing a ray differential based dOdx, dOdy (for ray origin) and dDdx, dDdy (for ray direction) */ + struct RayDiff { float3 dOdx; @@ -196,27 +199,20 @@ struct RayDiff float3 dDdx; float3 dDdy; - float3 getdOdx() - { - return dOdx; - } - float3 getdOdy() - { - return dOdy; - } - float3 getdDdx() - { - return dDdx; - } - float3 getdDdy() - { - return dDdy; - } + float3 getdOdx() { return dOdx; } // these are not super-useful right now, but TODO to add FP16 version later on + float3 getdOdy() { return dOdy; } + float3 getdDdx() { return dDdx; } + float3 getdDdy() { return dDdy; } - /** propagate the ray differential t distances away + /** Propagate the ray differential t distances away + \param[in] O Ray origin. + \param[in] D Ray direction. + \param[in] t The distance to the hit point. + \param[in] N The normal at the hit point. */ RayDiff propagate(in float3 O, in float3 D, in float t, in float3 N) { +#ifdef CLASSIC_IGEHY float3 dOdx = getdOdx() + t * getdDdx(); // part of Igehy Equation 10 float3 dOdy = getdOdy() + t * getdDdy(); @@ -225,221 +221,161 @@ struct RayDiff float dtdy = -dot(dOdy, N) * rcpDN; dOdx += D * dtdx; dOdy += D * dtdy; - - return createRayDiff(dOdx, dOdy, getdDdx(), getdDdy()); // dDdxy remain the same when transferring +#else + float3 dOdx = getdOdx(); // when not using CLASSIC_IGEHY, there is no propagate step, so we leave the ray diff unchanged. + float3 dOdy = getdOdy(); +#endif + return RayDiff.create(dOdx, dOdy, getdDdx(), getdDdy()); } - /** compute texture level of details based on ray differential + /** Create a ray differential struct + \param[in] dOdx The differential ray origin in x. + \param[in] dOdy The differential ray origin in y. + \param[in] dDdx The differential ray direction in x. + \param[in] dDdy The differential ray direction in y. */ - float computeLOD(in float2 dUVdx, in float2 dUVdy, in float txWidth, in float txHeight) // does not need to be a member function, but looks nicer (similar to RayCone) + static RayDiff create(in float3 dOdx, in float3 dOdy, in float3 dDdx, in float3 dDdy) { -#if 0 - float filterWidth = 2.0 * max(txWidth * max(abs(dUVdx.x), abs(dUVdy.x)), txHeight * max(abs(dUVdx.y), abs(dUVdy.y))); // same as in PBRT - return log2(filterWidth); -#else - dUVdx *= txWidth; - dUVdy *= txHeight; - return 0.5 * log2(max(dUVdx.x * dUVdx.x + dUVdx.y * dUVdx.y, dUVdy.x * dUVdy.x + dUVdy.y * dUVdy.y)); // OpenGL style -#endif + RayDiff rd; + rd.dOdx = dOdx; + rd.dOdy = dOdy; + rd.dDdx = dDdx; + rd.dDdy = dDdy; + return rd; } }; -/** create a ray differential struct +/** Computes the ray direction differential under the assumption that getCameraRayDir() is as commented out just above. + \param[in] nonNormalizedCameraRaydir Non-normalized camera ray direction. + \param[in] cameraRight Camera right vector. + \param[in] cameraUp Camera up vector. + \param[in] viewportDims Dimensions of the viewport. + \param[out] dDdx The differential ray direction in x. + \param[out] dDdy The differential ray direction in y. + + the getRayDirectionDifferentials() function differentiates normalize(getCameraRayDir()), where getCameraRayDir() is: + float3 getCameraRayDir(uint2 pixel, uint2 frameDim) + { + float2 p = (pixel.xy + float2(0.5f, 0.5f)) / frameDim.xy; // Pixel center on image plane in [0,1] where (0,0) is top-left + float2 ndc = float2(2, -2) * p + float2(-1, 1); + return ndc.x * gCamera.cameraU + ndc.y * gCamera.cameraV + gCamera.cameraW; // rayDir = world-space direction to point on image plane (unnormalized) + } */ -RayDiff createRayDiff(in float3 dOdx, in float3 dOdy, in float3 dDdx, in float3 dDdy) +void getRayDirectionDifferentials(in float3 nonNormalizedCameraRaydir, in float3 cameraRight, in float3 cameraUp, in float2 viewportDims, out float3 dDdx, out float3 dDdy) { - RayDiff ray; - ray.dOdx = dOdx; - ray.dOdy = dOdy; - ray.dDdx = dDdx; - ray.dDdy = dDdy; - return ray; + // Igehy Equation 8, adapted to getRayDirection() above + float dd = dot(nonNormalizedCameraRaydir, nonNormalizedCameraRaydir); + float divd = 2.0f / (dd * sqrt(dd)); + float dr = dot(nonNormalizedCameraRaydir, cameraRight); + float du = dot(nonNormalizedCameraRaydir, cameraUp); + dDdx = ((dd * cameraRight) - (dr * nonNormalizedCameraRaydir)) * divd / viewportDims.x; + dDdy = -((dd * cameraUp) - (du * nonNormalizedCameraRaydir)) * divd / viewportDims.y; } -VSOut getVertexAttributesAndBaryDifferentials(in uint triangleIndex, in BuiltInTriangleIntersectionAttributes attribs, in float3 rayOrg, in float3 rayDir, - in float hitT, in float3 normalizedGeometricNormal, inout RayDiff raydiff, out float2 dUVdx, out float2 dUVdy) +/** Computes the differential barycentric coordinates and differential texture coordinates + \param[in] rayDiff RayDifferential to be used for these computations. + \param[in] rayDir Ray direction. + \param[in] verticesW Triangle vertices in world space. + \param[in] txcoords Texture coordinates at the three vertices of the triangle. + \param[in] triangleEdge10 Triangle vertex 1 minus triangle vertex 0. + \param[in] triangleEdge20 Triangle vertex 2 minus triangle vertex 0. + \param[in] faceNormalW Normal of the triangle in world space. + \param[in] hitT Distance to the hit point. + \param[out] dBarydx Differential barycentric coordinates in x. Note that we skip the third component, since w=1-u-v and thus dw/dx=-du/dx-dv/dx + \param[out] dBarydy Differential barycentric coordinates in y. Note that we skip the third component, since w=1-u-v and thus dw/dy=-du/dy-dv/dy + \param[out] dUVdx Differential texture coordinates in x. + \param[out] dUVdy Differential texture coordinates in y. +*/ +void computeDifferentialsBarysAndUVs(in RayDiff rayDiff, in float3 rayDir, in float3 verticesW[3], in float2 txcoords[3], + in float3 triangleEdge10, in float3 triangleEdge20, in float3 faceNormalW, in float hitT, + out float2 dBarydx, out float2 dBarydy, out float2 dUVdx, out float2 dUVdy) { - float3 barycentrics = float3(1.0 - attribs.barycentrics.x - attribs.barycentrics.y, attribs.barycentrics.x, attribs.barycentrics.y); - uint3 indices = getIndices(triangleIndex); - VSOut v; - v.texC = 0; - v.normalW = 0; - v.bitangentW = 0; - v.posW = 0; - v.colorV = 0; - v.prevPosH = 0; - - uint idx[3]; - idx[0] = (indices[0] * 3) * 4; - idx[1] = (indices[1] * 3) * 4; - idx[2] = (indices[2] * 3) * 4; - - float3 unormalizedN; - float3 vertices[3]; - float3 normals[3]; - float2 txcoords[3]; - - vertices[0] = asfloat(gPositions.Load3(idx[0])); - vertices[1] = asfloat(gPositions.Load3(idx[1])); - vertices[2] = asfloat(gPositions.Load3(idx[2])); - - normals[0] = asfloat(gNormals.Load3(idx[0])); - normals[1] = asfloat(gNormals.Load3(idx[1])); - normals[2] = asfloat(gNormals.Load3(idx[2])); - v.normalW += normals[0] * barycentrics[0]; - v.normalW += normals[1] * barycentrics[1]; - v.normalW += normals[2] * barycentrics[2]; - unormalizedN = v.normalW; - v.normalW = normalize(v.normalW); - - txcoords[0] = asfloat(gTexCrds.Load2(idx[0])); - txcoords[1] = asfloat(gTexCrds.Load2(idx[1])); - txcoords[2] = asfloat(gTexCrds.Load2(idx[2])); - v.texC += txcoords[0] * barycentrics[0]; - v.texC += txcoords[1] * barycentrics[1]; - v.texC += txcoords[2] * barycentrics[2]; - - [unroll] - for (int i = 0; i < 3; i++) - { - int address = idx[i]; - v.bitangentW += asfloat(gBitangents.Load3(address)) * barycentrics[i]; - v.posW += vertices[i] * barycentrics[i]; - } - v.posW = mul(float4(v.posW, 1.f), gWorldMat[0]).xyz; - // Transform normal/bitangent to world space - v.normalW = mul(v.normalW, (float3x3)gWorldInvTransposeMat[0]).xyz; - v.bitangentW = mul(v.bitangentW, (float3x3)gWorldMat[0]).xyz; - v.normalW = normalize(v.normalW); - v.bitangentW = normalize(v.bitangentW); - - vertices[0] = mul(float4(vertices[0], 1.0), gWorldMat[0]).xyz; - vertices[1] = mul(float4(vertices[1], 1.0), gWorldMat[0]).xyz; - vertices[2] = mul(float4(vertices[2], 1.0), gWorldMat[0]).xyz; - normals[0] = mul(normals[0], (float3x3) gWorldInvTransposeMat[0]).xyz; - normals[1] = mul(normals[1], (float3x3) gWorldInvTransposeMat[0]).xyz; - normals[2] = mul(normals[2], (float3x3) gWorldInvTransposeMat[0]).xyz; - - normals[0] = normalize(normals[0]); - normals[1] = normalize(normals[1]); - normals[2] = normalize(normals[2]); - - // compute differential barycentric coordinates - float3 dBarydx, dBarydy; -//#ifdef CLASSIC_IGEHY // CLASSIC IGEHY IMPLEMENTATION -#if 1 - float3 Nu = cross(vertices[2] - vertices[1], normalizedGeometricNormal); // Igehy "Normal-Interpolated Triangles", page 182 SIGGRAPH 1999 - float3 Nv = cross(vertices[0] - vertices[2], normalizedGeometricNormal); - - float4 Lu = float4(Nu, -dot(Nu, vertices[1])); // plane equations for the triangle edges - float4 Lv = float4(Nv, -dot(Nv, vertices[2])); - - Lu /= dot(Lu, float4(vertices[0], 1.0)); // planes scaled in order to make the dot with the opposive vertex = 1 - Lv /= dot(Lv, float4(vertices[1], 1.0)); - - dBarydx.x = dot(Lu.xyz, raydiff.getdOdx()); // du / dx - dBarydx.y = dot(Lv.xyz, raydiff.getdOdx()); // dv / dx - dBarydx.z = -dBarydx.x - dBarydx.y; // dw / dx (w = 1 - u - w --> dw/dx = - du/dx - dv/dx ) - - dBarydy.x = dot(Lu.xyz, raydiff.getdOdy()); // du / dy - dBarydy.y = dot(Lv.xyz, raydiff.getdOdy()); // dv / dy - dBarydy.z = -dBarydy.x - dBarydy.y; // dw / dy - -#else // OPTIMIZED IMPLEMENTATION - float3 e1 = vertices[1] - vertices[0]; - float3 e2 = vertices[2] - vertices[0]; - float3 Cu = cross(e2, rayDir); - float3 Cv = cross(rayDir, e1); - float one_div_k = 1.0 / dot(Cu, e1); - float3 qx = raydiff.getdOdx() + hitT * raydiff.getdDdx(); - float3 qy = raydiff.getdOdy() + hitT * raydiff.getdDdy(); - - dBarydx.y = dot(Cu, qx) * one_div_k; // du / dx - dBarydx.z = dot(Cv, qx) * one_div_k; // dv / dx - dBarydx.x = -dBarydx.y - dBarydx.z; // dw / dx - - dBarydy.y = dot(Cu, qy) * one_div_k; // du / dy - dBarydy.z = dot(Cv, qy) * one_div_k; // dv / dy - dBarydy.x = -dBarydy.y - dBarydy.z; // dw / dy -#endif +#ifdef CLASSIC_IGEHY + float3 Nu = cross(verticesW[2] - verticesW[1], faceNormalW); // Igehy "Normal-Interpolated Triangles", page 182 SIGGRAPH 1999 + float3 Nv = cross(-triangleEdge20, faceNormalW); - // compute dUdx, dVdx, dUdy, dVdy for texture lookup - dUVdx = dBarydx.x * txcoords[0] + dBarydx.y * txcoords[1] + dBarydx.z * txcoords[2]; - dUVdy = dBarydy.x * txcoords[0] + dBarydy.y * txcoords[1] + dBarydy.z * txcoords[2]; + float4 Lu = float4(Nu, -dot(Nu, verticesW[1])); // plane equations for the triangle edges + float4 Lv = float4(Nv, -dot(Nv, verticesW[2])); - // differential normal (see "Normal-Interpolated Triangles" in Igehy's paper) - float NN = dot(unormalizedN, unormalizedN); // normal must be unnormalized! (otherwise NN would be 1) - float rcpNN = 1.0 / (NN * sqrt(NN)); - float3 dndx = dBarydx.x * normals[0] + dBarydx.y * normals[1] + dBarydx.z * normals[2]; - float3 dndy = dBarydy.x * normals[0] + dBarydy.y * normals[1] + dBarydy.z * normals[2]; - float3 dNdx = (dndx * NN - unormalizedN * dot(unormalizedN, dndx)) * rcpNN; - float3 dNdy = (dndy * NN - unormalizedN * dot(unormalizedN, dndy)) * rcpNN; + Lu /= dot(Lu, float4(verticesW[0], 1.0)); // planes scaled in order to make the dot with the opposive vertex = 1 + Lv /= dot(Lv, float4(verticesW[1], 1.0)); - // differential of reflected ray direction (perfect specular reflection) -- Equation 14 and 15 in Igehy's paper - float dDNdx = dot(raydiff.getdDdx(), v.normalW) + dot(rayDir, dNdx); - float dDNdy = dot(raydiff.getdDdy(), v.normalW) + dot(rayDir, dNdy); - float DN = dot(rayDir, v.normalW); -//#ifdef CLASSIC_IGEHY -#if 1 - float3 dOdx = raydiff.getdOdx(); - float3 dOdy = raydiff.getdOdy(); -#else - float3 dOdx = e1 * dBarydx.y + e2 * dBarydx.z; - float3 dOdy = e1 * dBarydy.y + e2 * dBarydy.z; -#endif - float3 dDdx = raydiff.getdDdx() - 2.0 * (dNdx * DN + v.normalW * dDNdx); - float3 dDdy = raydiff.getdDdy() - 2.0 * (dNdy * DN + v.normalW * dDNdy); - raydiff = createRayDiff(dOdx, dOdy, dDdx, dDdy); + dBarydx.x = dot(Lu.xyz, rayDiff.getdOdx()); // du / dx + dBarydx.y = dot(Lv.xyz, rayDiff.getdOdx()); // dv / dx + dBarydy.x = dot(Lu.xyz, rayDiff.getdOdy()); // du / dy + dBarydy.y = dot(Lv.xyz, rayDiff.getdOdy()); // dv / dy - return v; -} +#else // optimized implementation from Section 20.3.2.2 from Ray Tracing Gems + float3 Cu = cross(triangleEdge20, rayDir); + float3 Cv = cross(rayDir, triangleEdge10); -// the getRayDirectionDifferentials() function differentiates normalize(getCameraRayDir()), where getCameraRayDir() is: -//float3 getCameraRayDir(uint2 pixel, uint2 frameDim) -//{ -// float2 p = (pixel.xy + float2(0.5f, 0.5f)) / frameDim.xy; // Pixel center on image plane in [0,1] where (0,0) is top-left -// float2 ndc = float2(2, -2) * p + float2(-1, 1); -// return ndc.x * gCamera.cameraU + ndc.y * gCamera.cameraV + gCamera.cameraW; // rayDir = world-space direction to point on image plane (unnormalized) -//} -void getRayDirectionDifferentials(in float3 cameraRaydir, in float3 cameraRight, in float3 cameraUp, in float2 viewportDims, out float3 dDdx, out float3 dDdy) -{ - // Igehy Equation 8, adapted to getRayDirection() above - float dd = dot(cameraRaydir, cameraRaydir); - float divd = 2.0f / (dd * sqrt(dd)); - float dr = dot(cameraRaydir, cameraRight); - float du = dot(cameraRaydir, cameraUp); - dDdx = ((dd * cameraRight) - (dr * cameraRaydir)) * divd / viewportDims.x; - dDdy = -((dd * cameraUp) - (du * cameraRaydir)) * divd / viewportDims.y; -} + float k = dot(Cu, triangleEdge10) + float oneDivK = abs(k) > 0.0001f ? rcp(k) : 0.0f; + + float3 qx = rayDiff.getdOdx() + hitT * rayDiff.getdDdx(); + float3 qy = rayDiff.getdOdy() + hitT * rayDiff.getdDdy(); + + dBarydx.y = dot(Cu, qx) * oneDivK; // du / dx + dBarydx.z = dot(Cv, qx) * oneDivK; // dv / dx + dBarydx.x = -dBarydx.y - dBarydx.z; + + dBarydy.y = dot(Cu, qy) * oneDivK; // du / dy + dBarydy.z = dot(Cv, qy) * oneDivK; // dv / dy + dBarydy.x = -dBarydy.y - dBarydy.z; +#endif + + // compute dUdx, dVdx, dUdy, dVdy for texture lookup + float2 tx02 = txcoords[0] - txcoords[2]; + float2 tx12 = txcoords[1] - txcoords[2]; + dUVdx = dBarydx.x * tx02 + dBarydx.y * tx12; + dUVdy = dBarydy.x * tx02 + dBarydy.y * tx12; -float3 getTransformedGeometricNormal(in uint triangleIndex) -{ - uint3 indices = getIndices(triangleIndex); - float3 vertices[3]; - vertices[0] = asfloat(gPositions.Load3(indices[0] * 3 * 4)); - vertices[1] = asfloat(gPositions.Load3(indices[1] * 3 * 4)); - vertices[2] = asfloat(gPositions.Load3(indices[2] * 3 * 4)); - - float3 N = cross(vertices[2] - vertices[0], vertices[1] - vertices[0]); - N = mul(N, (float3x3) gWorldInvTransposeMat[0]); - return normalize(N); } -static const uint numRainbowColors = 7; -static const float4 rainbowColors[7] = +/** Reflects a ray differential + \param[in,out] rayDiff RayDifferential to be reflected, result is returned here as well. + \param[in] rayDir Ray direction. + \param[in] nonNormalizedInterpolatedNormalW Interpolated NON-normalized normal in world space. + \param[in] normalizedInterpolatedNormalW Interpolated normalized normal in world space. + \param[in] dBarydx Differential barycentric coordinates wrt x. + \param[in] dBarydy Differential barycentric coordinates wrt y. + \param[in] triangleEdge10 Triangle vertex 1 minus triangle vertex 0. + \param[in] triangleEdge20 Triangle vertex 2 minus triangle vertex 0. + \param[in] normals The triangle's three normalized normals in world space. +*/ +void reflectRayDifferential(inout RayDiff rayDiff, in float3 rayDir, in float3 nonNormalizedInterpolatedNormalW, + in float3 normalizedInterpolatedNormalW, in float2 dBarydx, in float2 dBarydy, + in float3 triangleEdge10, in float3 triangleEdge20, in float3 normals[3]) { - float4(1.0, 0.0, 0.0, 1.0), - float4(1.0, 1.0, 0.0, 1.0), - float4(0.0, 1.0, 0.0, 1.0), - float4(0.0, 1.0, 1.0, 1.0), - float4(0.0, 0.0, 1.0, 1.0), - float4(1.0, 0.0, 1.0, 1.0), - float4(1.0, 1.0, 1.0, 1.0), -}; + // differential normal (see "Normal-Interpolated Triangles" in Igehy's paper) + float NN = dot(nonNormalizedInterpolatedNormalW, nonNormalizedInterpolatedNormalW); // normal must be unnormalized! (otherwise NN would be 1) + float rcpNN = 1.0 / (NN * sqrt(NN)); + float3 n02 = normals[0] - normals[2]; + float3 n12 = normals[1] - normals[2]; + float3 dndx = dBarydx.x * n02 + dBarydx.y * n12; + float3 dndy = dBarydy.x * n02 + dBarydy.y * n12; + float3 dNdx = (dndx * NN - nonNormalizedInterpolatedNormalW * dot(nonNormalizedInterpolatedNormalW, dndx)) * rcpNN; + float3 dNdy = (dndy * NN - nonNormalizedInterpolatedNormalW * dot(nonNormalizedInterpolatedNormalW, dndy)) * rcpNN; -float4 lambdaToRainbowColor(in float lambda) -{ - uint idx = uint(clamp(lambda, 0, numRainbowColors - 1)); - float t = lambda - idx; - return (1.0 - t) * rainbowColors[idx] + t * rainbowColors[idx + 1]; + // differential of reflected ray direction (perfect specular reflection) -- Equation 14 and 15 in Igehy's paper + float dDNdx = dot(rayDiff.getdDdx(), normalizedInterpolatedNormalW) + dot(rayDir, dNdx); + float dDNdy = dot(rayDiff.getdDdy(), normalizedInterpolatedNormalW) + dot(rayDir, dNdy); + float DN = dot(rayDir, normalizedInterpolatedNormalW); +#ifdef CLASSIC_IGEHY + float3 dOdx = rayDiff.getdOdx(); + float3 dOdy = rayDiff.getdOdy(); +#else + float dBarydx_z = -dBarydx.x - dBarydx.y; // we usually only need u,v and not w=1-u-v, but here we need it + float dBarydy_z = -dBarydy.x - dBarydy.y; + // the reason why this following code looks different is that in Chapter 20, Ray Tracing Gems, equation 12 + // defines a point in the plane as: P = P_0 + u*e_1 + v*e_2, where e1 = P_1 - P_0 and e_2 = P_2 - P_0 + // but in the rest of the paper we used P = u * P_0 + v * P_1 + w * P_2, + // which means that in Equation 22, du/dx is dBaryDx.y (that is dv/dx) and dv/dx is dBarydx_z (that dw/dx) + float3 dOdx = triangleEdge10 * dBarydx.y + triangleEdge20 * dBarydx_z; + float3 dOdy = triangleEdge10 * dBarydy.y + triangleEdge20 * dBarydy_z; +#endif + float3 dDdx = rayDiff.getdDdx() - 2.0 * (dNdx * DN + normalizedInterpolatedNormalW * dDNdx); + float3 dDdy = rayDiff.getdDdy() - 2.0 * (dNdy * DN + normalizedInterpolatedNormalW * dDNdy); + rayDiff = RayDiff.create(dOdx, dOdy, dDdx, dDdy); } + diff --git a/Source/Falcor/Experimental/Scene/Material/TexLODTypes.slang b/Source/Falcor/Experimental/Scene/Material/TexLODTypes.slang new file mode 100644 index 000000000..cbb25b0b9 --- /dev/null +++ b/Source/Falcor/Experimental/Scene/Material/TexLODTypes.slang @@ -0,0 +1,71 @@ +/*************************************************************************** + # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** enum for texture level-of-detail -- see TexLODHelpers.slang +*/ + +#pragma once +#include "Utils/HostDeviceShared.slangh" + +BEGIN_NAMESPACE_FALCOR + +/** This enum is shared between CPU/GPU. + It enumerates the different the different texture LOD modes. +*/ +enum class TexLODMode + // TODO: Remove the ifdefs and the include when Slang supports enum type specifiers. +#ifdef HOST_CODE + : uint32_t +#endif +{ + Mip0 = 0, + RayCones = 1, + RayDiffsIsotropic = 2, + RayDiffsAnisotropic = 3, +}; + +// Define to_string() for TexLODMode for use in serialization. +#ifdef HOST_CODE +#define str(a) case TexLODMode::a: return #a +inline std::string to_string(TexLODMode type) +{ + switch (type) + { + str(Mip0); + str(RayCones); + str(RayDiffsIsotropic); + str(RayDiffsAnisotropic); + default: + should_not_get_here(); + return ""; + } +} +#undef str +#endif + +END_NAMESPACE_FALCOR diff --git a/Source/Falcor/Falcor.h b/Source/Falcor/Falcor.h index e03276f60..02d318875 100644 --- a/Source/Falcor/Falcor.h +++ b/Source/Falcor/Falcor.h @@ -164,7 +164,5 @@ #endif #define FALCOR_MAJOR_VERSION 4 -#define FALCOR_MINOR_VERSION 0 -#define FALCOR_DEV_STAGE "preview" -#define FALCOR_DEV_REVISION 0 -#define FALCOR_VERSION_STRING "4.0preview.0" +#define FALCOR_REVISION 1 +#define FALCOR_VERSION_STRING "4.1" diff --git a/Source/Falcor/Falcor.props b/Source/Falcor/Falcor.props index 6a95668e2..73af19fb0 100644 --- a/Source/Falcor/Falcor.props +++ b/Source/Falcor/Falcor.props @@ -14,12 +14,12 @@ Level3 true - $(FALCOR_CORE_DIRECTORY)\Falcor;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Cuda\include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Optix\include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\nvapi;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\GLM;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\VulkanSDK\Include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\RapidJson\include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\pybind11\include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Python\include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\WinPixEventRuntime\Include\WinPixEventRuntime;$(FALCOR_CORE_DIRECTORY)\Externals;$(FALCOR_CORE_DIRECTORY)\Externals\.packman;%(AdditionalIncludeDirectories) + $(FALCOR_CORE_DIRECTORY)\Falcor;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\nvapi;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\GLM;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\VulkanSDK\Include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\RapidJson\include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\pybind11\include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Python\include;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\WinPixEventRuntime\Include\WinPixEventRuntime;$(FALCOR_CORE_DIRECTORY)\Externals;$(FALCOR_CORE_DIRECTORY)\Externals\.packman;%(AdditionalIncludeDirectories) _$(OutputType);_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;GLM_FORCE_DEPTH_ZERO_TO_ONE;$(FALCOR_BACKEND);_UNICODE;UNICODE;%(PreprocessorDefinitions) stdcpp17 - $(FALCOR_CORE_DIRECTORY)\Externals\.packman\Cuda\lib\x64;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\FreeImage;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Assimp\lib\$(PlatformName);$(FALCOR_CORE_DIRECTORY)\Externals\.packman\FFMpeg\lib\$(PlatformName);$(FALCOR_CORE_DIRECTORY)\Externals\.packman\nvapi\amd64;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\VulkanSDK\Lib;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Slang\bin\windows-x64\release;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\GLFW\lib;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Python\libs;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\WinPixEventRuntime\bin\x64;%(AdditionalLibraryDirectories) + $(FALCOR_CORE_DIRECTORY)\Externals\.packman\FreeImage;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Assimp\lib\$(PlatformName);$(FALCOR_CORE_DIRECTORY)\Externals\.packman\FFMpeg\lib\$(PlatformName);$(FALCOR_CORE_DIRECTORY)\Externals\.packman\nvapi\amd64;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\VulkanSDK\Lib;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Slang\bin\windows-x64\release;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\GLFW\lib;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\Python\libs;$(FALCOR_CORE_DIRECTORY)\Externals\.packman\WinPixEventRuntime\bin\x64;%(AdditionalLibraryDirectories) WinPixEventRuntime.lib;glfw3dll.lib;slang.lib;Comctl32.lib;Shlwapi.lib;assimp-vc141-mt.lib;freeimage.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;avcodec.lib;avutil.lib;avformat.lib;swscale.lib;Shcore.lib;%(AdditionalDependencies) @@ -45,4 +45,4 @@ true - \ No newline at end of file + diff --git a/Source/Falcor/Falcor.vcxproj b/Source/Falcor/Falcor.vcxproj index f984d7de6..2ff7f880c 100644 --- a/Source/Falcor/Falcor.vcxproj +++ b/Source/Falcor/Falcor.vcxproj @@ -142,18 +142,18 @@ - + - + @@ -165,6 +165,7 @@ + @@ -237,6 +238,7 @@ + diff --git a/Source/Falcor/Falcor.vcxproj.filters b/Source/Falcor/Falcor.vcxproj.filters index f90410e8f..494d60c83 100644 --- a/Source/Falcor/Falcor.vcxproj.filters +++ b/Source/Falcor/Falcor.vcxproj.filters @@ -481,9 +481,6 @@ Scene\Importers - - RenderPasses\Shared - Utils @@ -493,6 +490,9 @@ RenderPasses\Shared\PathTracer + + Scene + @@ -1433,9 +1433,6 @@ Experimental\Scene\Material - - RenderPasses\Shared - RenderPasses\Shared\PathTracer @@ -1469,5 +1466,14 @@ Utils\Debug + + Experimental\Scene\Material + + + Utils + + + Scene + \ No newline at end of file diff --git a/Source/Falcor/Raytracing/ShaderTable.cpp b/Source/Falcor/Raytracing/ShaderTable.cpp index 84748faf9..66360d30c 100644 --- a/Source/Falcor/Raytracing/ShaderTable.cpp +++ b/Source/Falcor/Raytracing/ShaderTable.cpp @@ -110,7 +110,7 @@ namespace Falcor } auto& info = mSubTables[uint32_t(subTableType)]; - info.recordSize = max(pEntryPointGroup->getLocalRootSignature()->getSizeInBytes(), info.recordSize); + info.recordSize = std::max(pEntryPointGroup->getLocalRootSignature()->getSizeInBytes(), info.recordSize); } uint32_t subTableOffset = 0; diff --git a/Source/Falcor/RenderGraph/BasePasses/ComputePass.cpp b/Source/Falcor/RenderGraph/BasePasses/ComputePass.cpp index 79d380faa..6fdb222d4 100644 --- a/Source/Falcor/RenderGraph/BasePasses/ComputePass.cpp +++ b/Source/Falcor/RenderGraph/BasePasses/ComputePass.cpp @@ -54,11 +54,17 @@ namespace Falcor void ComputePass::execute(ComputeContext* pContext, uint32_t nThreadX, uint32_t nThreadY, uint32_t nThreadZ) { assert(mpVars); - uvec3 threadGroupSize = mpState->getProgram()->getReflector()->getThreadGroupSize(); - uvec3 groups = div_round_up(glm::uvec3(nThreadX, nThreadY, nThreadZ), threadGroupSize); + uint3 threadGroupSize = mpState->getProgram()->getReflector()->getThreadGroupSize(); + uint3 groups = div_round_up(uint3(nThreadX, nThreadY, nThreadZ), threadGroupSize); pContext->dispatch(mpState.get(), mpVars.get(), groups); } + void ComputePass::executeIndirect(ComputeContext* pContext, const Buffer* pArgBuffer, uint64_t argBufferOffset) + { + assert(mpVars); + pContext->dispatchIndirect(mpState.get(), mpVars.get(), pArgBuffer, argBufferOffset); + } + void ComputePass::addDefine(const std::string& name, const std::string& value, bool updateVars) { mpState->getProgram()->addDefine(name, value); diff --git a/Source/Falcor/RenderGraph/BasePasses/ComputePass.h b/Source/Falcor/RenderGraph/BasePasses/ComputePass.h index 1b6ddffac..1405dda12 100644 --- a/Source/Falcor/RenderGraph/BasePasses/ComputePass.h +++ b/Source/Falcor/RenderGraph/BasePasses/ComputePass.h @@ -65,7 +65,14 @@ namespace Falcor \param[in] pContext The compute context \param[in] nThreads The number of threads to dispatch in the XYZ dimensions (note that this is not the number of thread groups) */ - virtual void execute(ComputeContext* pContext, const glm::uvec3& nThreads) { execute(pContext, nThreads.x, nThreads.y, nThreads.z); } + virtual void execute(ComputeContext* pContext, const uint3& nThreads) { execute(pContext, nThreads.x, nThreads.y, nThreads.z); } + + /** Execute the pass using indirect dispatch given the compute-context and argument buffer + \param[in] pContext The compute context + \param[in] pArgBuffer Argument buffer + \param[in] argBufferOffset Offset in argument buffer + */ + virtual void executeIndirect(ComputeContext* context, const Buffer* pArgBuffer, uint64_t argBufferOffset = 0); /** Get the vars */ @@ -88,12 +95,12 @@ namespace Falcor /** Set a vars object. Allows the user to override the internal vars, for example when one wants to share a vars object between different passes. The function throws an exception on error. \param[in] pVars The new GraphicsVars object. If this is nullptr, then the pass will automatically create a new vars object. - */ + */ void setVars(const ComputeVars::SharedPtr& pVars); /** Get the thread group size from the program */ - uvec3 getThreadGroupSize() const { return mpState->getProgram()->getReflector()->getThreadGroupSize(); } + uint3 getThreadGroupSize() const { return mpState->getProgram()->getReflector()->getThreadGroupSize(); } protected: ComputePass(const Program::Desc& desc, const Program::DefineList& defines, bool createVars); diff --git a/Source/Falcor/RenderGraph/BasePasses/FullScreenPass.cpp b/Source/Falcor/RenderGraph/BasePasses/FullScreenPass.cpp index ee7251e7e..0a87848ae 100644 --- a/Source/Falcor/RenderGraph/BasePasses/FullScreenPass.cpp +++ b/Source/Falcor/RenderGraph/BasePasses/FullScreenPass.cpp @@ -53,8 +53,8 @@ namespace Falcor } struct Vertex { - glm::vec2 screenPos; - glm::vec2 texCoord; + float2 screenPos; + float2 texCoord; }; #ifdef FALCOR_VK @@ -65,10 +65,10 @@ namespace Falcor const Vertex kVertices[] = { - {glm::vec2(-1, ADJUST_Y(1)), glm::vec2(0, 0)}, - {glm::vec2(-1, ADJUST_Y(-1)), glm::vec2(0, 1)}, - {glm::vec2(1, ADJUST_Y(1)), glm::vec2(1, 0)}, - {glm::vec2(1, ADJUST_Y(-1)), glm::vec2(1, 1)}, + {float2(-1, ADJUST_Y(1)), float2(0, 0)}, + {float2(-1, ADJUST_Y(-1)), float2(0, 1)}, + {float2(1, ADJUST_Y(1)), float2(1, 0)}, + {float2(1, ADJUST_Y(-1)), float2(1, 1)}, }; #undef ADJUST_Y diff --git a/Source/Falcor/RenderGraph/RenderGraph.cpp b/Source/Falcor/RenderGraph/RenderGraph.cpp index 66ca6ed02..d5bba24a7 100644 --- a/Source/Falcor/RenderGraph/RenderGraph.cpp +++ b/Source/Falcor/RenderGraph/RenderGraph.cpp @@ -750,19 +750,20 @@ namespace Falcor SCRIPT_BINDING(RenderGraph) { - void(RenderGraph::*renderGraphRemoveEdge)(const std::string&, const std::string&)(&RenderGraph::removeEdge); auto graphClass = m.regClass(RenderGraph); graphClass.ctor(&RenderGraph::create); - graphClass.func_(RenderGraphIR::kAddPass, &RenderGraph::addPass, "renderPass"_a, "passName"_a).func_(RenderGraphIR::kRemovePass, &RenderGraph::removePass); - graphClass.func_(RenderGraphIR::kAddEdge, &RenderGraph::addEdge).func_(RenderGraphIR::kRemoveEdge, renderGraphRemoveEdge); - graphClass.func_(RenderGraphIR::kMarkOutput, &RenderGraph::markOutput).func_(RenderGraphIR::kUnmarkOutput, &RenderGraph::unmarkOutput); - graphClass.func_(RenderGraphIR::kAutoGenEdges, &RenderGraph::autoGenEdges); - graphClass.func_("name", &RenderGraph::setName); - graphClass.func_("name", &RenderGraph::getName); - graphClass.func_("getPass", &RenderGraph::getPass); + graphClass.property("name", &RenderGraph::getName, &RenderGraph::setName); + graphClass.func_(RenderGraphIR::kAddPass, &RenderGraph::addPass, "pass"_a, "name"_a); + graphClass.func_(RenderGraphIR::kRemovePass, &RenderGraph::removePass, "name"_a); + graphClass.func_(RenderGraphIR::kAddEdge, &RenderGraph::addEdge, "src"_a, "dst"_a); + graphClass.func_(RenderGraphIR::kRemoveEdge, ScriptBindings::overload_cast(&RenderGraph::removeEdge), "src"_a, "src"_a); + graphClass.func_(RenderGraphIR::kMarkOutput, &RenderGraph::markOutput, "name"_a); + graphClass.func_(RenderGraphIR::kUnmarkOutput, &RenderGraph::unmarkOutput, "name"_a); + graphClass.func_(RenderGraphIR::kAutoGenEdges, &RenderGraph::autoGenEdges, "executionOrder"_a); + graphClass.func_("getPass", &RenderGraph::getPass, "name"_a); + graphClass.func_("getOutput", ScriptBindings::overload_cast(&RenderGraph::getOutput), "name"_a); auto printGraph = [](RenderGraph::SharedPtr pGraph) { pybind11::print(RenderGraphExporter::getIR(pGraph)); }; graphClass.func_("print", printGraph); - graphClass.func_("getOutput", ScriptBindings::overload_cast(&RenderGraph::getOutput)); // RenderPass auto passClass = m.regClass(RenderPass); @@ -774,18 +775,18 @@ namespace Falcor if (!pPass) throw std::exception(("Can't create a render pass named `" + passName + "`. Make sure the required DLL was loaded.").c_str()); return pPass; }; - passClass.ctor(createRenderPass, "passName"_a, "dict"_a = pybind11::dict()); + passClass.ctor(createRenderPass, "name"_a, "dict"_a = pybind11::dict()); const auto& loadPassLibrary = [](const std::string& library) { return RenderPassLibrary::instance().loadLibrary(library); }; - m.func_(RenderGraphIR::kLoadPassLibrary, loadPassLibrary); + m.func_(RenderGraphIR::kLoadPassLibrary, loadPassLibrary, "name"_a); const auto& updateRenderPass = [](const RenderGraph::SharedPtr& pGraph, const std::string& passName, pybind11::dict d) { pGraph->updatePass(gpDevice->getRenderContext(), passName, Dictionary(d)); }; - graphClass.func_(RenderGraphIR::kUpdatePass, updateRenderPass); + graphClass.func_(RenderGraphIR::kUpdatePass, updateRenderPass, "name"_a, "dict"_a); } } diff --git a/Source/Falcor/RenderGraph/RenderGraph.h b/Source/Falcor/RenderGraph/RenderGraph.h index 9be1e9658..404b0fac0 100644 --- a/Source/Falcor/RenderGraph/RenderGraph.h +++ b/Source/Falcor/RenderGraph/RenderGraph.h @@ -36,7 +36,7 @@ namespace Falcor { - class dlldecl RenderGraph + class dlldecl RenderGraph : public std::enable_shared_from_this { public: using SharedPtr = std::shared_ptr; diff --git a/Source/Falcor/RenderGraph/RenderGraphExe.h b/Source/Falcor/RenderGraph/RenderGraphExe.h index 7e4c7ae38..e704d8407 100644 --- a/Source/Falcor/RenderGraph/RenderGraphExe.h +++ b/Source/Falcor/RenderGraph/RenderGraphExe.h @@ -42,7 +42,7 @@ namespace Falcor { RenderContext* pRenderContext; Dictionary::SharedPtr pGraphDictionary; - uvec2 defaultTexDims; + uint2 defaultTexDims; ResourceFormat defaultTexFormat; }; diff --git a/Source/Falcor/RenderGraph/RenderGraphUI.cpp b/Source/Falcor/RenderGraph/RenderGraphUI.cpp index b151462f2..49e8ca3e7 100644 --- a/Source/Falcor/RenderGraph/RenderGraphUI.cpp +++ b/Source/Falcor/RenderGraph/RenderGraphUI.cpp @@ -60,10 +60,10 @@ namespace Falcor void reset() { inited = false; } - glm::vec2 getOffsetPos() const { return { offset.x, offset.y }; } + float2 getOffsetPos() const { return { offset.x, offset.y }; } ImGui::NodeLink& getLink(int32_t index) { return links[index]; } - + void setLinkColor(uint32_t index, uint32_t col) { links[index].LinkColor = col; } RenderGraphUI* getRenderGraphUI() { return mpRenderGraphUI; } @@ -72,7 +72,7 @@ namespace Falcor ImGui::Node* getPopupNode() { return mpFocusedNode; } - void setPopupPin(uint32_t pinIndex, bool isInput) + void setPopupPin(uint32_t pinIndex, bool isInput) { if (ImGui::IsAnyMouseDown()) { @@ -80,7 +80,7 @@ namespace Falcor mPinIndexToDisplay = -1; } - if ((pinIndex != -1) )//&& pinIndex != mPinIndexToDisplay) + if ((pinIndex != -1) )//&& pinIndex != mPinIndexToDisplay) { std::chrono::system_clock::time_point thisTime = std::chrono::system_clock::now(); float timeDiff = (std::chrono::duration(thisTime - mLastTime)).count(); @@ -88,9 +88,9 @@ namespace Falcor mLastTime = thisTime; if (mPopupPinHoverTime < kTimeTillPopup) return; } - + if (mPopupPinHoverTime >= kTimeTillPopup) mPopupPinHoverTime = 0.0f; - mPinIndexToDisplay = pinIndex; mPopupPinIsInput = isInput; + mPinIndexToDisplay = pinIndex; mPopupPinIsInput = isInput; } void deselectPopupPin() @@ -110,7 +110,7 @@ namespace Falcor uint32_t getPopupPinIndex() const { return mPinIndexToDisplay; } bool isPopupPinInput() const { return mPopupPinIsInput; } - + ImGui::Node*& getNodeFromID(uint32_t nodeID) { return mpIDtoNode[nodeID]; } // wraps around creating link to avoid setting static flag @@ -193,13 +193,13 @@ namespace Falcor } // Allow the renderGraphUI to set the position of each node - void setPos(const glm::vec2& pos) + void setPos(const float2& pos) { Pos.x = pos.x; Pos.y = pos.y; } - glm::vec2 getPos() + float2 getPos() { return {Pos.x, Pos.y}; } @@ -300,7 +300,7 @@ namespace Falcor } ImGui::SetCursorScreenPos(oldScreenPos); - + for (int32_t i = 0; i < paddingSpace; ++i) { ImGui::TextUnformatted(dummyText.c_str()); @@ -311,7 +311,7 @@ namespace Falcor return false; } - void initialize(const std::string& name, const std::string& outputsString, + void initialize(const std::string& name, const std::string& outputsString, const std::string& inputsString, uint32_t guiNodeID, RenderPass* pRenderPass) { init(name.c_str(), Pos, inputsString.c_str(), outputsString.c_str(), guiNodeID); @@ -319,10 +319,10 @@ namespace Falcor if (pRenderPass) { mpRenderPass = pRenderPass; - const glm::vec4 nodeColor = Gui::pickUniqueColor(pRenderPass->getName()); + const float4 nodeColor = Gui::pickUniqueColor(pRenderPass->getName()); overrideTitleBgColor = ImGui::GetColorU32({ nodeColor.x, nodeColor.y, nodeColor.z, nodeColor.w }); } - + bool isInputs = true; uint32_t pinCount = static_cast(InputsCount); for (uint32_t j = 0; j < 2; ++j) @@ -409,7 +409,7 @@ namespace Falcor { return RenderGraphUI::RenderGraphNode::create(pos); } - + void RenderGraphUI::addRenderPass(const std::string& name, const std::string& nodeTypeName) { mpIr->addPass(nodeTypeName, name); @@ -466,13 +466,13 @@ namespace Falcor mLogString += warningMsg; return true; } - + return false; } bool RenderGraphUI::addLink(const std::string& srcPass, const std::string& dstPass, const std::string& srcField, const std::string& dstField, uint32_t& color) { - // outputs warning if edge could not be created + // outputs warning if edge could not be created std::string srcString = srcPass + (srcField[0] == '#' ? "" : ".") + srcField; std::string dstString = dstPass + (dstField[0] == '#' ? "" : ".") + dstField; bool canCreateEdge = (mpRenderGraph->getEdge(srcString, dstString) == ((uint32_t)-1)); @@ -487,11 +487,11 @@ namespace Falcor if ((dstField[0] == '#') || (srcField[0] == '#')) canCreateEdge &= (srcField[0] == '#') && (dstField[0] == '#'); // check that link could exist - canCreateEdge &= (outputIt != srcRenderPassUI.mNameToIndexOutput.end()) && + canCreateEdge &= (outputIt != srcRenderPassUI.mNameToIndexOutput.end()) && (inputIt != dstRenderPassUI.mNameToIndexInput.end()); // check that the input is not already connected canCreateEdge &= (mInputPinStringToLinkID.find(dstString) == mInputPinStringToLinkID.end()); - + if (canCreateEdge) { @@ -501,7 +501,7 @@ namespace Falcor srcRenderPassUI.mOutputPins[srcPinIndex].mConnectedNodeName = dstPass; dstRenderPassUI.mInputPins[dstPinIndex].mConnectedPinName = srcField; dstRenderPassUI.mInputPins[dstPinIndex].mConnectedNodeName = srcPass; - + if (!(dstField[0] == '#')) { RenderPassReflection srcReflection = mpRenderGraph->mNodeData[mpRenderGraph->getPassIndex(srcPass)].pPass->reflect({}); @@ -514,7 +514,7 @@ namespace Falcor if (canCreateEdge) { - + mShouldUpdate = true; if (dstField[0] == '#') @@ -569,7 +569,7 @@ namespace Falcor mLastCommand = newCommands; if (mRecordUpdates) mUpdateCommands += newCommands; - // update reference graph to check if valid before sending to next + // update reference graph to check if valid before sending to next Scripting::getGlobalContext().setObject("g", mpRenderGraph); Scripting::runScript(newCommands); if(newCommands.size()) mLogString += newCommands; @@ -610,7 +610,7 @@ namespace Falcor RenderGraphUI::~RenderGraphUI() { } - + void RenderGraphUI::NodeGraphEditorGui::setNode(ImGui::Node*& node, ImGui::NodeGraphEditor::NodeState state, ImGui::NodeGraphEditor& editor) { RenderGraphNode* pRenderGraphNode = static_cast(node); @@ -787,13 +787,13 @@ namespace Falcor { bool isPopupOpen = false; bool first = false; - + if (!(isPopupOpen = ImGui::IsPopupOpen(ImGui::GetCurrentWindow()->GetID("PinMenu")))) { ImGui::OpenPopup("PinMenu"); first = true; } - + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); if (ImGui::BeginPopup("PinMenu")) { @@ -839,7 +839,7 @@ namespace Falcor ImGui::SameLine(); ImGui::TextUnformatted(edgeData.srcField.c_str()); } - + if (edgeData.dstField.size()) { ImGui::TextUnformatted("Dst Field : "); @@ -855,7 +855,7 @@ namespace Falcor } } } - + ImGui::EndPopup(); } ImGui::PopStyleVar(); @@ -873,9 +873,9 @@ namespace Falcor mpNodeGraphEditor->show_left_pane = false; mpNodeGraphEditor->setLinkCallback(NodeGraphEditorGui::setLinkFromGui); mpNodeGraphEditor->setNodeCallback(NodeGraphEditorGui::setNode); - + ImVec2 mousePos = ImGui::GetMousePos(); - ImGui::NodeGraphEditor::Style& style = mpNodeGraphEditor->GetStyle(); + ImGui::NodeGraphEditor::Style& style = mpNodeGraphEditor->GetStyle(); style.color_node_frame_selected = ImGui::ColorConvertFloat4ToU32({ 226.0f / 255.0f, 190.0f / 255.0f, 42.0f / 255.0f, 0.8f }); style.color_node_frame_active = style.color_node_frame_selected; style.node_slots_radius = kPinRadius; @@ -959,7 +959,7 @@ namespace Falcor if (!mpNodeGraphEditor->isInited()) { mpNodeGraphEditor->render(); - + std::string statement; bool addPass = false; bool b = false; @@ -1017,7 +1017,7 @@ namespace Falcor mShouldUpdate = true; if (mMaxNodePositionX < mNewNodeStartPosition.x) mMaxNodePositionX = mNewNodeStartPosition.x; } - + // set editor window behind other windows. set top menu bar to always be infront.this is repeated for other render call ImGui::BringWindowToDisplayBack(ImGui::FindWindowByName("Graph Editor")); ImGui::BringWindowToDisplayFront(ImGui::FindWindowByName("##MainMenuBar")); @@ -1027,7 +1027,7 @@ namespace Falcor updateDisplayData(pContext); mAllNodeTypes.clear(); - + // reset internal data of node if all nodes deleted if (!mRenderPassUI.size()) { @@ -1035,7 +1035,7 @@ namespace Falcor mpNodeGraphEditor->render(); return; } - + for (auto& nodeTypeString : mAllNodeTypeStrings) { mAllNodeTypes.push_back(nodeTypeString.c_str()); @@ -1049,7 +1049,7 @@ namespace Falcor std::string inputsString; std::string outputsString; std::string nameString; - + for (const auto& currentPinUI : currentPassUI.mInputPins) { // Connect the graph nodes for each of the edges @@ -1057,28 +1057,28 @@ namespace Falcor const std::string& currentPinName = currentPinUI.mPinName; inputsString += inputsString.size() ? (";" + currentPinName) : currentPinName; } - + for (const auto& currentPinUI : currentPassUI.mOutputPins) { const std::string& currentPinName = currentPinUI.mPinName; outputsString += outputsString.size() ? (";" + currentPinName) : currentPinName; } - + uint32_t guiNodeID = currentPassUI.mGuiNodeID; RenderPass* pNodeRenderPass = mpRenderGraph->getPass(currentPass.first).get(); nameString = currentPass.first; - + if (!mpNodeGraphEditor->getAllNodesOfType(currentPassUI.mGuiNodeID, nullptr, false)) { - glm::vec2 nextPosition = mAddedFromDragAndDrop ? mNewNodeStartPosition : getNextNodePosition(mpRenderGraph->getPassIndex(nameString)); - + float2 nextPosition = mAddedFromDragAndDrop ? mNewNodeStartPosition : getNextNodePosition(mpRenderGraph->getPassIndex(nameString)); + mpNodeGraphEditor->getNodeFromID(guiNodeID) = mpNodeGraphEditor->addAndInitNode(guiNodeID, nameString, outputsString, inputsString, guiNodeID, pNodeRenderPass, ImVec2(nextPosition.x, nextPosition.y)); mAddedFromDragAndDrop = false; } } - + updatePins(); mpNodeGraphEditor->render(); ImGui::BringWindowToDisplayBack(ImGui::FindWindowByName("Graph Editor")); @@ -1213,9 +1213,9 @@ namespace Falcor mpNodeGraphEditor->getNodeFromID(inputIDs.second),inputIDs.first )) { auto edgeIt = mInputPinStringToLinkID.find(currentPass.first + "." + currentPinName); - assert(edgeIt != mInputPinStringToLinkID.end()); + assert(edgeIt != mInputPinStringToLinkID.end()); uint32_t edgeID = edgeIt->second; - + removeEdge(mpNodeGraphEditor->getNodeFromID(connectedNodeUI.mGuiNodeID)->getName(), mpNodeGraphEditor->getNodeFromID(inputIDs.second)->getName(), mpRenderGraph->mEdgeData[edgeID].srcField, mpRenderGraph->mEdgeData[edgeID].dstField); mpRenderGraph->removeEdge(edgeID); @@ -1223,7 +1223,7 @@ namespace Falcor currentPinUI.mConnectedNodeName = ""; RenderGraphNode* pDstGraphNode = static_cast(mpNodeGraphEditor->getNodeFromID(inputIDs.second)); RenderGraphNode* pSrcGraphNode = static_cast(mpNodeGraphEditor->getNodeFromID(connectedNodeUI.mGuiNodeID)); - + pDstGraphNode->mInputPinConnected[inputIDs.first] = false; pSrcGraphNode->mOutputPinConnected[inputPinID] = false; pSrcGraphNode->setPinColor(kPinColor, inputPinID, false); @@ -1236,11 +1236,11 @@ namespace Falcor } } - glm::vec2 RenderGraphUI::getNextNodePosition(uint32_t nodeID) + float2 RenderGraphUI::getNextNodePosition(uint32_t nodeID) { const float offsetX = 384.0f; const float offsetY = 128.0f; - glm::vec2 newNodePosition = mNewNodeStartPosition; + float2 newNodePosition = mNewNodeStartPosition; auto topologicalSort = DirectedGraphTopologicalSort::sort(mpRenderGraph->mpGraph.get()); @@ -1263,7 +1263,7 @@ namespace Falcor uint32_t outgoingEdgeCount = mpRenderGraph->mpGraph->getNode(mpRenderGraph->mpGraph->getEdge(pNode->getIncomingEdge(i))->getSourceNode())->getOutgoingEdgeCount(); if (outgoingEdgeCount > pNode->getIncomingEdgeCount()) { - // move down by index in + // move down by index in newNodePosition.y += offsetY * (outgoingEdgeCount - pNode->getIncomingEdgeCount()); break; } @@ -1287,7 +1287,7 @@ namespace Falcor std::unordered_set nodeConnectedOutput; std::unordered_map previousGuiNodeIDs; std::unordered_set existingIDs; - + for (const auto& currentRenderPassUI : mRenderPassUI) { existingIDs.insert(currentRenderPassUI.second.mGuiNodeID); @@ -1325,7 +1325,7 @@ namespace Falcor nodeIndex++; } - // clear and rebuild reflection for each pass. + // clear and rebuild reflection for each pass. renderPassUI.mReflection = mpRenderGraph->mNodeData[nameToIndex.second].pPass->reflect({}); // test to see if we have hit a graph output @@ -1353,8 +1353,8 @@ namespace Falcor while (pinIndex < renderPassUI.mReflection.getFieldCount()) { bool isInput = is_set(renderPassUI.mReflection.getField(pinIndex)->getVisibility(),RenderPassReflection::Field::Visibility::Input); - if (isInput) - { + if (isInput) + { if (renderPassUI.mReflection.getField(pinIndex)->getName() == currentEdge.dstField) { break; } inputPinIndex++; } @@ -1364,7 +1364,7 @@ namespace Falcor auto pSourceNode = mpRenderGraph->mNodeData.find( mpRenderGraph->mpGraph->getEdge(edgeID)->getSourceNode()); assert(pSourceNode != mpRenderGraph->mNodeData.end()); addedExecutionInput = currentEdge.dstField.empty(); - + std::string dstFieldName = currentEdge.dstField.empty() ? kInPrefix + nameToIndex.first : currentEdge.dstField; std::string inputPinString = nameToIndex.first + "." + dstFieldName; std::string srcFieldName = currentEdge.srcField.empty() ? kOutPrefix + pSourceNode->second.name : currentEdge.srcField; @@ -1405,11 +1405,11 @@ namespace Falcor } pinIndex++; } - + auto pDestNode = mpRenderGraph->mNodeData.find(mpRenderGraph->mpGraph->getEdge(edgeID)->getDestNode()); assert(pDestNode != mpRenderGraph->mNodeData.end()); addedExecutionOutput = currentEdge.dstField.empty(); - + std::string dstFieldName = currentEdge.dstField.empty() ? kInPrefix + pDestNode->second.name : currentEdge.dstField; std::string inputPinString = nameToIndex.first + "." + dstFieldName; std::string srcFieldName = currentEdge.srcField.empty() ? kOutPrefix + nameToIndex.first : currentEdge.srcField; @@ -1436,7 +1436,7 @@ namespace Falcor inputPinIndex++; } - + if (is_set(currentField.getVisibility(), RenderPassReflection::Field::Visibility::Output)) { if (nodeConnectedOutput.find(nameToIndex.first + "." + currentField.getName()) == nodeConnectedOutput.end()) @@ -1448,7 +1448,7 @@ namespace Falcor outputPinIndex++; } } - + // unconnected nodes will be renamed when they are connected if (!addedExecutionInput) renderPassUI.addUIPin(kInPrefix + nameToIndex.first, static_cast( renderPassUI.mInputPins.size()), true, "", "", false); if (!addedExecutionOutput) renderPassUI.addUIPin(kOutPrefix + nameToIndex.first, static_cast(renderPassUI.mOutputPins.size()), false, "", "", false); diff --git a/Source/Falcor/RenderGraph/RenderGraphUI.h b/Source/Falcor/RenderGraph/RenderGraphUI.h index ff4dbb48a..5fe75bb77 100644 --- a/Source/Falcor/RenderGraph/RenderGraphUI.h +++ b/Source/Falcor/RenderGraph/RenderGraphUI.h @@ -39,7 +39,7 @@ namespace Falcor public: // wrapper around inserting new pin for a given pass - void addUIPin(const std::string& fieldName, uint32_t guiPinID, bool isInput, const std::string& connectedPinName = "", const std::string& connectedNodeName = "", bool isGraphOutput = false); + void addUIPin(const std::string& fieldName, uint32_t guiPinID, bool isInput, const std::string& connectedPinName = "", const std::string& connectedNodeName = "", bool isGraphOutput = false); void renderPinUI(const std::string& passName, RenderGraphUI* pGraphUI, uint32_t index = 0, bool input = false); friend class RenderGraphUI; @@ -91,7 +91,7 @@ namespace Falcor */ void setToRebuild() { mRebuildDisplayData = true; } - /** Writes out all the changes made to the graph + /** Writes out all the changes made to the graph */ void writeUpdateScriptToFile(RenderContext* pContext, const std::string& filePath, float lastFrameTimes); @@ -155,14 +155,14 @@ namespace Falcor /** Updates structure for drawing the GUI graph */ void updateDisplayData(RenderContext* pContext); - + /** Updates information about pin connections and graph output. */ void updatePins(bool addLinks = true); /** Helper function to calculate position of the next node in execution order */ - glm::vec2 getNextNodePosition(uint32_t nodeID); + float2 getNextNodePosition(uint32_t nodeID); /** Renders specialized pop up menu. */ @@ -181,7 +181,7 @@ namespace Falcor RenderGraphIR::SharedPtr mpIr; - glm::vec2 mNewNodeStartPosition{ -40.0f, 100.0f }; + float2 mNewNodeStartPosition{ -40.0f, 100.0f }; float mMaxNodePositionX = 0.0f; std::unordered_set mAllNodeTypeStrings; diff --git a/Source/Falcor/RenderGraph/RenderPass.cpp b/Source/Falcor/RenderGraph/RenderPass.cpp index ea2e09b55..28ba7e080 100644 --- a/Source/Falcor/RenderGraph/RenderPass.cpp +++ b/Source/Falcor/RenderGraph/RenderPass.cpp @@ -30,7 +30,7 @@ namespace Falcor { - RenderData::RenderData(const std::string& passName, const ResourceCache::SharedPtr& pResourceCache, const Dictionary::SharedPtr& pDict, const uvec2& defaultTexDims, ResourceFormat defaultTexFormat) + RenderData::RenderData(const std::string& passName, const ResourceCache::SharedPtr& pResourceCache, const Dictionary::SharedPtr& pDict, const uint2& defaultTexDims, ResourceFormat defaultTexFormat) : mName(passName) , mpResources(pResourceCache) , mpDictionary(pDict) diff --git a/Source/Falcor/RenderGraph/RenderPass.h b/Source/Falcor/RenderGraph/RenderPass.h index 359f45c54..8be844d9b 100644 --- a/Source/Falcor/RenderGraph/RenderPass.h +++ b/Source/Falcor/RenderGraph/RenderPass.h @@ -60,18 +60,18 @@ namespace Falcor /** Get the default dimensions used for Texture2Ds (when `0` is specified as the dimensions in `RenderPassReflection`) */ - const uvec2& getDefaultTextureDims() const { return mDefaultTexDims; } + const uint2& getDefaultTextureDims() const { return mDefaultTexDims; } /** Get the default format used for Texture2Ds (when `Unknown` is specified as the format in `RenderPassReflection`) */ ResourceFormat getDefaultTextureFormat() const { return mDefaultTexFormat; } protected: friend class RenderGraphExe; - RenderData(const std::string& passName, const ResourceCache::SharedPtr& pResourceCache, const Dictionary::SharedPtr& pDict, const uvec2& defaultTexDims, ResourceFormat defaultTexFormat); + RenderData(const std::string& passName, const ResourceCache::SharedPtr& pResourceCache, const Dictionary::SharedPtr& pDict, const uint2& defaultTexDims, ResourceFormat defaultTexFormat); const std::string& mName; ResourceCache::SharedPtr mpResources; Dictionary::SharedPtr mpDictionary; - uvec2 mDefaultTexDims; + uint2 mDefaultTexDims; ResourceFormat mDefaultTexFormat; }; @@ -95,7 +95,7 @@ namespace Falcor struct CompileData { RenderPassReflection connectedResources; - uvec2 defaultTexDims; + uint2 defaultTexDims; ResourceFormat defaultTexFormat; }; diff --git a/Source/Falcor/RenderGraph/ResourceCache.cpp b/Source/Falcor/RenderGraph/ResourceCache.cpp index e6145186c..198dd51c7 100644 --- a/Source/Falcor/RenderGraph/ResourceCache.cpp +++ b/Source/Falcor/RenderGraph/ResourceCache.cpp @@ -82,8 +82,8 @@ namespace Falcor void mergeTimePoint(std::pair& range, uint32_t newTime) { - range.first = min(range.first, newTime); - range.second = max(range.second, newTime); + range.first = std::min(range.first, newTime); + range.second = std::max(range.second, newTime); } void ResourceCache::registerField(const std::string& name, const RenderPassReflection::Field& field, uint32_t timePoint, const std::string& alias) diff --git a/Source/Falcor/RenderGraph/ResourceCache.h b/Source/Falcor/RenderGraph/ResourceCache.h index 964bcbccf..c9f2d713c 100644 --- a/Source/Falcor/RenderGraph/ResourceCache.h +++ b/Source/Falcor/RenderGraph/ResourceCache.h @@ -30,7 +30,7 @@ #include "Core/API/Resource.h" namespace Falcor -{ +{ class dlldecl ResourceCache : public std::enable_shared_from_this { public: @@ -41,11 +41,11 @@ namespace Falcor */ static SharedPtr create(); - /** Properties to use during resource creation when its property has not been fully specified. + /** Properties to use during resource creation when its property has not been fully specified. */ struct DefaultProperties { - uvec2 dims; ///< Width, height of the swap chain + uint2 dims; ///< Width, height of the swap chain ResourceFormat format = ResourceFormat::Unknown; ///< Format to use for texture creation }; @@ -54,7 +54,7 @@ namespace Falcor \param[in] pResource The resource to register. If this is null, will unregister the resource */ void registerExternalResource(const std::string& name, const Resource::SharedPtr& pResource); - + /** Register a field that requires resources to be allocated. \param[in] name String in the format of PassName.FieldName \param[in] field Reflection data for the field @@ -72,7 +72,7 @@ namespace Falcor */ const RenderPassReflection::Field& getResourceReflection(const std::string& name) const; - /** Allocate all resources that need to be created/updated. + /** Allocate all resources that need to be created/updated. This includes new resources, resources whose properties have been updated since last allocation call. */ void allocateResources(const DefaultProperties& params); @@ -92,7 +92,7 @@ namespace Falcor bool resolveBindFlags; // Whether or not we should resolve the field's bind-flags before creating the resource std::string name; // Full name of the resource, including the pass name }; - + // Resources and properties for fields within (and therefore owned by) a render graph std::unordered_map mNameToIndex; std::vector mResourceData; diff --git a/Source/Falcor/RenderPasses/Shared/PathTracer/LoadShadingData.slang b/Source/Falcor/RenderPasses/Shared/PathTracer/LoadShadingData.slang index 5dbadffb5..78ef6ab7f 100644 --- a/Source/Falcor/RenderPasses/Shared/PathTracer/LoadShadingData.slang +++ b/Source/Falcor/RenderPasses/Shared/PathTracer/LoadShadingData.slang @@ -36,8 +36,8 @@ import Scene.Scene; import Scene.ShadingData; +import Scene.HitInfo; import Utils.Math.MathHelpers; -import RenderPasses.Shared.HitInfo; #if USE_VBUFFER @@ -101,16 +101,13 @@ bool loadShadingData(uint2 pixel, uint2 frameDim, const Camera camera, out Shadi if (hit.decode(gVBuffer[pixel])) { // Evaluate Falcor's material parameters at the hit point. - // Note we pass hitPos-rayDir as "camera position" to avoid zero-length rays causing NaNs - // in the view direction. It'd been cleaner if prepareShadingData() took ray dir directly. // TODO: Implement texLOD to enable texture filtering in prepareShadingData(). - float3 barycentrics = float3(1.f - hit.barycentrics.x - hit.barycentrics.y, hit.barycentrics.x, hit.barycentrics.y); - VertexData v = gScene.getVertexData(hit.meshInstanceID, hit.primitiveIndex, barycentrics); + VertexData v = gScene.getVertexData(hit); const uint materialID = gScene.getMaterialID(hit.meshInstanceID); sd = prepareShadingData(v, materialID, gScene.materials[materialID], gScene.materialResources[materialID], -rayDir, 0.f); // Compute tangent space if it is invalid. - // This is a workaround for assets having incorrect tangent spaces. See issue #25 + // This is a workaround for assets having incorrect tangent spaces. See Art issue #25 if (!(dot(sd.B, sd.B) > 0.f)) // Note: Comparison written so that NaNs trigger { sd.B = perp_stark(sd.N); diff --git a/Source/Falcor/RenderPasses/Shared/PathTracer/PathData.slang b/Source/Falcor/RenderPasses/Shared/PathTracer/PathData.slang index 744f8beb0..dd16b83e5 100644 --- a/Source/Falcor/RenderPasses/Shared/PathTracer/PathData.slang +++ b/Source/Falcor/RenderPasses/Shared/PathTracer/PathData.slang @@ -25,8 +25,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ +__exported import Scene.HitInfo; __exported import Utils.Sampling.SampleGenerator; -__exported import RenderPasses.Shared.HitInfo; __exported import RenderPasses.Shared.PathTracer.StaticParams; __exported import RenderPasses.Shared.PathTracer.InteriorList; @@ -88,6 +88,7 @@ struct PathData bool hasScatterRay() { return (flags & uint(PathFlags::scatterRay)) != 0; } bool hasShadowRay(uint i) { return (flags & (uint(PathFlags::shadowRay) << i)) != 0; } bool hasRays() { return (flags & uint(PathFlags::anyRays)) != 0; } + bool isShadowRayOccluded(uint i) { return (flags & ((uint)PathFlags::shadowRay << i)) == 0; } [mutating] void clearTransmission() { flags &= ~(uint(PathFlags::transmission)); } [mutating] void clearScatterRay() { flags &= ~(uint(PathFlags::scatterRay) | uint(PathFlags::scatterHit)); } diff --git a/Source/Falcor/RenderPasses/Shared/PathTracer/PathTracer.cpp b/Source/Falcor/RenderPasses/Shared/PathTracer/PathTracer.cpp index ef5c6189c..2006f73cf 100644 --- a/Source/Falcor/RenderPasses/Shared/PathTracer/PathTracer.cpp +++ b/Source/Falcor/RenderPasses/Shared/PathTracer/PathTracer.cpp @@ -359,14 +359,12 @@ namespace Falcor if (mpScene == nullptr) return true; // Load environment map if scene uses one. - // We're getting the file name from the scene's LightProbe because that was used in the fscene files. - // TODO: Switch to use Scene::getEnvironmentMap() when the assets have been updated. - auto pLightProbe = mpScene->getLightProbe(); - if (pLightProbe != nullptr) + Texture::SharedPtr pEnvMap = mpScene->getEnvironmentMap(); + if (pEnvMap != nullptr) { - std::string fn = pLightProbe->getOrigTexture()->getSourceFilename(); - mpEnvProbe = EnvProbe::create(pRenderContext, fn); - mEnvProbeFilename = mpEnvProbe ? getFilenameFromPath(mpEnvProbe->getEnvMap()->getSourceFilename()) : ""; + std::string filename = pEnvMap->getSourceFilename(); + mpEnvProbe = EnvProbe::create(pRenderContext, filename); + mEnvProbeFilename = mpEnvProbe ? getFilenameFromPath(filename) : ""; } // Setup for analytic lights. @@ -553,7 +551,7 @@ namespace Falcor Texture* pSrcRayCount = mpPixelStats->getRayCountBuffer().get(); if (pSrcRayCount == nullptr) { - pRenderContext->clearUAV(pDstRayCount->getUAV().get(), uvec4(0, 0, 0, 0)); + pRenderContext->clearUAV(pDstRayCount->getUAV().get(), uint4(0, 0, 0, 0)); } else { diff --git a/Source/Falcor/RenderPasses/Shared/PathTracer/PathTracer.h b/Source/Falcor/RenderPasses/Shared/PathTracer/PathTracer.h index 6d2e63c99..e7966f3da 100644 --- a/Source/Falcor/RenderPasses/Shared/PathTracer/PathTracer.h +++ b/Source/Falcor/RenderPasses/Shared/PathTracer/PathTracer.h @@ -68,7 +68,8 @@ namespace Falcor bool renderSamplingUI(Gui::Widgets& widget); bool renderLightsUI(Gui::Widgets& widget); void renderLoggingUI(Gui::Widgets& widget); - void setStaticParams(Program* pProgram) const; + + virtual void setStaticParams(Program* pProgram) const; // Internal state Scene::SharedPtr mpScene; ///< Current scene. diff --git a/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.cpp b/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.cpp index 559ba6262..4f06bc59a 100644 --- a/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.cpp +++ b/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.cpp @@ -37,7 +37,7 @@ namespace Falcor return SharedPtr(new PixelStats()); } - void PixelStats::beginFrame(RenderContext* pRenderContext, const glm::uvec2& frameDim) + void PixelStats::beginFrame(RenderContext* pRenderContext, const uint2& frameDim) { // Prepare state. assert(!mRunning); @@ -67,8 +67,8 @@ namespace Falcor } assert(mpStatsRayCount && mpStatsPathLength); - pRenderContext->clearUAV(mpStatsRayCount->getUAV().get(), uvec4(0, 0, 0, 0)); - pRenderContext->clearUAV(mpStatsPathLength->getUAV().get(), uvec4(0, 0, 0, 0)); + pRenderContext->clearUAV(mpStatsRayCount->getUAV().get(), uint4(0, 0, 0, 0)); + pRenderContext->clearUAV(mpStatsPathLength->getUAV().get(), uint4(0, 0, 0, 0)); } } @@ -99,13 +99,16 @@ namespace Falcor { assert(mRunning); - pProgram->addDefine("_PIXEL_STATS_ENABLED", mStatsEnabled ? "1" : "0"); - if (mStatsEnabled) { + pProgram->addDefine("_PIXEL_STATS_ENABLED"); var["gStatsRayCount"] = mpStatsRayCount; var["gStatsPathLength"] = mpStatsPathLength; } + else + { + pProgram->removeDefine("_PIXEL_STATS_ENABLED"); + } } void PixelStats::renderUI(Gui::Widgets& widget) diff --git a/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.h b/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.h index 4d7d0877a..959e302a3 100644 --- a/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.h +++ b/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.h @@ -53,7 +53,7 @@ namespace Falcor static SharedPtr create(); - void beginFrame(RenderContext* pRenderContext, const glm::uvec2& frameDim); + void beginFrame(RenderContext* pRenderContext, const uint2& frameDim); void endFrame(RenderContext* pRenderContext); void prepareProgram(const Program::SharedPtr& pProgram, const ShaderVar& var); @@ -86,7 +86,7 @@ namespace Falcor // Runtime data bool mRunning = false; ///< True inbetween begin() / end() calls. bool mWaitingForData = false; ///< True if we are waiting for data to become available on the GPU. - glm::uvec2 mFrameDim = { 0, 0 }; ///< Frame dimensions at last call to begin(). + uint2 mFrameDim = { 0, 0 }; ///< Frame dimensions at last call to begin(). bool mStatsValid = false; ///< True if stats have been read back and are valid. Stats mStats; ///< Traversal stats. diff --git a/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.slang b/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.slang index e04c5b781..7d9df79f4 100644 --- a/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.slang +++ b/Source/Falcor/RenderPasses/Shared/PathTracer/PixelStats.slang @@ -37,27 +37,27 @@ RWTexture2D gStatsRayCount; // Per-pixel ray count stats. RWTexture2D gStatsPathLength; // Per-pixel path length. -#if _PIXEL_STATS_ENABLED +#ifdef _PIXEL_STATS_ENABLED static uint2 gPixelStatsPixel; #endif void logSetPixel(uint2 pixel) { -#if _PIXEL_STATS_ENABLED +#ifdef _PIXEL_STATS_ENABLED gPixelStatsPixel = pixel; #endif } void logTraceRay() { -#if _PIXEL_STATS_ENABLED +#ifdef _PIXEL_STATS_ENABLED InterlockedAdd(gStatsRayCount[gPixelStatsPixel], 1); #endif } void logPathLength(uint pathLength) { -#if _PIXEL_STATS_ENABLED +#ifdef _PIXEL_STATS_ENABLED gStatsPathLength[gPixelStatsPixel] = pathLength; #endif } diff --git a/Source/Falcor/Scene/Animation/Animation.cpp b/Source/Falcor/Scene/Animation/Animation.cpp index 9fa1547c6..a9767ab5e 100644 --- a/Source/Falcor/Scene/Animation/Animation.cpp +++ b/Source/Falcor/Scene/Animation/Animation.cpp @@ -51,26 +51,26 @@ namespace Falcor return frameID; } - mat4 Animation::interpolate(const Keyframe& start, const Keyframe& end, double curTime) const + glm::mat4 Animation::interpolate(const Keyframe& start, const Keyframe& end, double curTime) const { double localTime = curTime - start.time; double keyframeDuration = end.time - start.time; if (keyframeDuration < 0) keyframeDuration += mDurationInSeconds; float factor = keyframeDuration != 0 ? (float)(localTime / keyframeDuration) : 1; - vec3 translation = lerp(start.translation, end.translation, factor); - vec3 scaling = lerp(start.scaling, end.scaling, factor); - quat rotation = slerp(start.rotation, end.rotation, factor); + float3 translation = lerp(start.translation, end.translation, factor); + float3 scaling = lerp(start.scaling, end.scaling, factor); + glm::quat rotation = slerp(start.rotation, end.rotation, factor); - mat4 T; - T[3] = vec4(translation, 1); - mat4 R = mat4_cast(rotation); - mat4 S = scale(scaling); - mat4 transform = T * R * S; + glm::mat4 T; + T[3] = float4(translation, 1); + glm::mat4 R = glm::mat4_cast(rotation); + glm::mat4 S = scale(scaling); + glm::mat4 transform = T * R * S; return transform; } - mat4 Animation::animateChannel(Channel& c, double time) + glm::mat4 Animation::animateChannel(Channel& c, double time) { size_t curKeyIndex = findChannelFrame(c, time); size_t nextKeyIndex = curKeyIndex + 1; @@ -82,7 +82,7 @@ namespace Falcor return interpolate(c.keyframes[curKeyIndex], c.keyframes[nextKeyIndex], time); } - void Animation::animate(double totalTime, std::vector& matrices) + void Animation::animate(double totalTime, std::vector& matrices) { // Calculate the relative time double modTime = fmod(totalTime, mDurationInSeconds); diff --git a/Source/Falcor/Scene/Animation/Animation.h b/Source/Falcor/Scene/Animation/Animation.h index 0ecbcf419..7d6df98aa 100644 --- a/Source/Falcor/Scene/Animation/Animation.h +++ b/Source/Falcor/Scene/Animation/Animation.h @@ -41,9 +41,9 @@ namespace Falcor struct Keyframe { double time = 0; - vec3 translation = vec3(0, 0, 0); - vec3 scaling = vec3(1, 1, 1); - quat rotation = quat(1, 0, 0, 0); + float3 translation = float3(0, 0, 0); + float3 scaling = float3(1, 1, 1); + glm::quat rotation = glm::quat(1, 0, 0, 0); }; /** Create a new object @@ -80,11 +80,12 @@ namespace Falcor \param currentTime The current time in seconds. This can be larger then the animation time, in which case the animation will loop \param matrices The array of global matrices to update */ - void animate(double currentTime, std::vector& matrices); + void animate(double currentTime, std::vector& matrices); /** Get the matrixID affected by a channel */ size_t getChannelMatrixID(size_t channel) const { return mChannels[channel].matrixID; } + private: Animation(const std::string& name, double durationInSeconds); @@ -101,8 +102,8 @@ namespace Falcor const std::string mName; double mDurationInSeconds = 0; - mat4 animateChannel(Channel& c, double time); + glm::mat4 animateChannel(Channel& c, double time); size_t findChannelFrame(const Channel& c, double time) const; - mat4 interpolate(const Keyframe& start, const Keyframe& end, double curTime) const; + glm::mat4 interpolate(const Keyframe& start, const Keyframe& end, double curTime) const; }; } diff --git a/Source/Falcor/Scene/Animation/AnimationController.cpp b/Source/Falcor/Scene/Animation/AnimationController.cpp index 6e2154cc2..d3856fb4d 100644 --- a/Source/Falcor/Scene/Animation/AnimationController.cpp +++ b/Source/Falcor/Scene/Animation/AnimationController.cpp @@ -44,9 +44,9 @@ namespace Falcor assert(mLocalMatrices.size() * 4 <= UINT32_MAX); uint32_t float4Count = (uint32_t)mLocalMatrices.size() * 4; - mpWorldMatricesBuffer = Buffer::createTyped(ResourceFormat::RGBA32Float, float4Count, Resource::BindFlags::ShaderResource); + mpWorldMatricesBuffer = Buffer::createStructured(sizeof(float4), float4Count, Resource::BindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); mpPrevWorldMatricesBuffer = mpWorldMatricesBuffer; - mpInvTransposeWorldMatricesBuffer = Buffer::createTyped(ResourceFormat::RGBA32Float, float4Count, Resource::BindFlags::ShaderResource); + mpInvTransposeWorldMatricesBuffer = Buffer::createStructured(sizeof(float4), float4Count, Resource::BindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); createSkinningPass(staticVertexData, dynamicVertexData); } @@ -215,21 +215,31 @@ namespace Falcor { if (mActiveAnimationCount) { - if(mpWorldMatricesBuffer == mpPrevWorldMatricesBuffer) + if (mpWorldMatricesBuffer == mpPrevWorldMatricesBuffer) { - mpPrevWorldMatricesBuffer = Buffer::createTyped(ResourceFormat::RGBA32Float, mpWorldMatricesBuffer->getElementCount(), ResourceBindFlags::ShaderResource); + mpPrevWorldMatricesBuffer = Buffer::createStructured(sizeof(float4), mpWorldMatricesBuffer->getElementCount(), Resource::BindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); } } else mpPrevWorldMatricesBuffer = mpWorldMatricesBuffer; } - void AnimationController::createSkinningPass(const std::vector& staticVertexData, const std::vector& dynamicVertexData) + void AnimationController::createSkinningPass(const std::vector& staticVertexData, const std::vector& dynamicVertexData) { + // We always copy the static data, to initialize the non-skinned vertices Buffer::ConstSharedPtrRef pVB = mpScene->mpVao->getVertexBuffer(Scene::kStaticDataBufferIndex); assert(pVB->getSize() == staticVertexData.size() * sizeof(staticVertexData[0])); - // We always copy the static data, to initialize the non-skinned vertices pVB->setBlob(staticVertexData.data(), 0, pVB->getSize()); + // Initialize the previous positions for non-skinned vertices. + std::vector prevVertexData(staticVertexData.size()); + for (size_t i = 0; i < staticVertexData.size(); i++) + { + prevVertexData[i].position = staticVertexData[i].position; + } + Buffer::ConstSharedPtrRef pPrevVB = mpScene->mpVao->getVertexBuffer(Scene::kPrevVertexBufferIndex); + assert(pPrevVB->getSize() == prevVertexData.size() * sizeof(prevVertexData[0])); + pPrevVB->setBlob(prevVertexData.data(), 0, pPrevVB->getSize()); + if (dynamicVertexData.size()) { mSkinningMatrices.resize(mpScene->mSceneGraph.size()); @@ -238,10 +248,11 @@ namespace Falcor mpSkinningPass = ComputePass::create("Scene/Animation/Skinning.slang"); auto block = mpSkinningPass->getVars()["gData"]; block["skinnedVertices"] = pVB; + block["prevSkinnedVertices"] = pPrevVB; auto createBuffer = [&](const std::string& name, const auto& initData) { - auto pBuffer = Buffer::createStructured(block[name], (uint32_t)initData.size(), ResourceBindFlags::ShaderResource); + auto pBuffer = Buffer::createStructured(block[name], (uint32_t)initData.size(), ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); pBuffer->setBlob(initData.data(), 0, pBuffer->getSize()); block[name] = pBuffer; }; @@ -251,13 +262,13 @@ namespace Falcor assert(mSkinningMatrices.size() * 4 < UINT32_MAX); uint32_t float4Count = (uint32_t)mSkinningMatrices.size() * 4; - mpSkinningMatricesBuffer = Buffer::createTyped(ResourceFormat::RGBA32Float, float4Count, ResourceBindFlags::ShaderResource); - mpInvTransposeSkinningMatricesBuffer = Buffer::createTyped(ResourceFormat::RGBA32Float, float4Count, ResourceBindFlags::ShaderResource); + mpSkinningMatricesBuffer = Buffer::createStructured(sizeof(float4), float4Count, ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); + mpInvTransposeSkinningMatricesBuffer = Buffer::createStructured(sizeof(float4), float4Count, ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); block["boneMatrices"].setBuffer(mpSkinningMatricesBuffer); block["inverseTransposeBoneMatrices"].setBuffer(mpInvTransposeSkinningMatricesBuffer); block["inverseTransposeWorldMatrices"].setBuffer(mpInvTransposeWorldMatricesBuffer); block["worldMatrices"].setBuffer(mpWorldMatricesBuffer); - + mSkinningDispatchSize = (uint32_t)dynamicVertexData.size(); } } diff --git a/Source/Falcor/Scene/Animation/AnimationController.h b/Source/Falcor/Scene/Animation/AnimationController.h index 454e4c469..97952e8a9 100644 --- a/Source/Falcor/Scene/Animation/AnimationController.h +++ b/Source/Falcor/Scene/Animation/AnimationController.h @@ -57,7 +57,7 @@ namespace Falcor static const uint32_t kInvalidBoneID = -1; ~AnimationController() = default; - using StaticVertexVector = std::vector; + using StaticVertexVector = std::vector; using DynamicVertexVector = std::vector; /** Create a new object @@ -92,8 +92,8 @@ namespace Falcor */ bool setActiveAnimation(uint32_t meshID, uint32_t animID); - /** Get a mesh's active animation - If no animations exist for the mesh, will return kBindPoseAnimationId + /** Get a mesh's active animation. + \return Active animation ID, or kBindPoseAnimationId if no animations exist for the mesh. */ uint32_t getActiveAnimation(uint32_t meshID) const; @@ -107,11 +107,12 @@ namespace Falcor /** Get the global matrices */ - const std::vector& getGlobalMatrices() const { return mGlobalMatrices; } + const std::vector& getGlobalMatrices() const { return mGlobalMatrices; } /** Check if a matrix changed */ bool didMatrixChanged(size_t matrixID) const { return mMatricesChanged[matrixID]; } + private: friend class SceneBuilder; AnimationController(Scene* pScene, const StaticVertexVector& staticVertexData, const DynamicVertexVector& dynamicVertexData); @@ -128,9 +129,9 @@ namespace Falcor }; std::map mMeshes; - std::vector mLocalMatrices; - std::vector mGlobalMatrices; - std::vector mInvTransposeGlobalMatrices; + std::vector mLocalMatrices; + std::vector mGlobalMatrices; + std::vector mInvTransposeGlobalMatrices; std::vector mMatricesChanged; bool mHasAnimations = false; @@ -145,10 +146,10 @@ namespace Falcor // Skinning ComputePass::SharedPtr mpSkinningPass; - std::vector mSkinningMatrices; - std::vector mInvTransposeSkinningMatrices; + std::vector mSkinningMatrices; + std::vector mInvTransposeSkinningMatrices; uint32_t mSkinningDispatchSize = 0; - void createSkinningPass(const std::vector& staticVertexData, const std::vector& dynamicVertexData); + void createSkinningPass(const std::vector& staticVertexData, const std::vector& dynamicVertexData); void executeSkinningPass(RenderContext* pContext); Buffer::SharedPtr mpSkinningMatricesBuffer; diff --git a/Source/Falcor/Scene/Animation/Skinning.slang b/Source/Falcor/Scene/Animation/Skinning.slang index 5d9b0e358..4a0813a38 100644 --- a/Source/Falcor/Scene/Animation/Skinning.slang +++ b/Source/Falcor/Scene/Animation/Skinning.slang @@ -29,13 +29,14 @@ import Scene.SceneTypes; struct SkinningData { - StructuredBuffer staticData; + StructuredBuffer staticData; StructuredBuffer dynamicData; - RWStructuredBuffer skinnedVertices; - Buffer boneMatrices; - Buffer inverseTransposeBoneMatrices; - Buffer worldMatrices; - Buffer inverseTransposeWorldMatrices; + RWStructuredBuffer skinnedVertices; + RWStructuredBuffer prevSkinnedVertices; + StructuredBuffer boneMatrices; + StructuredBuffer inverseTransposeBoneMatrices; + StructuredBuffer worldMatrices; + StructuredBuffer inverseTransposeWorldMatrices; float4x4 getTransposeWorldMatrix(uint matrixID) { @@ -106,12 +107,13 @@ struct SkinningData StaticVertexData getStaticVertexData(uint vertexId) { - return staticData[getStaticVertexID(vertexId)]; + return staticData[getStaticVertexID(vertexId)].unpack(); } - void storeStaticData(uint vertexId, StaticVertexData data) + void storeSkinnedVertexData(uint vertexId, StaticVertexData data, PrevVertexData prevData) { - gData.skinnedVertices[getStaticVertexID(vertexId)] = data; + gData.skinnedVertices[getStaticVertexID(vertexId)].pack(data); + gData.prevSkinnedVertices[getStaticVertexID(vertexId)] = prevData; } float3 getCurrentPosition(uint vertexId) @@ -131,16 +133,19 @@ void main(uint3 dispatchThreadID : SV_DispatchThreadID) gData.dynamicData.GetDimensions(vertexCount, stride); if (vertexId >= vertexCount) return; + // Copy the previous skinned data + PrevVertexData prev; + prev.position = gData.getCurrentPosition(vertexId); + // Blend the vertices StaticVertexData s = gData.getStaticVertexData(vertexId); float4x4 boneMat = gData.getBlendedMatrix(vertexId); float4x4 invTransposeMat = gData.getInverseTransposeBlendedMatrix(vertexId); - s.prevPosition = gData.getCurrentPosition(vertexId); s.position = mul(float4(s.position, 1.f), boneMat).xyz; s.bitangent = mul(s.bitangent, (float3x3) boneMat); s.normal = mul(s.normal, (float3x3) transpose(invTransposeMat)); // Store the result - gData.storeStaticData(vertexId, s); + gData.storeSkinnedVertexData(vertexId, s, prev); } diff --git a/Source/Falcor/Scene/Camera/Camera.cpp b/Source/Falcor/Scene/Camera/Camera.cpp index 564d95be9..d5fb6c551 100644 --- a/Source/Falcor/Scene/Camera/Camera.cpp +++ b/Source/Falcor/Scene/Camera/Camera.cpp @@ -34,7 +34,7 @@ namespace Falcor { - static_assert(sizeof(CameraData) % (sizeof(vec4)) == 0, "CameraData size should be a multiple of 16"); + static_assert(sizeof(CameraData) % (sizeof(float4)) == 0, "CameraData size should be a multiple of 16"); // Default dimensions of full frame cameras and 35mm film const float Camera::kDefaultFrameHeight = 24.0f; @@ -55,7 +55,7 @@ namespace Falcor { if (mJitterPattern.pGenerator) { - vec2 jitter = mJitterPattern.pGenerator->next(); + float2 jitter = mJitterPattern.pGenerator->next(); jitter *= mJitterPattern.scale; setJitterInternal(jitter.x, jitter.y); } @@ -147,13 +147,13 @@ namespace Falcor glm::mat4 tempMat = glm::transpose(mData.viewProjMat); for (int i = 0; i < 6; i++) { - glm::vec4 plane = (i & 1) ? tempMat[i >> 1] : -tempMat[i >> 1]; + float4 plane = (i & 1) ? tempMat[i >> 1] : -tempMat[i >> 1]; if(i != 5) // Z range is [0, w]. For the 0 <= z plane we don't need to add w { plane += tempMat[3]; } - mFrustumPlanes[i].xyz = glm::vec3(plane); + mFrustumPlanes[i].xyz = float3(plane); mFrustumPlanes[i].sign = glm::sign(mFrustumPlanes[i].xyz); mFrustumPlanes[i].negW = -plane.w; } @@ -228,7 +228,7 @@ namespace Falcor // See method 4b: https://fgiesen.wordpress.com/2010/10/17/view-frustum-culling/ for (int plane = 0; plane < 6; plane++) { - glm::vec3 signedExtent = box.extent * mFrustumPlanes[plane].sign; + float3 signedExtent = box.extent * mFrustumPlanes[plane].sign; float dr = glm::dot(box.center + signedExtent, mFrustumPlanes[plane].xyz); isInside = isInside && (dr > mFrustumPlanes[plane].negW); } @@ -242,7 +242,7 @@ namespace Falcor var["data"].setBlob(mData); } - void Camera::setPatternGenerator(const CPUSampleGenerator::SharedPtr& pGenerator, const vec2& scale) + void Camera::setPatternGenerator(const CPUSampleGenerator::SharedPtr& pGenerator, const float2& scale) { mJitterPattern.pGenerator = pGenerator; mJitterPattern.scale = scale; @@ -269,6 +269,13 @@ namespace Falcor mDirty = true; } + float Camera::computeScreenSpacePixelSpreadAngle(const uint32_t winHeightPixels) const + { + const float FOVrad = focalLengthToFovY(getFocalLength(), Camera::kDefaultFrameHeight); + const float angle = atanf(2.0f * tanf(FOVrad * 0.5f) / winHeightPixels); + return angle; + } + void Camera::renderUI(Gui* pGui, const char* uiGroup) { if (!uiGroup) uiGroup = "Camera Settings"; @@ -294,7 +301,7 @@ namespace Falcor float ISOSpeed = getISOSpeed(); if (g.var("ISO Speed", ISOSpeed, 0.8f, FLT_MAX, 0.25f)) setISOSpeed(ISOSpeed); - float2 depth = glm::vec2(mData.nearZ, mData.farZ); + float2 depth = float2(mData.nearZ, mData.farZ); if (g.var("Depth Range", depth, 0.f, FLT_MAX, 0.1f)) setDepthRange(depth.x, depth.y); float3 pos = getPosition(); diff --git a/Source/Falcor/Scene/Camera/Camera.h b/Source/Falcor/Scene/Camera/Camera.h index dd9fc4448..b5713a28c 100644 --- a/Source/Falcor/Scene/Camera/Camera.h +++ b/Source/Falcor/Scene/Camera/Camera.h @@ -119,27 +119,27 @@ namespace Falcor /** Get the camera's world space position. */ - const glm::vec3& getPosition() const { return mData.posW; } + const float3& getPosition() const { return mData.posW; } /** Get the camera's world space up vector. */ - const glm::vec3& getUpVector() const {return mData.up;} + const float3& getUpVector() const {return mData.up;} /** Get the camera's world space target position. */ - const glm::vec3& getTarget() const { return mData.target; } + const float3& getTarget() const { return mData.target; } /** Set the camera's world space position. */ - void setPosition(const glm::vec3& posW) { mData.posW = posW; mDirty = true; } + void setPosition(const float3& posW) { mData.posW = posW; mDirty = true; } /** Set the camera's world space up vector. */ - void setUpVector(const glm::vec3& up) { mData.up = up; mDirty = true; } + void setUpVector(const float3& up) { mData.up = up; mDirty = true; } /** Set the camera's world space target position. */ - void setTarget(const glm::vec3& target) { mData.target = target; mDirty = true; } + void setTarget(const float3& target) { mData.target = target; mDirty = true; } /** Set the camera's depth range. */ @@ -163,7 +163,7 @@ namespace Falcor /** Set a pattern generator. If a generator is set, then a jitter will be set every frame based on the generator */ - void setPatternGenerator(const CPUSampleGenerator::SharedPtr& pGenerator, const vec2& scale = vec2(1)); + void setPatternGenerator(const CPUSampleGenerator::SharedPtr& pGenerator, const float2& scale = float2(1)); /** Get the bound pattern generator */ @@ -177,6 +177,12 @@ namespace Falcor float getJitterX() const { return mData.jitterX; } float getJitterY() const { return mData.jitterY; } + /** Compute pixel spread in screen space -- to be used with RayCones for texture level-of-detail. + \param[in] winHeightPixels Window height in pixels + \return the pixel spread angle in screen space + */ + float computeScreenSpacePixelSpreadAngle(const uint32_t winHeightPixels) const; + /** Get the view matrix. */ const glm::mat4& getViewMatrix() const; @@ -271,15 +277,15 @@ namespace Falcor struct { - glm::vec3 xyz; ///< Camera frustum plane position - float negW; ///< Camera frustum plane, sign of the coordinates - glm::vec3 sign; ///< Camera frustum plane position + float3 xyz; ///< Camera frustum plane position + float negW; ///< Camera frustum plane, sign of the coordinates + float3 sign; ///< Camera frustum plane position } mutable mFrustumPlanes[6]; struct { CPUSampleGenerator::SharedPtr pGenerator; - vec2 scale; + float2 scale; } mJitterPattern; void setJitterInternal(float jitterX, float jitterY); diff --git a/Source/Falcor/Scene/Camera/Camera.slang b/Source/Falcor/Scene/Camera/Camera.slang index a966ce9bf..fc2bd3424 100644 --- a/Source/Falcor/Scene/Camera/Camera.slang +++ b/Source/Falcor/Scene/Camera/Camera.slang @@ -58,14 +58,9 @@ struct Camera { CameraRay ray; - // Sample position in screen space in [0,1] with origin at the top-left corner. - // The camera jitter offsets the sample by +-0.5 pixels from the pixel center. - float2 p = (pixel + float2(0.5f, 0.5f)) / frameDim + float2(-data.jitterX, data.jitterY); - float2 ndc = float2(2, -2) * p + float2(-1, 1); - // Compute the normalized ray direction assuming a pinhole camera. ray.origin = data.posW; - ray.dir = normalize(ndc.x * data.cameraU + ndc.y * data.cameraV + data.cameraW); + ray.dir = normalize(computeNonNormalizedRayDirPinhole(pixel, frameDim)); float invCos = 1.f / dot(normalize(data.cameraW), ray.dir); ray.tMin = data.nearZ * invCos; @@ -74,6 +69,24 @@ struct Camera return ray; } + /** Computes the primary ray's direction, non-normalized assuming pinhole camera model. + The camera jitter is taken into account to compute the sample position on the image plane. + \param[in] pixel Pixel coordinates with origin in top-left. + \param[in] frameDim Image plane dimensions in pixels. + \return Returns the non-normalized ray direction + */ + float3 computeNonNormalizedRayDirPinhole(uint2 pixel, uint2 frameDim) + { + // Compute sample position in screen space in [0,1] with origin at the top-left corner. + // The camera jitter offsets the sample by +-0.5 pixels from the pixel center. + float2 p = (pixel + float2(0.5f, 0.5f)) / frameDim + float2(-data.jitterX, data.jitterY); + float2 ndc = float2(2, -2) * p + float2(-1, 1); + + // Compute the non-normalized ray direction assuming a pinhole camera. + return ndc.x * data.cameraU + ndc.y * data.cameraV + data.cameraW; + } + + /** Computes a camera ray for a given pixel assuming a thin-lens camera model. The camera jitter is taken into account to compute the sample position on the image plane. \param[in] pixel Pixel coordinates with origin in top-left. diff --git a/Source/Falcor/Scene/Camera/CameraController.cpp b/Source/Falcor/Scene/Camera/CameraController.cpp index 2c7ced88b..f5976def5 100644 --- a/Source/Falcor/Scene/Camera/CameraController.cpp +++ b/Source/Falcor/Scene/Camera/CameraController.cpp @@ -33,16 +33,16 @@ namespace Falcor { - glm::vec2 convertCamPosRange(const glm::vec2 pos) + float2 convertCamPosRange(const float2 pos) { // Convert [0,1] range to [-1, 1], and inverse the Y (screen-space y==0 is top) - const glm::vec2 scale(2, -2); - const glm::vec2 offset(-1, 1); - glm::vec2 res = (pos * scale) + offset; + const float2 scale(2, -2); + const float2 offset(-1, 1); + float2 res = (pos * scale) + offset; return res; } - void OrbiterCameraController::setModelParams(const glm::vec3& center, float radius, float distanceInRadius) + void OrbiterCameraController::setModelParams(const float3& center, float radius, float distanceInRadius) { mModelCenter = center; mModelRadius = radius; @@ -73,7 +73,7 @@ namespace Falcor case MouseEvent::Type::Move: if(mIsLeftButtonDown) { - glm::vec3 curVec = project2DCrdToUnitSphere(convertCamPosRange(mouseEvent.pos)); + float3 curVec = project2DCrdToUnitSphere(convertCamPosRange(mouseEvent.pos)); glm::quat q = createQuaternionFromVectors(mLastVector, curVec); glm::mat3x3 rot = (glm::mat3x3)q; mRotation = rot * mRotation; @@ -98,11 +98,11 @@ namespace Falcor mShouldRotate = false; mpCamera->setTarget(mModelCenter); - glm::vec3 camPos = mModelCenter; - camPos += (glm::vec3(0,0,1) * mRotation) * mModelRadius * mCameraDistance; + float3 camPos = mModelCenter; + camPos += (float3(0,0,1) * mRotation) * mModelRadius * mCameraDistance; mpCamera->setPosition(camPos); - glm::vec3 up(0, 1, 0); + float3 up(0, 1, 0); up = up * mRotation; mpCamera->setUpVector(up); return true; @@ -173,14 +173,14 @@ namespace Falcor { if(mShouldRotate) { - glm::vec3 camPos = mpCamera->getPosition(); - glm::vec3 camTarget = mpCamera->getTarget(); - glm::vec3 camUp = b6DoF ? mpCamera->getUpVector() : glm::vec3(0, 1, 0);; + float3 camPos = mpCamera->getPosition(); + float3 camTarget = mpCamera->getTarget(); + float3 camUp = b6DoF ? mpCamera->getUpVector() : float3(0, 1, 0);; - glm::vec3 viewDir = glm::normalize(camTarget - camPos); + float3 viewDir = glm::normalize(camTarget - camPos); if(mIsLeftButtonDown) { - glm::vec3 sideway = glm::cross(viewDir, normalize(camUp)); + float3 sideway = glm::cross(viewDir, normalize(camUp)); // Rotate around x-axis glm::quat qy = glm::angleAxis(mMouseDelta.y * mSpeedModifier, sideway); @@ -213,7 +213,7 @@ namespace Falcor if(mMovement.any()) { - glm::vec3 movement(0, 0, 0); + float3 movement(0, 0, 0); movement.z += mMovement.test(Direction::Forward) ? 1 : 0; movement.z += mMovement.test(Direction::Backward) ? -1 : 0; movement.x += mMovement.test(Direction::Left) ? 1 : 0; @@ -221,12 +221,12 @@ namespace Falcor movement.y += mMovement.test(Direction::Up) ? 1 : 0; movement.y += mMovement.test(Direction::Down) ? -1 : 0; - glm::vec3 camPos = mpCamera->getPosition(); - glm::vec3 camTarget = mpCamera->getTarget(); - glm::vec3 camUp = mpCamera->getUpVector(); + float3 camPos = mpCamera->getPosition(); + float3 camTarget = mpCamera->getTarget(); + float3 camUp = mpCamera->getUpVector(); - glm::vec3 viewDir = normalize(camTarget - camPos); - glm::vec3 sideway = glm::cross(viewDir, normalize(camUp)); + float3 viewDir = normalize(camTarget - camPos); + float3 sideway = glm::cross(viewDir, normalize(camUp)); float elapsedTime = (float)mTimer.delta(); diff --git a/Source/Falcor/Scene/Camera/CameraController.h b/Source/Falcor/Scene/Camera/CameraController.h index 9672d5897..b11ff255b 100644 --- a/Source/Falcor/Scene/Camera/CameraController.h +++ b/Source/Falcor/Scene/Camera/CameraController.h @@ -91,7 +91,7 @@ namespace Falcor \param[in] Radius The model's radius. Used to determin the speed of movement when zooming in/out. \param[in] InitialDistanceInRadius The initial distance of the camera from the model, measured in the model's radius. */ - void setModelParams(const glm::vec3& center, float radius, float initialDistanceInRadius); + void setModelParams(const float3& center, float radius, float initialDistanceInRadius); /** Update the camera position and orientation. \return Whether the camera was updated/changed @@ -99,13 +99,13 @@ namespace Falcor bool update() override; private: - glm::vec3 mModelCenter; + float3 mModelCenter; float mModelRadius; float mCameraDistance; bool mbDirty; glm::mat3x3 mRotation; - glm::vec3 mLastVector; + float3 mLastVector; bool mIsLeftButtonDown = false; bool mShouldRotate = false; }; @@ -150,8 +150,8 @@ namespace Falcor bool mIsRightButtonDown = false; bool mShouldRotate = false; - glm::vec2 mLastMousePos; - glm::vec2 mMouseDelta; + float2 mLastMousePos; + float2 mMouseDelta; CpuTimer mTimer; diff --git a/Source/Falcor/RenderPasses/Shared/HitInfo.h b/Source/Falcor/Scene/HitInfo.h similarity index 87% rename from Source/Falcor/RenderPasses/Shared/HitInfo.h rename to Source/Falcor/Scene/HitInfo.h index f8e5704ec..0eb20389c 100644 --- a/Source/Falcor/RenderPasses/Shared/HitInfo.h +++ b/Source/Falcor/Scene/HitInfo.h @@ -37,13 +37,13 @@ namespace Falcor /** Returns defines needed packing/unpacking a HitInfo struct. */ - static Shader::DefineList getDefines(const Scene::SharedPtr& pScene) + static Shader::DefineList getDefines(const Scene* pScene) { // Setup bit allocations for encoding the meshInstanceID and primitive indices. + uint32_t meshInstanceCount = pScene->getMeshInstanceCount(); - assert(meshInstanceCount > 0); - uint32_t maxInstanceID = meshInstanceCount - 1; - uint32_t instanceIndexBits = bitScanReverse(maxInstanceID) + 1; + uint32_t maxInstanceID = meshInstanceCount > 0 ? meshInstanceCount - 1 : 0; + uint32_t instanceIndexBits = maxInstanceID > 0 ? bitScanReverse(maxInstanceID) + 1 : 0; uint32_t maxTriangleCount = 0; for (uint32_t meshID = 0; meshID < pScene->getMeshCount(); meshID++) @@ -51,9 +51,8 @@ namespace Falcor uint32_t triangleCount = pScene->getMesh(meshID).indexCount / 3; maxTriangleCount = std::max(triangleCount, maxTriangleCount); } - assert(maxTriangleCount > 0); - uint32_t maxTriangleID = maxTriangleCount - 1; - uint32_t triangleIndexBits = bitScanReverse(maxTriangleID) + 1; + uint32_t maxTriangleID = maxTriangleCount > 0 ? maxTriangleCount - 1 : 0; + uint32_t triangleIndexBits = maxTriangleID > 0 ? bitScanReverse(maxTriangleID) + 1 : 0; assert(instanceIndexBits > 0 && triangleIndexBits > 0); if (instanceIndexBits + triangleIndexBits > 32 || diff --git a/Source/Falcor/RenderPasses/Shared/HitInfo.slang b/Source/Falcor/Scene/HitInfo.slang similarity index 94% rename from Source/Falcor/RenderPasses/Shared/HitInfo.slang rename to Source/Falcor/Scene/HitInfo.slang index 9a97b0316..e0cfe82af 100644 --- a/Source/Falcor/RenderPasses/Shared/HitInfo.slang +++ b/Source/Falcor/Scene/HitInfo.slang @@ -49,6 +49,13 @@ struct HitInfo uint primitiveIndex; ///< Primitive index at hit. float2 barycentrics; ///< Barycentric coordinates at ray hit, always in [0,1]. + /** Return the barycentric weights. + */ + float3 getBarycentricWeights() + { + return float3(1.f - barycentrics.x - barycentrics.y, barycentrics.x, barycentrics.y); + } + #if defined(HIT_INSTANCE_INDEX_BITS) && defined(HIT_TRIANGLE_INDEX_BITS) #if ((HIT_INSTANCE_INDEX_BITS) + (HIT_TRIANGLE_INDEX_BITS)) > 32 #error HitInfo instance/primitive index bits exceed 32 bits diff --git a/Source/Falcor/Scene/Importers/AssimpImporter.cpp b/Source/Falcor/Scene/Importers/AssimpImporter.cpp index d4f14d0ce..51eaa46a6 100644 --- a/Source/Falcor/Scene/Importers/AssimpImporter.cpp +++ b/Source/Falcor/Scene/Importers/AssimpImporter.cpp @@ -57,9 +57,9 @@ namespace Falcor GLTF2, }; - mat4 aiCast(const aiMatrix4x4& aiMat) + glm::mat4 aiCast(const aiMatrix4x4& aiMat) { - mat4 glmMat; + glm::mat4 glmMat; glmMat[0][0] = aiMat.a1; glmMat[0][1] = aiMat.a2; glmMat[0][2] = aiMat.a3; glmMat[0][3] = aiMat.a4; glmMat[1][0] = aiMat.b1; glmMat[1][1] = aiMat.b2; glmMat[1][2] = aiMat.b3; glmMat[1][3] = aiMat.b4; glmMat[2][0] = aiMat.c1; glmMat[2][1] = aiMat.c2; glmMat[2][2] = aiMat.c3; glmMat[2][3] = aiMat.c4; @@ -68,19 +68,19 @@ namespace Falcor return transpose(glmMat); } - vec3 aiCast(const aiColor3D& ai) + float3 aiCast(const aiColor3D& ai) { - return vec3(ai.r, ai.g, ai.b); + return float3(ai.r, ai.g, ai.b); } - vec3 aiCast(const aiVector3D& val) + float3 aiCast(const aiVector3D& val) { - return vec3(val.x, val.y, val.z); + return float3(val.x, val.y, val.z); } - quat aiCast(const aiQuaternion& q) + glm::quat aiCast(const aiQuaternion& q) { - return quat(q.w, q.x, q.y, q.z); + return glm::quat(q.w, q.x, q.y, q.z); } /** Texture types used in Falcor materials. @@ -187,21 +187,21 @@ namespace Falcor SceneBuilder& builder; std::map materialMap; - std::map meshMap; + std::map meshMap; // Assimp mesh index to Falcor mesh ID std::map textureCache; const SceneBuilder::InstanceMatrices& modelInstances; - std::map localToBindPoseMatrices; + std::map localToBindPoseMatrices; - size_t getFalcorNode(const aiNode* pNode) const + uint32_t getFalcorNodeID(const aiNode* pNode) const { - return mAiToFalcorNode.at(pNode); + return mAiToFalcorNodeID.at(pNode); } - size_t getFalcorNode(const std::string& aiNodeName, uint32_t index) const + uint32_t getFalcorNodeID(const std::string& aiNodeName, uint32_t index) const { try { - return getFalcorNode(mAiNodes.at(aiNodeName)[index]); + return getFalcorNodeID(mAiNodes.at(aiNodeName)[index]); } catch (const std::exception&) { @@ -214,10 +214,10 @@ namespace Falcor return (uint32_t)mAiNodes.at(nodeName).size(); } - void addAiNode(const aiNode* pNode, size_t falcorID) + void addAiNode(const aiNode* pNode, uint32_t falcorNodeID) { - assert(mAiToFalcorNode.find(pNode) == mAiToFalcorNode.end()); - mAiToFalcorNode[pNode] = falcorID; + assert(mAiToFalcorNodeID.find(pNode) == mAiToFalcorNodeID.end()); + mAiToFalcorNodeID[pNode] = falcorNodeID; if (mAiNodes.find(pNode->mName.C_Str()) == mAiNodes.end()) { @@ -227,7 +227,7 @@ namespace Falcor } private: - std::map mAiToFalcorNode; + std::map mAiToFalcorNodeID; std::map> mAiNodes; }; @@ -284,7 +284,7 @@ namespace Falcor std::vector channels; for (uint32_t i = 0; i < data.getNodeInstanceCount(pAiNode->mNodeName.C_Str()); i++) { - channels.push_back(pAnimation->addChannel(data.getFalcorNode(pAiNode->mNodeName.C_Str(), i))); + channels.push_back(pAnimation->addChannel(data.getFalcorNodeID(pAiNode->mNodeName.C_Str(), i))); } uint32_t pos = 0, rot = 0, scale = 0; @@ -294,9 +294,9 @@ namespace Falcor auto nextKeyTime = [&]() { double time = -std::numeric_limits::max(); - if (pos < pAiNode->mNumPositionKeys) time = max(time, pAiNode->mPositionKeys[pos].mTime); - if (rot < pAiNode->mNumRotationKeys) time = max(time, pAiNode->mRotationKeys[rot].mTime); - if (scale < pAiNode->mNumScalingKeys) time = max(time, pAiNode->mScalingKeys[scale].mTime); + if (pos < pAiNode->mNumPositionKeys) time = std::max(time, pAiNode->mPositionKeys[pos].mTime); + if (rot < pAiNode->mNumRotationKeys) time = std::max(time, pAiNode->mRotationKeys[rot].mTime); + if (scale < pAiNode->mNumScalingKeys) time = std::max(time, pAiNode->mScalingKeys[scale].mTime); assert(time != -std::numeric_limits::max()); return time; }; @@ -346,9 +346,9 @@ namespace Falcor pCamera->setAspectRatio(aspectRatio); pCamera->setDepthRange(pAiCamera->mClipPlaneNear, pAiCamera->mClipPlaneFar); - size_t nodeID = data.getFalcorNode(pAiCamera->mName.C_Str(), 0); + uint32_t nodeID = data.getFalcorNodeID(pAiCamera->mName.C_Str(), 0); - if(nodeID != SceneBuilder::kInvalidNode) + if (nodeID != SceneBuilder::kInvalidNode) { SceneBuilder::Node n; n.name = "Camera.BaseMatrix"; @@ -364,14 +364,14 @@ namespace Falcor return true; } - bool addLightCommon(Light::ConstSharedPtrRef pLight, const mat4& baseMatrix, ImporterData& data, const aiLight* pAiLight) + bool addLightCommon(Light::ConstSharedPtrRef pLight, const glm::mat4& baseMatrix, ImporterData& data, const aiLight* pAiLight) { pLight->setName(pAiLight->mName.C_Str()); assert(pAiLight->mColorDiffuse == pAiLight->mColorSpecular); pLight->setIntensity(aiCast(pAiLight->mColorSpecular)); // Find if the light is affected by a node - size_t nodeID = data.getFalcorNode(pAiLight->mName.C_Str(), 0); + uint32_t nodeID = data.getFalcorNodeID(pAiLight->mName.C_Str(), 0); if (nodeID != SceneBuilder::kInvalidNode) { SceneBuilder::Node n; @@ -388,30 +388,30 @@ namespace Falcor bool createDirLight(ImporterData& data, const aiLight* pAiLight) { DirectionalLight::SharedPtr pLight = DirectionalLight::create(); - vec3 direction = normalize(aiCast(pAiLight->mDirection)); + float3 direction = normalize(aiCast(pAiLight->mDirection)); pLight->setWorldDirection(direction); - mat4 base; - base[2] = vec4(direction, 0); + glm::mat4 base; + base[2] = float4(direction, 0); return addLightCommon(pLight, base, data, pAiLight); } bool createPointLight(ImporterData& data, const aiLight* pAiLight) { PointLight::SharedPtr pLight = PointLight::create(); - vec3 position = aiCast(pAiLight->mPosition); - vec3 lookAt = normalize(aiCast(pAiLight->mDirection)); - vec3 up = normalize(aiCast(pAiLight->mUp)); + float3 position = aiCast(pAiLight->mPosition); + float3 lookAt = normalize(aiCast(pAiLight->mDirection)); + float3 up = normalize(aiCast(pAiLight->mUp)); pLight->setWorldPosition(position); pLight->setWorldDirection(lookAt); pLight->setOpeningAngle(pAiLight->mAngleOuterCone); pLight->setPenumbraAngle(pAiLight->mAngleOuterCone - pAiLight->mAngleInnerCone); - vec3 right = cross(up, lookAt); - mat4 base; - base[0] = vec4(right, 0); - base[1] = vec4(up, 0); - base[2] = vec4(lookAt, 0); - base[3] = vec4(position, 1); + float3 right = cross(up, lookAt); + glm::mat4 base; + base[0] = float4(right, 0); + base[1] = float4(up, 0); + base[2] = float4(lookAt, 0); + base[3] = float4(position, 1); return addLightCommon(pLight, base, data, pAiLight); } @@ -449,13 +449,13 @@ namespace Falcor return true; } - std::vector createTexCrdList(const aiVector3D* pAiTexCrd, uint32_t count) + std::vector createTexCrdList(const aiVector3D* pAiTexCrd, uint32_t count) { - std::vector v2(count); + std::vector v2(count); for (uint32_t i = 0; i < count; i++) { assert(pAiTexCrd[i].z == 0); - v2[i] = vec2(pAiTexCrd[i].x, pAiTexCrd[i].y); + v2[i] = float2(pAiTexCrd[i].x, pAiTexCrd[i].y); } return v2; } @@ -478,7 +478,7 @@ namespace Falcor return indices; } - void loadBones(const aiMesh* pAiMesh, const ImporterData& data, std::vector& weights, std::vector& ids) + void loadBones(const aiMesh* pAiMesh, const ImporterData& data, std::vector& weights, std::vector& ids) { const uint32_t vertexCount = pAiMesh->mNumVertices; weights.resize(vertexCount); @@ -488,7 +488,7 @@ namespace Falcor { const aiBone* pAiBone = pAiMesh->mBones[bone]; assert(data.getNodeInstanceCount(pAiBone->mName.C_Str()) == 1); - size_t aiBoneID = data.getFalcorNode(pAiBone->mName.C_Str(), 0); + uint32_t aiBoneID = data.getFalcorNodeID(pAiBone->mName.C_Str(), 0); // The way Assimp works, the weights holds the IDs of the vertices it affects. // We loop over all the weights, initializing the vertices data along the way @@ -498,8 +498,8 @@ namespace Falcor const aiVertexWeight& aiWeight = pAiBone->mWeights[weightID]; // Get the address of the Bone ID and weight for the current vertex - uvec4& vertexIds = ids[aiWeight.mVertexId]; - vec4& vertexWeights = weights[aiWeight.mVertexId]; + uint4& vertexIds = ids[aiWeight.mVertexId]; + float4& vertexWeights = weights[aiWeight.mVertexId]; // Find the next unused slot in the bone array of the vertex, and initialize it with the current value bool emptySlotFound = false; @@ -507,7 +507,7 @@ namespace Falcor { if (vertexWeights[j] == 0) { - vertexIds[j] = (uint32_t)aiBoneID; + vertexIds[j] = aiBoneID; vertexWeights[j] = aiWeight.mWeight; emptySlotFound = true; break; @@ -521,7 +521,7 @@ namespace Falcor // Now we need to normalize the weights for each vertex, since in some models the sum is larger than 1 for (uint32_t i = 0; i < vertexCount; i++) { - vec4& w = weights[i]; + float4& w = weights[i]; float f = 0; for (int j = 0; j < Scene::kMaxBonesPerVertex; j++) f += w[j]; w /= f; @@ -538,6 +538,7 @@ namespace Falcor // Indices const auto indexList = createIndexList(pAiMesh); + assert(indexList.size() <= std::numeric_limits::max()); mesh.indexCount = (uint32_t)indexList.size(); mesh.pIndices = indexList.data(); @@ -547,14 +548,14 @@ namespace Falcor static_assert(sizeof(pAiMesh->mVertices[0]) == sizeof(mesh.pPositions[0])); static_assert(sizeof(pAiMesh->mNormals[0]) == sizeof(mesh.pNormals[0])); static_assert(sizeof(pAiMesh->mBitangents[0]) == sizeof(mesh.pBitangents[0])); - mesh.pPositions = (vec3*)pAiMesh->mVertices; - mesh.pNormals = (vec3*)pAiMesh->mNormals; - mesh.pBitangents = (vec3*)pAiMesh->mBitangents; - const auto& texCrd = pAiMesh->HasTextureCoords(0) ? createTexCrdList(pAiMesh->mTextureCoords[0], pAiMesh->mNumVertices) : std::vector(); + mesh.pPositions = (float3*)pAiMesh->mVertices; + mesh.pNormals = (float3*)pAiMesh->mNormals; + mesh.pBitangents = (float3*)pAiMesh->mBitangents; + const auto& texCrd = pAiMesh->HasTextureCoords(0) ? createTexCrdList(pAiMesh->mTextureCoords[0], pAiMesh->mNumVertices) : std::vector(); mesh.pTexCrd = texCrd.size() ? texCrd.data() : nullptr; - std::vector boneIds; - std::vector boneWeights; + std::vector boneIds; + std::vector boneWeights; if (pAiMesh->HasBones()) { @@ -575,7 +576,7 @@ namespace Falcor mesh.pMaterial = data.materialMap.at(pAiMesh->mMaterialIndex); assert(mesh.pMaterial); - size_t meshID = data.builder.addMesh(mesh); + uint32_t meshID = data.builder.addMesh(mesh); if (meshID == SceneBuilder::kInvalidNode) return false; data.meshMap[i] = meshID; } @@ -607,10 +608,10 @@ namespace Falcor const aiNode* pChild = pNode->mChildren[i]; std::string parent = pNode->mName.C_Str(); std::string parentType = getNodeType(data, pNode); - std::string parentID = to_string(data.getFalcorNode(pNode)); + std::string parentID = to_string(data.getFalcorNodeID(pNode)); std::string me = pChild->mName.C_Str(); std::string myType = getNodeType(data, pChild); - std::string myID = to_string(data.getFalcorNode(pChild)); + std::string myID = to_string(data.getFalcorNodeID(pChild)); std::replace(parent.begin(), parent.end(), '.', '_'); std::replace(me.begin(), me.end(), '.', '_'); std::replace(parent.begin(), parent.end(), '$', '_'); @@ -630,9 +631,9 @@ namespace Falcor dotfile.close(); } - mat4 getLocalToBindPoseMatrix(ImporterData& data, const std::string& name) + glm::mat4 getLocalToBindPoseMatrix(ImporterData& data, const std::string& name) { - return isBone(data, name) ? data.localToBindPoseMatrices[name] : identity(); + return isBone(data, name) ? data.localToBindPoseMatrices[name] : glm::identity(); } bool parseNode(ImporterData& data, const aiNode* pCurrent, bool hasBoneAncestor) @@ -642,7 +643,7 @@ namespace Falcor bool currentIsBone = isBone(data, n.name); assert(currentIsBone == false || pCurrent->mNumMeshes == 0); - n.parent = pCurrent->mParent ? data.getFalcorNode(pCurrent->mParent) : SceneBuilder::kInvalidNode; + n.parent = pCurrent->mParent ? data.getFalcorNodeID(pCurrent->mParent) : SceneBuilder::kInvalidNode; n.transform = aiCast(pCurrent->mTransformation); n.localToBindPose = getLocalToBindPoseMatrix(data, n.name); @@ -685,26 +686,26 @@ namespace Falcor bool addMeshes(ImporterData& data, aiNode* pNode) { - size_t nodeID = data.getFalcorNode(pNode); - for (size_t mesh = 0; mesh < pNode->mNumMeshes; mesh++) + uint32_t nodeID = data.getFalcorNodeID(pNode); + for (uint32_t mesh = 0; mesh < pNode->mNumMeshes; mesh++) { - size_t meshID = data.meshMap.at(pNode->mMeshes[mesh]); + uint32_t meshID = data.meshMap.at(pNode->mMeshes[mesh]); if (data.modelInstances.size()) { - for(size_t instance = 0 ; instance < data.modelInstances.size() ; instance++) + for(size_t instance = 0; instance < data.modelInstances.size(); instance++) { - size_t instanceNode = nodeID; - if(data.modelInstances[instance] != mat4()) + uint32_t instanceNodeID = nodeID; + if(data.modelInstances[instance] != glm::mat4()) { // Add nodes SceneBuilder::Node n; n.name = "Node" + to_string(nodeID) + ".instance" + to_string(instance); n.parent = nodeID; n.transform = data.modelInstances[instance]; - instanceNode = data.builder.addNode(n); + instanceNodeID = data.builder.addNode(n); } - data.builder.addMeshInstance(instanceNode, meshID); + data.builder.addMeshInstance(instanceNodeID, meshID); } } else data.builder.addMeshInstance(nodeID, meshID); @@ -795,7 +796,7 @@ namespace Falcor float opacity = 1.f; if (pAiMaterial->Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) { - vec4 diffuse = pMaterial->getBaseColor(); + float4 diffuse = pMaterial->getBaseColor(); diffuse.a = opacity; pMaterial->setBaseColor(diffuse); } @@ -817,7 +818,7 @@ namespace Falcor float roughness = convertSpecPowerToRoughness(shininess); shininess = 1.f - roughness; } - vec4 spec = pMaterial->getSpecularParams(); + float4 spec = pMaterial->getSpecularParams(); spec.a = shininess; pMaterial->setSpecularParams(spec); } @@ -830,21 +831,21 @@ namespace Falcor aiColor3D color; if (pAiMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) { - vec4 diffuse = vec4(color.r, color.g, color.b, pMaterial->getBaseColor().a); + float4 diffuse = float4(color.r, color.g, color.b, pMaterial->getBaseColor().a); pMaterial->setBaseColor(diffuse); } // Specular color if (pAiMaterial->Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) { - vec4 specular = vec4(color.r, color.g, color.b, pMaterial->getSpecularParams().a); + float4 specular = float4(color.r, color.g, color.b, pMaterial->getSpecularParams().a); pMaterial->setSpecularParams(specular); } // Emissive color if (pAiMaterial->Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) { - vec3 emissive = vec3(color.r, color.g, color.b); + float3 emissive = float3(color.r, color.g, color.b); pMaterial->setEmissiveColor(emissive); } @@ -860,11 +861,11 @@ namespace Falcor { if (pAiMaterial->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR, color) == AI_SUCCESS) { - vec4 baseColor = vec4(color.r, color.g, color.b, pMaterial->getBaseColor().a); + float4 baseColor = float4(color.r, color.g, color.b, pMaterial->getBaseColor().a); pMaterial->setBaseColor(baseColor); } - vec4 specularParams = pMaterial->getSpecularParams(); + float4 specularParams = pMaterial->getSpecularParams(); float metallic; if (pAiMaterial->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, metallic) == AI_SUCCESS) diff --git a/Source/Falcor/Scene/Importers/PythonImporter.cpp b/Source/Falcor/Scene/Importers/PythonImporter.cpp index 6fe60f27d..418e4e0dd 100644 --- a/Source/Falcor/Scene/Importers/PythonImporter.cpp +++ b/Source/Falcor/Scene/Importers/PythonImporter.cpp @@ -69,9 +69,11 @@ namespace Falcor { return error("Script file is missing header with reference to scene file."); } - const std::string sceneFile = directory + '/' + script.substr(2, endOfFirstLine - 2); + + addDataDirectory(directory); // Load referenced scene + const std::string sceneFile = script.substr(2, endOfFirstLine - 2); mBuilder.import(sceneFile.c_str()); // Execute scene script @@ -79,6 +81,7 @@ namespace Falcor context.setObject("scene", mBuilder.getScene()); Scripting::runScriptFromFile(fullpath, context); + removeDataDirectory(directory); return true; } else diff --git a/Source/Falcor/Scene/Importers/SceneImporter.cpp b/Source/Falcor/Scene/Importers/SceneImporter.cpp index 1631fe89a..3a3cf92f9 100644 --- a/Source/Falcor/Scene/Importers/SceneImporter.cpp +++ b/Source/Falcor/Scene/Importers/SceneImporter.cpp @@ -134,7 +134,7 @@ namespace Falcor bool loadIncludeFile(const std::string& Include); - std::vector parseModelInstances(const rapidjson::Value& jsonVal); + std::vector parseModelInstances(const rapidjson::Value& jsonVal); bool createModel(const rapidjson::Value& jsonModel); bool createPointLight(const rapidjson::Value& jsonLight); bool createDirLight(const rapidjson::Value& jsonLight); @@ -214,13 +214,13 @@ namespace Falcor return true; } - std::vector SceneImporterImpl::parseModelInstances(const rapidjson::Value& jsonVal) + std::vector SceneImporterImpl::parseModelInstances(const rapidjson::Value& jsonVal) { struct ModelInstance { - vec3 scaling = vec3(1, 1, 1); - vec3 position = vec3(0, 0, 0); - vec3 rotation = vec3(0, 0, 0); + float3 scaling = float3(1, 1, 1); + float3 position = float3(0, 0, 0); + float3 rotation = float3(0, 0, 0); }; std::vector instances; @@ -255,13 +255,13 @@ namespace Falcor instances.push_back(instance); } - std::vector matrices(instances.size()); + std::vector matrices(instances.size()); for (size_t i = 0; i < matrices.size(); i++) { - mat4 T; - T[3] = vec4(instances[i].position, 1); - mat4 S = scale(instances[i].scaling); - mat4 R = yawPitchRoll(instances[i].rotation[0], instances[i].rotation[1], instances[i].rotation[2]); + glm::mat4 T; + T[3] = float4(instances[i].position, 1); + glm::mat4 S = glm::scale(instances[i].scaling); + glm::mat4 R = glm::yawPitchRoll(instances[i].rotation[0], instances[i].rotation[1], instances[i].rotation[2]); matrices[i] = T * R * S; } @@ -319,7 +319,7 @@ namespace Falcor } } - std::vector instances; + std::vector instances; // Loop over the other members for (auto jval = jsonModel.MemberBegin(); jval != jsonModel.MemberEnd(); jval++) @@ -420,7 +420,7 @@ namespace Falcor } else if (key == SceneKeys::kLightIntensity) { - glm::vec3 intensity; + float3 intensity; if (getFloatVec<3>(value, "Directional light intensity", &intensity[0]) == false) { return false; @@ -429,8 +429,8 @@ namespace Falcor } else if (key == SceneKeys::kLightDirection) { - glm::vec3 direction; - if (getFloatVec<3>(value, "Directional light intensity", &direction[0]) == false) + float3 direction; + if (getFloatVec<3>(value, "Directional light direction", &direction[0]) == false) { return false; } @@ -495,7 +495,7 @@ namespace Falcor } else if (key == SceneKeys::kLightIntensity) { - glm::vec3 intensity; + float3 intensity; if (getFloatVec<3>(value, "Point light intensity", &intensity[0]) == false) { return false; @@ -504,7 +504,7 @@ namespace Falcor } else if (key == SceneKeys::kLightPos) { - glm::vec3 position; + float3 position; if (getFloatVec<3>(value, "Point light position", &position[0]) == false) { return false; @@ -513,7 +513,7 @@ namespace Falcor } else if (key == SceneKeys::kLightDirection) { - glm::vec3 dir; + float3 dir; if (getFloatVec<3>(value, "Point light direction", &dir[0]) == false) { return false; @@ -547,9 +547,9 @@ namespace Falcor // Create the light. auto pAreaLight = AnalyticAreaLight::create(type); - glm::vec3 scaling(1, 1, 1); - glm::vec3 translation(0, 0, 0); - glm::vec3 rotation(0, 0, 0); + float3 scaling(1, 1, 1); + float3 translation(0, 0, 0); + float3 rotation(0, 0, 0); for (auto it = jsonLight.MemberBegin(); it != jsonLight.MemberEnd(); it++) { @@ -574,7 +574,7 @@ namespace Falcor } else if (key == SceneKeys::kLightIntensity) { - glm::vec3 intensity; + float3 intensity; if (getFloatVec<3>(value, "Area light intensity", &intensity[0]) == false) { return false; @@ -696,8 +696,8 @@ namespace Falcor actualPath = imagePath; } - vec3 position; - glm::vec3 intensity(1.0f); + float3 position; + float3 intensity(1.0f); float radius = -1; uint32_t diffuseSamples = LightProbe::kDefaultDiffSamples; uint32_t specSamples = LightProbe::kDefaultSpecSamples; @@ -806,7 +806,7 @@ namespace Falcor } else if (key == SceneKeys::kCamPosition) { - glm::vec3 pos; + float3 pos; if (getFloatVec<3>(value, "Camera's position", &pos[0]) == false) { return false; @@ -815,7 +815,7 @@ namespace Falcor } else if (key == SceneKeys::kCamTarget) { - glm::vec3 target; + float3 target; if (getFloatVec<3>(value, "Camera's target", &target[0]) == false) { return false; @@ -824,7 +824,7 @@ namespace Falcor } else if (key == SceneKeys::kCamUp) { - glm::vec3 up; + float3 up; if (getFloatVec<3>(value, "Camera's up vector", &up[0]) == false) { return false; @@ -1131,6 +1131,7 @@ namespace Falcor bool SceneImporter::import(const std::string& filename, SceneBuilder& builder) { + logWarning("fscene files are no longer supported in Falcor 4.0. Some properties may not be loaded."); SceneImporterImpl importer(builder); return importer.load(filename); } diff --git a/Source/Falcor/Scene/Lights/Light.cpp b/Source/Falcor/Scene/Lights/Light.cpp index 5406c6e5d..bd28cfbd3 100644 --- a/Source/Falcor/Scene/Lights/Light.cpp +++ b/Source/Falcor/Scene/Lights/Light.cpp @@ -32,7 +32,7 @@ namespace Falcor { - bool checkOffset(const std::string& structName, UniformShaderVarOffset cbOffset, size_t cppOffset, const char* field) + static bool checkOffset(const std::string& structName, UniformShaderVarOffset cbOffset, size_t cppOffset, const char* field) { if (cbOffset.getByteOffset() != cppOffset) { @@ -42,7 +42,7 @@ namespace Falcor return true; } - void Light::setIntensity(const glm::vec3& intensity) + void Light::setIntensity(const float3& intensity) { mData.intensity = intensity; } @@ -79,11 +79,11 @@ namespace Falcor var.setBlob(mData); } - glm::vec3 Light::getColorForUI() + float3 Light::getColorForUI() { if ((mUiLightIntensityColor * mUiLightIntensityScale) != mData.intensity) { - float mag = max(mData.intensity.x, max(mData.intensity.y, mData.intensity.z)); + float mag = std::max(mData.intensity.x, std::max(mData.intensity.y, mData.intensity.z)); if (mag <= 1.f) { mUiLightIntensityColor = mData.intensity; @@ -99,7 +99,7 @@ namespace Falcor return mUiLightIntensityColor; } - void Light::setColorFromUI(const glm::vec3& uiColor) + void Light::setColorFromUI(const float3& uiColor) { mUiLightIntensityColor = uiColor; setIntensity(mUiLightIntensityColor * mUiLightIntensityScale); @@ -109,7 +109,7 @@ namespace Falcor { if ((mUiLightIntensityColor * mUiLightIntensityScale) != mData.intensity) { - float mag = max(mData.intensity.x, max(mData.intensity.y, mData.intensity.z)); + float mag = std::max(mData.intensity.x, std::max(mData.intensity.y, mData.intensity.z)); if (mag <= 1.f) { mUiLightIntensityColor = mData.intensity; @@ -137,7 +137,7 @@ namespace Falcor Gui::Group g(pGui, group); if (g.open()) { - glm::vec3 color = getColorForUI(); + float3 color = getColorForUI(); if (g.rgbColor("Color", color)) { setColorFromUI(color); @@ -180,13 +180,18 @@ namespace Falcor } } - void DirectionalLight::setWorldDirection(const glm::vec3& dir) + void DirectionalLight::setWorldDirection(const float3& dir) { + if (!(glm::length(dir) > 0.f)) // NaNs propagate + { + logWarning("Can't set light direction to zero length vector. Ignoring call."); + return; + } mData.dirW = normalize(dir); mData.posW = mCenter - mData.dirW * mDistance; // Move light's position sufficiently far away } - void DirectionalLight::setWorldParams(const glm::vec3& center, float radius) + void DirectionalLight::setWorldParams(const float3& center, float radius) { mDistance = radius; mCenter = center; @@ -212,12 +217,17 @@ namespace Falcor PointLight::~PointLight() = default; - void PointLight::setWorldDirection(const glm::vec3& dir) + void PointLight::setWorldDirection(const float3& dir) { + if (!(glm::length(dir) > 0.f)) // NaNs propagate + { + logWarning("Can't set light direction to zero length vector. Ignoring call."); + return; + } mData.dirW = normalize(dir); } - void PointLight::setWorldPosition(const glm::vec3& pos) + void PointLight::setWorldPosition(const float3& pos) { mData.posW = pos; } @@ -281,7 +291,7 @@ namespace Falcor mData.bitangent = float3(0, 1, 0); mData.surfaceArea = 4.0f; - mScaling = vec3(1, 1, 1); + mScaling = float3(1, 1, 1); update(); } @@ -315,17 +325,17 @@ namespace Falcor case LightType::Rect: { - float rx = glm::length(mData.transMat * vec4(1.0f, 0.0f, 0.0f, 0.0f)); - float ry = glm::length(mData.transMat * vec4(0.0f, 1.0f, 0.0f, 0.0f)); + float rx = glm::length(mData.transMat * float4(1.0f, 0.0f, 0.0f, 0.0f)); + float ry = glm::length(mData.transMat * float4(0.0f, 1.0f, 0.0f, 0.0f)); mData.surfaceArea = 4.0f * rx * ry; } break; case LightType::Sphere: { - float rx = glm::length(mData.transMat * vec4(1.0f, 0.0f, 0.0f, 0.0f)); - float ry = glm::length(mData.transMat * vec4(0.0f, 1.0f, 0.0f, 0.0f)); - float rz = glm::length(mData.transMat * vec4(0.0f, 0.0f, 1.0f, 0.0f)); + float rx = glm::length(mData.transMat * float4(1.0f, 0.0f, 0.0f, 0.0f)); + float ry = glm::length(mData.transMat * float4(0.0f, 1.0f, 0.0f, 0.0f)); + float rz = glm::length(mData.transMat * float4(0.0f, 0.0f, 1.0f, 0.0f)); mData.surfaceArea = 4.0f * (float)M_PI * pow(pow(rx * ry, 1.6f) + pow(ry * rz, 1.6f) + pow(rx * rz, 1.6f) / 3.0f, 1.0f / 1.6f); } @@ -333,8 +343,8 @@ namespace Falcor case LightType::Disc: { - float rx = glm::length(mData.transMat * vec4(1.0f, 0.0f, 0.0f, 0.0f)); - float ry = glm::length(mData.transMat * vec4(0.0f, 1.0f, 0.0f, 0.0f)); + float rx = glm::length(mData.transMat * float4(1.0f, 0.0f, 0.0f, 0.0f)); + float ry = glm::length(mData.transMat * float4(0.0f, 1.0f, 0.0f, 0.0f)); mData.surfaceArea = (float)M_PI * rx * ry; } diff --git a/Source/Falcor/Scene/Lights/Light.h b/Source/Falcor/Scene/Lights/Light.h index 6a5a9f725..d0c4bc9f3 100644 --- a/Source/Falcor/Scene/Lights/Light.h +++ b/Source/Falcor/Scene/Lights/Light.h @@ -79,7 +79,7 @@ namespace Falcor /** Set the light intensity. */ - virtual void setIntensity(const glm::vec3& intensity); + virtual void setIntensity(const float3& intensity); enum class Changes { @@ -101,9 +101,9 @@ namespace Falcor /** Scripting helper functions for getting/setting intensity and color. */ void setIntensityFromScript(float intensity) { setIntensityFromUI(intensity); } - void setColorFromScript(glm::vec3 color) { setColorFromUI(color); } + void setColorFromScript(float3 color) { setColorFromUI(color); } float getIntensityForScript() { return getIntensityForUI(); } - glm::vec3 getColorForScript() { return getColorForUI(); } + float3 getColorForScript() { return getColorForUI(); } protected: Light() = default; @@ -111,15 +111,15 @@ namespace Falcor static const size_t kDataSize = sizeof(LightData); /* UI callbacks for keeping the intensity in-sync */ - glm::vec3 getColorForUI(); - void setColorFromUI(const glm::vec3& uiColor); + float3 getColorForUI(); + void setColorFromUI(const float3& uiColor); float getIntensityForUI(); void setIntensityFromUI(float intensity); std::string mName; /* These two variables track mData values for consistent UI operation.*/ - glm::vec3 mUiLightIntensityColor = glm::vec3(0.5f, 0.5f, 0.5f); + float3 mUiLightIntensityColor = float3(0.5f, 0.5f, 0.5f); float mUiLightIntensityScale = 1.0f; LightData mData, mPrevData; Changes mChanges = Changes::None; @@ -143,16 +143,17 @@ namespace Falcor void renderUI(Gui* pGui, const char* group = nullptr) override; /** Set the light's world-space direction. + \param[in] dir Light direction. Does not have to be normalized. */ - void setWorldDirection(const glm::vec3& dir); + void setWorldDirection(const float3& dir); /** Set the scene parameters */ - void setWorldParams(const glm::vec3& center, float radius); + void setWorldParams(const float3& center, float radius); /** Get the light's world-space direction. */ - const glm::vec3& getWorldDirection() const { return mData.dirW; } + const float3& getWorldDirection() const { return mData.dirW; } /** Get total light power (needed for light picking) */ @@ -161,7 +162,7 @@ namespace Falcor private: DirectionalLight(); float mDistance = 1e3f; ///< Scene bounding radius is required to move the light position sufficiently far away - vec3 mCenter; + float3 mCenter; }; /** Simple infinitely-small point light with quadratic attenuation @@ -187,11 +188,12 @@ namespace Falcor /** Set the light's world-space position */ - void setWorldPosition(const glm::vec3& pos); + void setWorldPosition(const float3& pos); /** Set the light's world-space direction. + \param[in] dir Light direction. Does not have to be normalized. */ - void setWorldDirection(const glm::vec3& dir); + void setWorldDirection(const float3& dir); /** Set the cone opening half-angle for use as a spot light \param[in] openingAngle Angle in radians. @@ -200,15 +202,15 @@ namespace Falcor /** Get the light's world-space position */ - const glm::vec3& getWorldPosition() const { return mData.posW; } + const float3& getWorldPosition() const { return mData.posW; } /** Get the light's world-space direction */ - const glm::vec3& getWorldDirection() const { return mData.dirW; } + const float3& getWorldDirection() const { return mData.dirW; } /** Get the light intensity. */ - const glm::vec3& getIntensity() const { return mData.intensity; } + const float3& getIntensity() const { return mData.intensity; } /** Get the penumbra half-angle */ @@ -246,11 +248,11 @@ namespace Falcor /** Set light source scaling \param[in] scale x,y,z scaling factors */ - void setScaling(vec3 scale) { mScaling = scale; } + void setScaling(float3 scale) { mScaling = scale; } /** Set light source scale */ - vec3 getScaling() const { return mScaling; } + float3 getScaling() const { return mScaling; } /** Get total light power (needed for light picking) */ @@ -276,8 +278,8 @@ namespace Falcor void update(); bool mDirty = true; - glm::vec3 mScaling; ///< Scaling, controls the size of the light - glm::mat4 mTransformMatrix; ///< Transform matrix minus scaling component + float3 mScaling; ///< Scaling, controls the size of the light + glm::mat4 mTransformMatrix; ///< Transform matrix minus scaling component }; // TODO: Remove this? It's not used anywhere diff --git a/Source/Falcor/Scene/Lights/LightProbe.cpp b/Source/Falcor/Scene/Lights/LightProbe.cpp index 1fe56dfa4..a93b0d352 100644 --- a/Source/Falcor/Scene/Lights/LightProbe.cpp +++ b/Source/Falcor/Scene/Lights/LightProbe.cpp @@ -201,7 +201,7 @@ namespace Falcor float intensity = mData.intensity.r; if (g.var("Intensity", intensity, 0.0f)) { - mData.intensity = vec3(intensity); + mData.intensity = float3(intensity); } g.var("Radius", mData.radius, -1.0f); @@ -232,7 +232,7 @@ namespace Falcor // Set the data into the constant buffer check_offset(posW); check_offset(intensity); - static_assert(kDataSize % sizeof(vec4) == 0, "LightProbeData size should be a multiple of 16"); + static_assert(kDataSize % sizeof(float4) == 0, "LightProbeData size should be a multiple of 16"); if(!var.isValid()) return; diff --git a/Source/Falcor/Scene/Lights/LightProbe.h b/Source/Falcor/Scene/Lights/LightProbe.h index 883710413..13c5e0f13 100644 --- a/Source/Falcor/Scene/Lights/LightProbe.h +++ b/Source/Falcor/Scene/Lights/LightProbe.h @@ -84,11 +84,11 @@ namespace Falcor /** Set the light probe's world-space position */ - void setPosW(const vec3& posW) { mData.posW = posW; } + void setPosW(const float3& posW) { mData.posW = posW; } /** Get the light probe's world-space position */ - const vec3& getPosW() const { return mData.posW; } + const float3& getPosW() const { return mData.posW; } /** Set the spherical radius the light probe encompasses. Set radius to negative to sample as an infinite-distance global light probe. */ @@ -108,11 +108,11 @@ namespace Falcor /** Set the light probe's light intensity */ - void setIntensity(const vec3& intensity) { mData.intensity = intensity; } + void setIntensity(const float3& intensity) { mData.intensity = intensity; } /** Get the light probe's light intensity */ - const vec3& getIntensity() const { return mData.intensity; } + const float3& getIntensity() const { return mData.intensity; } /** Attach a sampler to the light probe */ diff --git a/Source/Falcor/Scene/Material/Material.cpp b/Source/Falcor/Scene/Material/Material.cpp index 7900f0805..ac0520640 100644 --- a/Source/Falcor/Scene/Material/Material.cpp +++ b/Source/Falcor/Scene/Material/Material.cpp @@ -69,7 +69,7 @@ namespace Falcor } else { - glm::vec4 baseColor = getBaseColor(); + float4 baseColor = getBaseColor(); if (widget.var("Base color", baseColor, 0.f, 1.f, 0.01f)) setBaseColor(baseColor); } @@ -82,7 +82,7 @@ namespace Falcor } else { - glm::vec4 specularParams = getSpecularParams(); + float4 specularParams = getSpecularParams(); if (widget.var("Specular params", specularParams, 0.f, 1.f, 0.01f)) setSpecularParams(specularParams); widget.tooltip("The encoding depends on the shading model:\n\n" @@ -100,7 +100,7 @@ namespace Falcor } else { - glm::vec3 emissiveColor = getEmissiveColor(); + float3 emissiveColor = getEmissiveColor(); if (widget.var("Emissive color", emissiveColor, 0.f, 1.f, 0.01f)) setEmissiveColor(emissiveColor); } @@ -213,7 +213,7 @@ namespace Falcor } } - void Material::setBaseColor(const vec4& color) + void Material::setBaseColor(const float4& color) { if (mData.baseColor != color) { @@ -223,7 +223,7 @@ namespace Falcor } } - void Material::setSpecularParams(const vec4& color) + void Material::setSpecularParams(const float4& color) { if (mData.specular != color) { @@ -242,7 +242,7 @@ namespace Falcor } } - void Material::setVolumeAbsorption(const vec3& volumeAbsorption) + void Material::setVolumeAbsorption(const float3& volumeAbsorption) { if (mData.volumeAbsorption != volumeAbsorption) { @@ -251,7 +251,7 @@ namespace Falcor } } - void Material::setEmissiveColor(const vec3& color) + void Material::setEmissiveColor(const float3& color) { if (mData.emissive != color) { diff --git a/Source/Falcor/Scene/Material/Material.h b/Source/Falcor/Scene/Material/Material.h index 69efb0db4..a492db4b2 100644 --- a/Source/Falcor/Scene/Material/Material.h +++ b/Source/Falcor/Scene/Material/Material.h @@ -162,19 +162,19 @@ namespace Falcor /** Set the base color */ - void setBaseColor(const vec4& color); + void setBaseColor(const float4& color); /** Get the base color */ - const vec4& getBaseColor() const { return mData.baseColor; } + const float4& getBaseColor() const { return mData.baseColor; } /** Set the specular parameters */ - void setSpecularParams(const vec4& color); + void setSpecularParams(const float4& color); /** Get the specular parameters */ - const vec4& getSpecularParams() const { return mData.specular; } + const float4& getSpecularParams() const { return mData.specular; } /** Set the specular transmission */ @@ -186,15 +186,15 @@ namespace Falcor /** Set the volume absorption (absorption coefficient). */ - void setVolumeAbsorption(const vec3& volumeAbsorption); + void setVolumeAbsorption(const float3& volumeAbsorption); /** Get the volume absorption (absorption coefficient). */ - const vec3& getVolumeAbsorption() const { return mData.volumeAbsorption; } + const float3& getVolumeAbsorption() const { return mData.volumeAbsorption; } /** Set the emissive color */ - void setEmissiveColor(const vec3& color); + void setEmissiveColor(const float3& color); /** Set the emissive factor */ @@ -202,7 +202,7 @@ namespace Falcor /** Get the emissive color */ - const vec3& getEmissiveColor() const { return mData.emissive; } + const float3& getEmissiveColor() const { return mData.emissive; } /** Get the emissive factor */ diff --git a/Source/Falcor/Scene/ParticleSystem/ParticleSystem.cpp b/Source/Falcor/Scene/ParticleSystem/ParticleSystem.cpp index f9821628e..8a64b4722 100644 --- a/Source/Falcor/Scene/ParticleSystem/ParticleSystem.cpp +++ b/Source/Falcor/Scene/ParticleSystem/ParticleSystem.cpp @@ -66,9 +66,9 @@ namespace Falcor } //compute cs ComputeProgram::SharedPtr pSimulateCs = ComputeProgram::createFromFile(simulateComputeShader, "main", defineList); - + //get num sim threads, required as a define for emit cs - uvec3 simThreads; + uint3 simThreads; simThreads = pSimulateCs->getReflector()->getThreadGroupSize(); mSimulateThreads = simThreads.x * simThreads.y * simThreads.z; @@ -146,7 +146,7 @@ namespace Falcor mDrawResources.pState = GraphicsState::create(); mDrawResources.pState->setProgram(pDrawProgram); - //Create empty vbo for draw + //Create empty vbo for draw Vao::BufferVec bufferVec; VertexLayout::SharedPtr pLayout = VertexLayout::create(); Vao::Topology topology = Vao::Topology::TriangleStrip; @@ -164,11 +164,11 @@ namespace Falcor emittedParticles.resize(num); for (uint32_t i = 0; i < num; ++i) { - Particle p; + Particle p; p.pos = mEmitter.spawnPos + glm::linearRand(-mEmitter.spawnPosOffset, mEmitter.spawnPosOffset); p.vel = mEmitter.vel + glm::linearRand(-mEmitter.velOffset, mEmitter.velOffset); p.accel = mEmitter.accel + glm::linearRand(-mEmitter.accelOffset, mEmitter.accelOffset); - //total scale of the billboard, so the amount to actually move to billboard corners is half scale. + //total scale of the billboard, so the amount to actually move to billboard corners is half scale. p.scale = 0.5f * mEmitter.scale + glm::linearRand(-mEmitter.scaleOffset, mEmitter.scaleOffset); p.growth = 0.5f * mEmitter.growth + glm::linearRand(-mEmitter.growthOffset, mEmitter.growthOffset); p.life = mEmitter.duration + glm::linearRand(-mEmitter.growthOffset, mEmitter.growthOffset); @@ -196,7 +196,7 @@ namespace Falcor if (mEmitTimer >= mEmitter.emitFrequency) { mEmitTimer -= mEmitter.emitFrequency; - emit(pCtx, max(mEmitter.emitCount + glm::linearRand(-mEmitter.emitCountOffset, mEmitter.emitCountOffset), 0)); + emit(pCtx, std::max(mEmitter.emitCount + glm::linearRand(-mEmitter.emitCountOffset, mEmitter.emitCountOffset), 0)); } //Simulate @@ -220,7 +220,7 @@ namespace Falcor //reset alive list counter to 0 uint32_t zero = 0; mpAliveList->getUAVCounter()->setBlob(&zero, 0, sizeof(uint32_t)); - pCtx->dispatch(mSimulateResources.pState.get(), mSimulateResources.pVars.get(), {max(mMaxParticles / mSimulateThreads, 1u), 1, 1}); + pCtx->dispatch(mSimulateResources.pState.get(), mSimulateResources.pVars.get(), {std::max(mMaxParticles / mSimulateThreads, 1u), 1, 1}); } void ParticleSystem::render(RenderContext* pCtx, const Fbo::SharedPtr& pDst, glm::mat4 view, glm::mat4 proj) @@ -234,7 +234,7 @@ namespace Falcor cbuf.proj = proj; mDrawResources.pVars->getParameterBlock(mBindLocations.drawCB)->setBlob(&cbuf, 0, sizeof(cbuf)); - //particle draw uses many of render context's existing state's properties + //particle draw uses many of render context's existing state's properties mDrawResources.pState->setFbo(pDst); pCtx->drawIndirect(mDrawResources.pState.get(), mDrawResources.pVars.get(), 1, mpIndirectArgs.get(), 0, nullptr, 0); } @@ -292,9 +292,9 @@ namespace Falcor } void ParticleSystem::setParticleDuration(float dur, float offset) - { - mEmitter.duration = dur; - mEmitter.durationOffset = offset; + { + mEmitter.duration = dur; + mEmitter.durationOffset = offset; } void ParticleSystem::setEmitData(uint32_t emitCount, uint32_t emitCountOffset, float emitFrequency) @@ -304,19 +304,19 @@ namespace Falcor mEmitter.emitFrequency = emitFrequency; } - void ParticleSystem::setSpawnPos(vec3 spawnPos, vec3 offset) + void ParticleSystem::setSpawnPos(float3 spawnPos, float3 offset) { mEmitter.spawnPos = spawnPos; mEmitter.spawnPosOffset = offset; } - void ParticleSystem::setVelocity(vec3 velocity, vec3 offset) + void ParticleSystem::setVelocity(float3 velocity, float3 offset) { mEmitter.vel = velocity; mEmitter.velOffset = offset; } - void ParticleSystem::setAcceleration(vec3 accel, vec3 offset) + void ParticleSystem::setAcceleration(float3 accel, float3 offset) { mEmitter.accel = accel; mEmitter.accelOffset = offset; @@ -339,7 +339,7 @@ namespace Falcor mEmitter.billboardRotation = rot; mEmitter.billboardRotationOffset = offset; } - + void ParticleSystem::setBillboardRotationVelocity(float rotVel, float offset) { mEmitter.billboardRotationVel = rotVel; diff --git a/Source/Falcor/Scene/ParticleSystem/ParticleSystem.h b/Source/Falcor/Scene/ParticleSystem/ParticleSystem.h index 0e6701731..40362ef6d 100644 --- a/Source/Falcor/Scene/ParticleSystem/ParticleSystem.h +++ b/Source/Falcor/Scene/ParticleSystem/ParticleSystem.h @@ -48,7 +48,7 @@ namespace Falcor /** Creates a new particle system \params[in] pCtx The render context - \params[in] maxParticles The max number of particles allowed at once, emits will be blocked if the system is maxxed out + \params[in] maxParticles The max number of particles allowed at once, emits will be blocked if the system is maxxed out \params[in] drawPixelShader The pixel shader used to draw the particles \params[in] simulateComputeShader The compute shader used to update the particles \params[in] sorted Whether or not the particles should be sorted by depth before render @@ -58,7 +58,7 @@ namespace Falcor std::string simulateComputeShader = kDefaultSimulateShader, bool sorted = true); - /** Updates the particle system, emitting if it's time to do so and simulating particles + /** Updates the particle system, emitting if it's time to do so and simulating particles */ void update(RenderContext* pCtx, float dt, glm::mat4 view); @@ -84,7 +84,7 @@ namespace Falcor ComputeVars::SharedPtr getSimulateVars() { return mSimulateResources.pVars; } /** Sets how long a particle will remain alive after spawning. - \params[in] dur The new base duration + \params[in] dur The new base duration \params[in] offset The new random offset to be applied. final value is base + randRange(-offset, offset) */ void setParticleDuration(float dur, float offset); @@ -104,19 +104,19 @@ namespace Falcor \params[in] spawnPos The new base spawn position \params[in] offset The new random offset to be applied. final value is base + randRange(-offset, offset) */ - void setSpawnPos(vec3 spawnPos, vec3 offset); + void setSpawnPos(float3 spawnPos, float3 offset); /** Sets the velocity particles spawn with. \params[in] velocity The new base velocity \params[in] offset The new random offset to be applied. final value is base + randRange(-offset, offset) */ - void setVelocity(vec3 velocity, vec3 offset); + void setVelocity(float3 velocity, float3 offset); /** Sets the acceleration particles spawn with. \params[in] accel The new base acceleration \params[in] offset The new random offset to be applied. final value is base + randRange(-offset, offset) */ - void setAcceleration(vec3 accel, vec3 offset); + void setAcceleration(float3 accel, float3 offset); /** Sets the scale particles spawn with. \params[in] scale The new base scale @@ -156,16 +156,16 @@ namespace Falcor scale(0.2f), scaleOffset(0.f), growth(-0.05f), growthOffset(0.f), billboardRotation(0.f), billboardRotationOffset(0.25f), billboardRotationVel(0.f), billboardRotationVelOffset(0.f) {} float duration; - float durationOffset; + float durationOffset; float emitFrequency; int32_t emitCount; int32_t emitCountOffset; - vec3 spawnPos; - vec3 spawnPosOffset; - vec3 vel; - vec3 velOffset; - vec3 accel; - vec3 accelOffset; + float3 spawnPos; + float3 spawnPosOffset; + float3 vel; + float3 velOffset; + float3 accel; + float3 accelOffset; float scale; float scaleOffset; float growth; @@ -212,7 +212,7 @@ namespace Falcor Buffer::SharedPtr mpEmitList; Buffer::SharedPtr mpDeadList; Buffer::SharedPtr mpAliveList; - //for draw (0 - Verts Per Instance, 1 - Instance Count, + //for draw (0 - Verts Per Instance, 1 - Instance Count, //2 - start vertex offset, 3 - start instance offset) Buffer::SharedPtr mpIndirectArgs; diff --git a/Source/Falcor/Scene/Raster.slang b/Source/Falcor/Scene/Raster.slang index 9ac285e79..b218791f8 100644 --- a/Source/Falcor/Scene/Raster.slang +++ b/Source/Falcor/Scene/Raster.slang @@ -31,15 +31,23 @@ __exported import Scene.ShadingData; struct VSIn { - float4 pos : POSITION; - float3 normal : NORMAL; - float3 bitangent : BITANGENT; - float2 texC : TEXCOORD; - uint meshInstanceID : DRAW_ID; - float4 prevPos : PREV_POSITION; -//#ifdef HAS_LIGHTMAP_UV -// float2 lightmapC : LIGHTMAP_UV; -//#endif + // Packed vertex attributes, see PackedStaticVertexData + float3 pos : POSITION; + float3 packedNormalBitangent : PACKED_NORMAL_BITANGENT; + float2 texC : TEXCOORD; + + // Other vertex attributes + uint meshInstanceID : DRAW_ID; + float3 prevPos : PREV_POSITION; + + StaticVertexData unpack() + { + PackedStaticVertexData v; + v.position = pos; + v.packedNormalBitangent = packedNormalBitangent; + v.texCrd = texC; + return v.unpack(); + } }; #ifndef INTERPOLATION_MODE @@ -66,7 +74,7 @@ VSOut defaultVS(VSIn vIn) { VSOut vOut; float4x4 worldMat = gScene.getWorldMatrix(vIn.meshInstanceID); - float4 posW = mul(vIn.pos, worldMat); + float4 posW = mul(float4(vIn.pos, 1.f), worldMat); vOut.posW = posW.xyz; vOut.posH = mul(posW, gScene.camera.getViewProj()); @@ -74,10 +82,10 @@ VSOut defaultVS(VSIn vIn) vOut.materialID = gScene.getMaterialID(vIn.meshInstanceID); vOut.texC = vIn.texC; - vOut.normalW = mul(vIn.normal, (float3x3)gScene.getInverseTransposeWorldMatrix(vIn.meshInstanceID)).xyz; - vOut.bitangentW = mul(vIn.bitangent,(float3x3) gScene.getWorldMatrix(vIn.meshInstanceID)); + vOut.normalW = mul(vIn.unpack().normal, gScene.getInverseTransposeWorldMatrix(vIn.meshInstanceID)); + vOut.bitangentW = mul(vIn.unpack().bitangent, (float3x3)gScene.getWorldMatrix(vIn.meshInstanceID)); - float4 prevPosW = mul(vIn.prevPos, gScene.getPrevWorldMatrix(vIn.meshInstanceID)); + float4 prevPosW = mul(float4(vIn.prevPos, 1.f), gScene.getPrevWorldMatrix(vIn.meshInstanceID)); vOut.prevPosH = mul(prevPosW, gScene.camera.data.prevViewProjMatNoJitter); return vOut; diff --git a/Source/Falcor/Scene/Raytracing.slang b/Source/Falcor/Scene/Raytracing.slang index 50af99704..79d902b56 100644 --- a/Source/Falcor/Scene/Raytracing.slang +++ b/Source/Falcor/Scene/Raytracing.slang @@ -29,8 +29,9 @@ __exported import Scene.Scene; __exported import Scene.ShadingData; __exported import Utils.Helpers; +import Experimental.Scene.Material.TexLODHelpers; + RaytracingAccelerationStructure gRtScene; -Buffer gAsToInstance; cbuffer DxrPerFrame { @@ -47,7 +48,7 @@ struct HitShaderParams */ uint getGlobalHitID() { - return gAsToInstance[InstanceID() + geometryIndex]; + return InstanceID() + geometryIndex; } }; @@ -62,6 +63,36 @@ VertexData getVertexData(HitShaderParams hitParams, uint triangleIndex, BuiltInT return gScene.getVertexData(hitParams.getGlobalHitID(), triangleIndex, barycentrics); } +/** Returns interpolated vertex attributes in a ray tracing hit program when ray cones are used for texture LOD. + \param[in] hitParams Parmaters for hit shader + \param[in] triangleIndex Index of the triangle in the current mesh (= PrimitiveIndex()). + \param[in] attribs Intersection attributes provided by DXR. + \return Interpolated vertex attributes. +*/ +VertexData getVertexDataRayCones(HitShaderParams hitParams, uint triangleIndex, BuiltInTriangleIntersectionAttributes attribs) +{ + float3 barycentrics = float3(1.0 - attribs.barycentrics.x - attribs.barycentrics.y, attribs.barycentrics.x, attribs.barycentrics.y); + return gScene.getVertexDataRayCones(hitParams.getGlobalHitID(), triangleIndex, barycentrics); +} + +/** Returns interpolated vertex attributes in a ray tracing hit program when ray differentials are used for texture LOD. + \param[in] hitParams Parmaters for hit shader + \param[in] triangleIndex Index of the triangle in the current mesh (= PrimitiveIndex()). + \param[in] attribs Intersection attributes provided by DXR. + \param[in] rayDir Ray direction. + \param[in] hitT Distance to hit point. + \param[in,out] rayDiff The ray differential used as input and output. + \param[out] dUVdx The differential of the texture coordinates in pixel coordinate x. + \param[out] dUVdy The differential of the texture coordinates in pixel coordinate y. + \return Interpolated vertex attributes. +*/ +VertexData getVertexDataRayDiff(HitShaderParams hitParams, uint triangleIndex, BuiltInTriangleIntersectionAttributes attribs, in float3 rayDir, in float hitT, + inout RayDiff rayDiff, out float2 dUVdx, out float2 dUVdy) +{ + float3 barycentrics = float3(1.0 - attribs.barycentrics.x - attribs.barycentrics.y, attribs.barycentrics.x, attribs.barycentrics.y); + return gScene.getVertexDataRayDiff(hitParams.getGlobalHitID(), triangleIndex, barycentrics, rayDir, hitT, rayDiff, dUVdx, dUVdy); +} + /** Returns interpolated position on a triangle in world space for the previous frame. \param[in] triangleIndex Index of the triangle in the current mesh (= PrimitiveIndex()). \param[in] attribs Intersection attributes provided by DXR. diff --git a/Source/Falcor/Scene/Scene.cpp b/Source/Falcor/Scene/Scene.cpp index 809ea4113..d151cf49f 100644 --- a/Source/Falcor/Scene/Scene.cpp +++ b/Source/Falcor/Scene/Scene.cpp @@ -27,18 +27,22 @@ **************************************************************************/ #include "stdafx.h" #include "Scene.h" +#include "HitInfo.h" #include "Raytracing/RtProgram/RtProgram.h" #include "Raytracing/RtProgramVars.h" #include namespace Falcor { + static_assert(sizeof(MeshInstanceData) % 16 == 0, "MeshInstanceData size should be a multiple of 16"); + static_assert(sizeof(PackedStaticVertexData) % 16 == 0, "PackedStaticVertexData size should be a multiple of 16"); + namespace { // Checks if the transform flips the coordinate system handedness (its determinant is negative). - bool doesTransformFlip(const mat4& m) + bool doesTransformFlip(const glm::mat4& m) { - return determinant((mat3)m) < 0.f; + return glm::determinant((glm::mat3)m) < 0.f; } const std::string kParameterBlockName = "gScene"; @@ -46,20 +50,23 @@ namespace Falcor const std::string kMeshInstanceBufferName = "meshInstances"; const std::string kIndexBufferName = "indices"; const std::string kVertexBufferName = "vertices"; + const std::string kPrevVertexBufferName = "prevVertices"; const std::string kMaterialsBufferName = "materials"; const std::string kLightsBufferName = "lights"; - const std::string kCameraVarName = "camera"; - const std::string kCamera = "c"; - const std::string kViewpoint = "viewpoint"; - const std::string kPosition = "position"; - const std::string kTarget = "target"; - const std::string kUp = "up"; + const std::string kCamera = "camera"; + const std::string kGetLight = "getLight"; + const std::string kGetMaterial = "getMaterial"; + const std::string kSetEnvMap = "setEnvMap"; + const std::string kAddViewpoint = "addViewpoint"; + const std::string kRemoveViewpoint = "kRemoveViewpoint"; + const std::string kSelectViewpoint = "selectViewpoint"; } const FileDialogFilterVec Scene::kFileExtensionFilters = { {"fscene"}, + {"py"}, {"fbx"}, {"gltf"}, {"obj"}, @@ -114,6 +121,7 @@ namespace Falcor { Shader::DefineList defines; defines.add("MATERIAL_COUNT", std::to_string(mMaterials.size())); + defines.add(HitInfo::getDefines(this)); return defines; } @@ -152,7 +160,7 @@ namespace Falcor if (overrideRS) pState->setRasterizerState(pCurrentRS); } - void Scene::raytrace(RenderContext* pContext, RtProgram* pProgram, const std::shared_ptr& pVars, uvec3 dispatchDims) + void Scene::raytrace(RenderContext* pContext, RtProgram* pProgram, const std::shared_ptr& pVars, uint3 dispatchDims) { PROFILE("raytraceScene"); @@ -180,21 +188,20 @@ namespace Falcor assert(pReflection); mpSceneBlock = ParameterBlock::create(pReflection); - mpMeshesBuffer = Buffer::createStructured(mpSceneBlock[kMeshBufferName], (uint32_t)mMeshDesc.size(), Resource::BindFlags::ShaderResource); - mpMeshInstancesBuffer = Buffer::createStructured(mpSceneBlock[kMeshInstanceBufferName], (uint32_t)mMeshInstanceData.size(), Resource::BindFlags::ShaderResource); + mpMeshesBuffer = Buffer::createStructured(mpSceneBlock[kMeshBufferName], (uint32_t)mMeshDesc.size(), Resource::BindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); + mpMeshInstancesBuffer = Buffer::createStructured(mpSceneBlock[kMeshInstanceBufferName], (uint32_t)mMeshInstanceData.size(), Resource::BindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); - mpMaterialsBuffer = Buffer::createStructured(mpSceneBlock[kMaterialsBufferName], (uint32_t)mMaterials.size(), Resource::BindFlags::ShaderResource); + mpMaterialsBuffer = Buffer::createStructured(mpSceneBlock[kMaterialsBufferName], (uint32_t)mMaterials.size(), Resource::BindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); if (mLights.size()) { - mpLightsBuffer = Buffer::createStructured(mpSceneBlock[kLightsBufferName], (uint32_t)mLights.size(), Resource::BindFlags::ShaderResource); + mpLightsBuffer = Buffer::createStructured(mpSceneBlock[kLightsBufferName], (uint32_t)mLights.size(), Resource::BindFlags::ShaderResource, Buffer::CpuAccess::None, nullptr, false); } } void Scene::uploadResources() { // Upload geometry - checkOffsets(); mpMeshesBuffer->setBlob(mMeshDesc.data(), 0, sizeof(MeshDesc) * mMeshDesc.size()); mpMeshInstancesBuffer->setBlob(mMeshInstanceData.data(), 0, sizeof(MeshInstanceData) * mMeshInstanceData.size()); @@ -204,6 +211,7 @@ namespace Falcor mpSceneBlock->setBuffer(kMaterialsBufferName, mpMaterialsBuffer); mpSceneBlock->setBuffer(kIndexBufferName, mpVao->getIndexBuffer()); mpSceneBlock->setBuffer(kVertexBufferName, mpVao->getVertexBuffer(Scene::kStaticDataBufferIndex)); + mpSceneBlock->setBuffer(kPrevVertexBufferName, mpVao->getVertexBuffer(Scene::kPrevVertexBufferIndex)); if (mpLightProbe) { @@ -236,29 +244,6 @@ namespace Falcor var["samplerState"] = resources.samplerState; } - void Scene::checkOffsets() - { -#if 0 // #SHADER_VAR fix this after we get rid of StructuredBuffer - // Reflector, Struct type, Member -#define assert_offset(_r, _s, _m) assert(_r->getOffsetDesc(offsetof(_s, _m)).type != ReflectionBasicType::Type::Unknown) - - // MeshDesc - auto pMeshReflector = mpMeshesBuffer->getBufferReflector(); - assert_offset(pMeshReflector, MeshDesc, vbOffset); - assert_offset(pMeshReflector, MeshDesc, ibOffset); - assert_offset(pMeshReflector, MeshDesc, vertexCount); - assert_offset(pMeshReflector, MeshDesc, indexCount); - assert_offset(pMeshReflector, MeshDesc, materialID); - - // MeshInstanceData - auto pInstanceReflector = mpMeshInstancesBuffer->getBufferReflector(); - assert_offset(pInstanceReflector, MeshInstanceData, meshID); - assert_offset(pInstanceReflector, MeshInstanceData, globalMatrixID); - -#undef assert_offset -#endif - } - void Scene::updateBounds() { const auto& globalMatrices = mpAnimationController->getGlobalMatrices(); @@ -268,7 +253,7 @@ namespace Falcor for (const auto& inst : mMeshInstanceData) { const BoundingBox& meshBB = mMeshBBs[inst.meshID]; - const mat4& transform = globalMatrices[inst.globalMatrixID]; + const glm::mat4& transform = globalMatrices[inst.globalMatrixID]; instanceBBs.push_back(meshBB.transform(transform)); } @@ -285,21 +270,14 @@ namespace Falcor { inst.flags = MeshInstanceFlags::None; - const mat4& transform = mpAnimationController->getGlobalMatrices()[inst.globalMatrixID]; + const glm::mat4& transform = mpAnimationController->getGlobalMatrices()[inst.globalMatrixID]; if (doesTransformFlip(transform)) inst.flags |= MeshInstanceFlags::Flipped; } } void Scene::finalize() { - // Create mapping of meshes to their instances. - mMeshIdToInstanceIds.clear(); - mMeshIdToInstanceIds.resize(mMeshDesc.size()); - for (uint32_t i = 0; i < (uint32_t)mMeshInstanceData.size(); i++) - { - mMeshIdToInstanceIds[mMeshInstanceData[i].meshID].push_back(i); - } - + sortMeshes(); initResources(); mpAnimationController->animate(gpDevice->getRenderContext(), 0); // Requires Scene block to exist updateMeshInstanceFlags(); @@ -312,7 +290,7 @@ namespace Falcor } setCameraController(mCamCtrlType); updateCamera(true); - saveNewViewpoint(); + addViewpoint(); updateLights(true); updateMaterials(true); uploadResources(); // Upload data after initialization is complete @@ -342,7 +320,7 @@ namespace Falcor } template<> - void Scene::AnimatedObject::setIntoObject(const vec3& pos, const vec3& up, const vec3& lookAt) + void Scene::AnimatedObject::setIntoObject(const float3& pos, const float3& up, const float3& lookAt) { pObject->setUpVector(up); pObject->setPosition(pos); @@ -350,7 +328,7 @@ namespace Falcor } template<> - void Scene::AnimatedObject::setIntoObject(const vec3& pos, const vec3& up, const vec3& lookAt) + void Scene::AnimatedObject::setIntoObject(const float3& pos, const float3& up, const float3& lookAt) { DirectionalLight* pDirLight = dynamic_cast(pObject.get()); if (pDirLight) @@ -380,10 +358,10 @@ namespace Falcor { if (!pAnimCtrl->didMatrixChanged(nodeID) && !force) return false; - mat4 camMat = pAnimCtrl->getGlobalMatrices()[nodeID]; - vec3 pos = vec3(camMat[3]); - vec3 up = vec3(camMat[1]); - vec3 lookAt = vec3(camMat[2]); + glm::mat4 camMat = pAnimCtrl->getGlobalMatrices()[nodeID]; + float3 pos = float3(camMat[3]); + float3 up = float3(camMat[1]); + float3 lookAt = float3(camMat[2]); setIntoObject(pos, up, lookAt); return true; } @@ -397,7 +375,7 @@ namespace Falcor auto cameraChanges = mCamera.pObject->beginFrame(); if (cameraChanges != Camera::Changes::None) { - mCamera.pObject->setShaderData(mpSceneBlock[kCameraVarName]); + mCamera.pObject->setShaderData(mpSceneBlock[kCamera]); if (is_set(cameraChanges, Camera::Changes::Movement)) flags |= UpdateFlags::CameraMoved; if ((cameraChanges & (~Camera::Changes::Movement)) != Camera::Changes::None) flags |= UpdateFlags::CameraPropertiesChanged; } @@ -408,16 +386,16 @@ namespace Falcor { UpdateFlags flags = UpdateFlags::None; - for (size_t i = 0 ; i < mLights.size() ; i++) + for (size_t i = 0; i < mLights.size(); i++) { - auto& l = mLights[i]; - l.update(mpAnimationController.get(), forceUpdate); - auto lightChanges = l.pObject->beginFrame(); + auto& light = mLights[i]; + light.update(mpAnimationController.get(), forceUpdate); + auto lightChanges = light.pObject->beginFrame(); if (lightChanges != Light::Changes::None) { // TODO: This is slow since the buffer is not CPU writable. Copy into CPU buffer and upload once instead. - mpLightsBuffer->setBlob(&l.pObject->getData(), sizeof(LightData) * i, sizeof(LightData)); + mpLightsBuffer->setBlob(&light.pObject->getData(), sizeof(LightData) * i, sizeof(LightData)); if (is_set(lightChanges, Light::Changes::Intensity)) flags |= UpdateFlags::LightIntensityChanged; if (is_set(lightChanges, Light::Changes::Position)) flags |= UpdateFlags::LightsMoved; if (is_set(lightChanges, Light::Changes::Direction)) flags |= UpdateFlags::LightsMoved; @@ -435,14 +413,14 @@ namespace Falcor // Early out if no materials have changed if (!forceUpdate && Material::getGlobalUpdates() == Material::UpdateFlags::None) return flags; - for (uint32_t i = 0; i < (uint32_t)mMaterials.size(); ++i) + for (uint32_t materialId = 0; materialId < (uint32_t)mMaterials.size(); ++materialId) { - auto& material = mMaterials[i]; + auto& material = mMaterials[materialId]; auto materialUpdates = material->getUpdates(); if (forceUpdate || materialUpdates != Material::UpdateFlags::None) { material->clearUpdates(); - uploadMaterial(i); + uploadMaterial(materialId); flags |= UpdateFlags::MaterialsChanged; } } @@ -498,15 +476,15 @@ namespace Falcor auto cameraGroup = Gui::Group(widget, "Camera"); if (cameraGroup.open()) { - if (cameraGroup.button("Save New Viewpoint")) saveNewViewpoint(); + if (cameraGroup.button("Save New Viewpoint")) addViewpoint(); Gui::DropdownList viewpoints; viewpoints.push_back({ 0, "Default Viewpoint" }); - for (uint32_t i = 1; i < mViewpoints.size(); i++) + for (uint32_t viewId = 1; viewId < (uint32_t)mViewpoints.size(); viewId++) { - viewpoints.push_back({ i, "Saved Viewpoint " + to_string(i) }); + viewpoints.push_back({ viewId, "Saved Viewpoint " + to_string(viewId) }); } uint32_t index = mCurrentViewpoint; - if (cameraGroup.dropdown("Saved Viewpoints", viewpoints, index)) gotoViewpoint(index); + if (cameraGroup.dropdown("Saved Viewpoints", viewpoints, index)) selectViewpoint(index); if (cameraGroup.button("Remove Current Viewpoint")) removeViewpoint(); if (cameraGroup.var("Camera Speed", mCameraSpeed, 0.f, FLT_MAX, 0.01f)) @@ -598,8 +576,8 @@ namespace Falcor { float radius = length(mSceneBB.extent); mCamera.pObject->setPosition(mSceneBB.center); - mCamera.pObject->setTarget(mSceneBB.center + vec3(0, 0, -1)); - mCamera.pObject->setUpVector(glm::vec3(0, 1, 0)); + mCamera.pObject->setTarget(mSceneBB.center + float3(0, 0, -1)); + mCamera.pObject->setUpVector(float3(0, 1, 0)); if(resetDepthRange) { @@ -609,15 +587,17 @@ namespace Falcor } } - void Scene::saveNewViewpoint() + void Scene::addViewpoint() { auto camera = getCamera(); - auto position = camera->getPosition(); - auto target = camera->getTarget(); - auto up = camera->getUpVector(); + addViewpoint(camera->getPosition(), camera->getTarget(), camera->getUpVector()); + } - Viewpoint v = { position, target, up }; - mViewpoints.push_back(v); + void Scene::addViewpoint(const float3& position, const float3& target, const float3& up) + { + Viewpoint viewpoint = { position, target, up }; + mViewpoints.push_back(viewpoint); + selectViewpoint(uint32_t(mViewpoints.size() - 1)); } void Scene::removeViewpoint() @@ -628,11 +608,17 @@ namespace Falcor return; } mViewpoints.erase(mViewpoints.begin() + mCurrentViewpoint); - mCurrentViewpoint = 0; + selectViewpoint(0); } - void Scene::gotoViewpoint(uint32_t index) + void Scene::selectViewpoint(uint32_t index) { + if (index >= mViewpoints.size()) + { + logWarning("Viewpoint does not exist"); + return; + } + auto camera = getCamera(); camera->setPosition(mViewpoints[index].position); camera->setTarget(mViewpoints[index].target); @@ -674,7 +660,7 @@ namespace Falcor { std::vector drawClockwiseMeshes, drawCounterClockwiseMeshes; auto pMatricesBuffer = mpSceneBlock->getBuffer("worldMatrices"); - const mat4* matrices = (mat4*)pMatricesBuffer->map(Buffer::MapType::Read); // #SCENEV2 This will cause the pipeline to flush and sync, but it's probably not too bad as this only happens once + const glm::mat4* matrices = (glm::mat4*)pMatricesBuffer->map(Buffer::MapType::Read); // #SCENEV2 This will cause the pipeline to flush and sync, but it's probably not too bad as this only happens once for (const auto& instance : mMeshInstanceData) { @@ -708,52 +694,109 @@ namespace Falcor assert(drawCount <= UINT32_MAX); } - void Scene::sortBlasMeshes() + void Scene::sortMeshes() { - // Of the non-instanced meshes, group based on what global matrix ID their transform is. + // We first sort meshes into groups with the same transform. + // The mesh instances list is then reordered to match this order. + // + // For ray tracing, we create one BLAS per mesh group and the mesh instances + // can therefore be directly indexed by [InstanceID() + GeometryIndex()]. + // This avoids the need to have a lookup table from hit IDs to mesh instance. + + // Build a list of mesh instance indices per mesh. + std::vector> instanceLists(mMeshDesc.size()); + for (size_t i = 0; i < mMeshInstanceData.size(); i++) + { + assert(mMeshInstanceData[i].meshID < instanceLists.size()); + instanceLists[mMeshInstanceData[i].meshID].push_back(i); + } + + // The non-instanced meshes are grouped based on what global matrix ID their transform is. std::unordered_map> nodeToMeshList; - for (uint32_t meshId = 0; meshId < (uint32_t)mMeshIdToInstanceIds.size(); meshId++) + for (uint32_t meshId = 0; meshId < (uint32_t)instanceLists.size(); meshId++) { - auto& instanceList = mMeshIdToInstanceIds[meshId]; + const auto& instanceList = instanceLists[meshId]; if (instanceList.size() > 1) continue; // Only processing non-instanced meshes here + assert(instanceList.size() == 1); uint32_t globalMatrixId = mMeshInstanceData[instanceList[0]].globalMatrixID; nodeToMeshList[globalMatrixId].push_back(meshId); } - // This should currently only be run on scene initialization - assert(mBlasData.empty()); + // Build final result. Format is a list of Mesh ID's per mesh group. - // Build final result. Format is a list of Mesh ID's per BLAS + // This should currently only be run on scene initialization. + assert(mMeshGroups.empty()); - // Non-instanced meshes were sorted above so just copy each list - for (auto& it : nodeToMeshList) mBlasData.push_back(it.second); + // Non-instanced meshes were sorted above so just copy each list. + for (const auto& it : nodeToMeshList) mMeshGroups.push_back({ it.second }); - // Meshes that have multiple instances go in their own BLAS - for (uint32_t meshId = 0; meshId < (uint32_t)mMeshIdToInstanceIds.size(); meshId++) + // Meshes that have multiple instances go in their own groups. + for (uint32_t meshId = 0; meshId < (uint32_t)instanceLists.size(); meshId++) { - auto& instanceList = mMeshIdToInstanceIds[meshId]; + const auto& instanceList = instanceLists[meshId]; if (instanceList.size() == 1) continue; // Only processing instanced meshes here - mBlasData.push_back(std::vector({ meshId })); + mMeshGroups.push_back({ std::vector({ meshId }) }); + } + + // Calculate mapping from new mesh instance ID to existing instance index. + // Here, just append existing instance ID's in order they appear in the mesh groups. + std::vector instanceMapping; + for (const auto& meshGroup : mMeshGroups) + { + for (const uint32_t meshId : meshGroup.meshList) + { + const auto& instanceList = instanceLists[meshId]; + for (size_t idx : instanceList) + { + instanceMapping.push_back(idx); + } + } + } + assert(instanceMapping.size() == mMeshInstanceData.size()); + { + // Check that all indices exist + std::set instanceIndices(instanceMapping.begin(), instanceMapping.end()); + assert(instanceIndices.size() == mMeshInstanceData.size()); + } + + // Now reorder mMeshInstanceData based on the new mapping. + // We'll make a copy of the existing data first, and the populate the array. + std::vector prevInstanceData = mMeshInstanceData; + for (size_t i = 0; i < mMeshInstanceData.size(); i++) + { + assert(instanceMapping[i] < prevInstanceData.size()); + mMeshInstanceData[i] = prevInstanceData[instanceMapping[i]]; + } + + // Create mapping of meshes to their instances. + mMeshIdToInstanceIds.clear(); + mMeshIdToInstanceIds.resize(mMeshDesc.size()); + for (uint32_t instId = 0; instId < (uint32_t)mMeshInstanceData.size(); instId++) + { + mMeshIdToInstanceIds[mMeshInstanceData[instId].meshID].push_back(instId); } } void Scene::initGeomDesc() { - sortBlasMeshes(); + assert(mBlasData.empty()); const VertexBufferLayout::SharedConstPtr& pVbLayout = mpVao->getVertexLayout()->getBufferLayout(kStaticDataBufferIndex); const Buffer::SharedPtr& pVb = mpVao->getVertexBuffer(kStaticDataBufferIndex); const Buffer::SharedPtr& pIb = mpVao->getIndexBuffer(); - for (uint32_t i = 0; i < (uint32_t)mBlasData.size(); i++) + assert(mMeshGroups.size() > 0); + mBlasData.resize(mMeshGroups.size()); + + for (size_t i = 0; i < mBlasData.size(); i++) { + const auto& meshList = mMeshGroups[i].meshList; auto& blas = mBlasData[i]; - auto& meshList = blas.meshList; auto& geomDescs = blas.geomDescs; geomDescs.resize(meshList.size()); - for (uint32_t j = 0; j < (uint32_t)meshList.size(); j++) + for (size_t j = 0; j < meshList.size(); j++) { const MeshDesc& mesh = mMeshDesc[meshList[j]]; blas.hasSkinnedMesh |= mMeshHasDynamicData[meshList[j]]; @@ -761,6 +804,7 @@ namespace Falcor D3D12_RAYTRACING_GEOMETRY_DESC& desc = geomDescs[j]; desc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; desc.Triangles.Transform3x4 = 0; + // If this is an opaque mesh, set the opaque flag const auto& material = mMaterials[mesh.materialID]; bool opaque = (material->getAlphaMode() == AlphaModeOpaque) && material->getSpecularTransmission() == 0.f; @@ -794,11 +838,8 @@ namespace Falcor pContext->resourceBarrier(pIb.get(), Resource::State::NonPixelShader); // For each BLAS - for (uint32_t i = 0; i < (uint32_t)mBlasData.size(); i++) + for (auto& blas : mBlasData) { - auto& blas = mBlasData[i]; - auto& meshList = blas.meshList; - if (blas.pBlas != nullptr && !blas.hasSkinnedMesh) continue; // Skip updating BLASes not containing skinned meshes // Setup build parameters and get prebuild info @@ -857,8 +898,6 @@ namespace Falcor if (!blas.hasSkinnedMesh) blas.pScratchBuffer.reset(); // Release else blas.updateMode = mBlasUpdateMode; } - - updateAsToInstanceDataMapping(); } void Scene::fillInstanceDesc(std::vector& instanceDescs, uint32_t rayCount, bool perMeshHitEntry) @@ -866,9 +905,11 @@ namespace Falcor instanceDescs.clear(); uint32_t instanceContributionToHitGroupIndex = 0; uint32_t instanceId = 0; - for (uint32_t i = 0; i < (uint32_t)mBlasData.size(); i++) + + for (size_t i = 0; i < mBlasData.size(); i++) { - auto& meshList = mBlasData[i].meshList; + const auto& meshList = mMeshGroups[i].meshList; + D3D12_RAYTRACING_INSTANCE_DESC desc = {}; desc.AccelerationStructure = mBlasData[i].pBlas->getGpuAddress(); desc.InstanceMask = 0xFF; @@ -877,16 +918,17 @@ namespace Falcor // If multiple meshes are in a BLAS: // - Their global matrix is the same. - // - From sortBlasMeshes(), each mesh in the BLAS is guaranteed to be non-instanced, so only one INSTANCE_DESC is needed + // - From sortMeshes(), each mesh in the BLAS is guaranteed to be non-instanced, so only one INSTANCE_DESC is needed if (meshList.size() > 1) { + assert(mMeshIdToInstanceIds[meshList[0]].size() == 1); + assert(mMeshIdToInstanceIds[meshList[0]][0] == instanceId); // Mesh instances are sorted by instanceId desc.InstanceID = instanceId; instanceId += (uint32_t)meshList.size(); // Any instances of the mesh will get you the correct matrix, so just pick the first mesh then the first instance. - uint32_t firstInstanceId = mMeshIdToInstanceIds[meshList[0]][0]; - uint32_t matrixId = mMeshInstanceData[firstInstanceId].globalMatrixID; - mat4 transform4x4 = transpose(mpAnimationController->getGlobalMatrices()[matrixId]); + uint32_t matrixId = mMeshInstanceData[desc.InstanceID].globalMatrixID; + glm::mat4 transform4x4 = transpose(mpAnimationController->getGlobalMatrices()[matrixId]); std::memcpy(desc.Transform, &transform4x4, sizeof(desc.Transform)); instanceDescs.push_back(desc); } @@ -895,13 +937,16 @@ namespace Falcor // - A mesh with multiple instances else { + assert(meshList.size() == 1); + const auto& instanceList = mMeshIdToInstanceIds[meshList[0]]; + // For every instance of the mesh, create an INSTANCE_DESC - auto& instanceList = mMeshIdToInstanceIds[meshList[0]]; for (uint32_t instId : instanceList) { + assert(instId == instanceId); // Mesh instances are sorted by instanceId desc.InstanceID = instanceId++; - uint32_t matrixId = mMeshInstanceData[instId].globalMatrixID; - mat4 transform4x4 = transpose(mpAnimationController->getGlobalMatrices()[matrixId]); + uint32_t matrixId = mMeshInstanceData[desc.InstanceID].globalMatrixID; + glm::mat4 transform4x4 = transpose(mpAnimationController->getGlobalMatrices()[matrixId]); std::memcpy(desc.Transform, &transform4x4, sizeof(desc.Transform)); instanceDescs.push_back(desc); } @@ -1004,42 +1049,26 @@ namespace Falcor mTlasCache[rayCount] = tlas; } - void Scene::updateAsToInstanceDataMapping() - { - // Calculate acceleration structure indexing to mMeshInstanceData index - // Essentially: mMeshInstanceData[ buffer[TLAS InstanceID() + GeometryIndex] ] - // Here, just append mesh instance ID's in order they'd appear in the TLAS. - std::vector asToInstanceMapping; - for (uint32_t blasIndex = 0; blasIndex < (uint32_t)mBlasData.size(); blasIndex++) - { - for (const uint32_t meshId : mBlasData[blasIndex].meshList) - { - auto& instList = mMeshIdToInstanceIds[meshId]; - for (const uint32_t instId : instList) - { - asToInstanceMapping.push_back(instId); - } - } - } - - mpAsToInstanceMapping = Buffer::createTyped((uint32_t)asToInstanceMapping.size(), Resource::BindFlags::ShaderResource, Buffer::CpuAccess::None, asToInstanceMapping.data()); - } - void Scene::setGeometryIndexIntoRtVars(const std::shared_ptr& pVars) { + // Sets the 'geometryIndex' hit shader variable for each mesh. + // This is the local index of which mesh in the BLAS was hit. + // In DXR 1.0 we have to pass it via a constant buffer to the shader, + // in DXR 1.1 it is available through the GeometryIndex() system value. + // assert(!mBlasData.empty()); - auto meshCount = getMeshCount(); + uint32_t meshCount = getMeshCount(); uint32_t descHitCount = pVars->getDescHitGroupCount(); uint32_t blasIndex = 0; uint32_t geometryIndex = 0; - for (uint32_t i = 0; i < meshCount; i++) + for (uint32_t meshId = 0; meshId < meshCount; meshId++) { for (uint32_t hit = 0; hit < descHitCount; hit++) { - auto pHitVars = pVars->getHitVars(hit, i); + auto pHitVars = pVars->getHitVars(hit, meshId); auto var = pHitVars->findMember(0).findMember("geometryIndex"); - if( var.isValid() ) + if (var.isValid()) { var = geometryIndex; } @@ -1048,7 +1077,7 @@ namespace Falcor geometryIndex++; // If at the end of this BLAS, reset counters and start checking next BLAS - uint32_t geomCount = (uint32_t)mBlasData[blasIndex].meshList.size(); + uint32_t geomCount = (uint32_t)mMeshGroups[blasIndex].meshList.size(); if (geometryIndex == geomCount) { geometryIndex = 0; @@ -1064,12 +1093,11 @@ namespace Falcor { initGeomDesc(); buildBlas(pContext); - updateAsToInstanceDataMapping(); } // On first execution, when meshes have moved, when there's a new ray count, or when a BLAS has changed, create/update the TLAS // - // TODO: The notion of "ray count" is being treated as fundamental here, and intrinsicly + // TODO: The notion of "ray count" is being treated as fundamental here, and intrinsically // linked to the number of hit groups in the program, without checking if this matches // other things like the number of miss shaders. If/when we support meshes with custom // intersection shaders, then the assumption that number of ray types and number of @@ -1088,14 +1116,11 @@ namespace Falcor } // Bind Scene parameter block. - mCamera.pObject->setShaderData(mpSceneBlock[kCameraVarName]); + mCamera.pObject->setShaderData(mpSceneBlock[kCamera]); var["gScene"] = mpSceneBlock; // Bind TLAS. var["gRtScene"].setSrv(tlasIt->second.pSrv); - - // Bind lookup table for mesh instance ID. - var["gAsToInstance"] = mpAsToInstanceMapping; } void Scene::setEnvironmentMap(Texture::ConstSharedPtrRef pEnvMap) @@ -1105,6 +1130,12 @@ namespace Falcor mpSceneBlock["envMap"] = mpEnvMap; } + void Scene::loadEnvironmentMap(const std::string& filename) + { + Texture::SharedPtr pEnvMap = Texture::createFromFile(filename, false, true); + setEnvironmentMap(pEnvMap); + } + void Scene::setCameraAspectRatio(float ratio) { mCamera.pObject->setAspectRatio(ratio); @@ -1153,7 +1184,7 @@ namespace Falcor { if (keyEvent.key == KeyboardEvent::Key::F3) { - saveNewViewpoint(); + addViewpoint(); return true; } } @@ -1161,36 +1192,56 @@ namespace Falcor return mpCamCtrl->onKeyEvent(keyEvent); } - std::string Scene::getConfig() + std::string Scene::getScript(const std::string& sceneVar) { std::string c; - c += std::string(kCamera) + " = " + Scripting::makeMemberFunc(kScene, kCameraVarName); - for (int i = 0; i < mViewpoints.size(); i++) + + // Environment map. + if (getEnvironmentMap() != nullptr) + { + c += Scripting::makeMemberFunc(sceneVar, kSetEnvMap, Scripting::getFilenameString(getEnvironmentMap()->getSourceFilename())); + } + + // Viewpoints. + if (hasSavedViewpoints()) { - if (i == 0) continue; - auto v = mViewpoints[i]; - c += std::string(kCamera) + "." + kPosition + "=" + to_string(v.position) + "\n"; - c += std::string(kCamera) + "." + kTarget + "=" + to_string(v.target) + "\n"; - c += std::string(kCamera) + "." + kUp + "=" + to_string(v.up) + "\n"; - c += Scripting::makeMemberFunc(kScene, kViewpoint); + for (size_t i = 1; i < mViewpoints.size(); i++) + { + auto v = mViewpoints[i]; + c += Scripting::makeMemberFunc(sceneVar, kAddViewpoint, v.position, v.target, v.up); + } + c += Scripting::makeMemberFunc(sceneVar, kSelectViewpoint, mCurrentViewpoint); } - c += Scripting::makeMemberFunc(kScene, kViewpoint, 0); + return c; } SCRIPT_BINDING(Scene) { auto s = m.regClass(Scene); - s.func_("animate", &Scene::toggleAnimations); // toggle animations on or off - s.func_("light", &Scene::getLight); // get specific light - s.func_("light", &Scene::getLightByName); // get specific light - s.func_("animateLight", &Scene::toggleLightAnimation); // toggle animation for a specific light on or off - s.func_("material", &Scene::getMaterial); // get specific material - s.func_("material", &Scene::getMaterialByName); // get specific material - s.func_("camera", &Scene::getCamera); // get camera - s.func_("animateCamera", &Scene::toggleCameraAnimation); // toggle camera animation on or off - s.func_("viewpoint", &Scene::saveNewViewpoint); // save the current camera position etc. - s.func_("viewpoint", &Scene::gotoViewpoint); // select a previously saved camera viewpoint - s.func_("removeViewpoint", &Scene::removeViewpoint); // remove the current camera viewpoint + s.roProperty(kCamera.c_str(), &Scene::getCamera); + + s.func_("animate", &Scene::toggleAnimations, "animate"_a); // toggle animations on or off + s.func_("animateCamera", &Scene::toggleCameraAnimation, "animate"_a); // toggle camera animation on or off + s.func_("animateLight", &Scene::toggleLightAnimation, "index"_a, "animate"_a); // toggle animation for a specific light on or off + + s.func_(kSetEnvMap.c_str(), &Scene::loadEnvironmentMap, "filename"_a); + s.func_(kGetLight.c_str(), &Scene::getLight, "index"_a); + s.func_(kGetLight.c_str(), &Scene::getLightByName, "name"_a); + s.func_("light", &Scene::getLight); // PYTHONDEPRECATED + s.func_("light", &Scene::getLightByName); // PYTHONDEPRECATED + s.func_(kGetMaterial.c_str(), &Scene::getMaterial, "index"_a); + s.func_(kGetMaterial.c_str(), &Scene::getMaterialByName, "name"_a); + s.func_("material", &Scene::getMaterial); // PYTHONDEPRECATED + s.func_("material", &Scene::getMaterialByName); // PYTHONDEPRECATED + + // Viewpoints + s.func_(kAddViewpoint.c_str(), ScriptBindings::overload_cast<>(&Scene::addViewpoint)); // add current camera as viewpoint + s.func_(kAddViewpoint.c_str(), ScriptBindings::overload_cast(&Scene::addViewpoint), "position"_a, "target"_a, "up"_a); // add specified viewpoint + s.func_(kRemoveViewpoint.c_str(), &Scene::removeViewpoint); // remove the selected viewpoint + s.func_(kSelectViewpoint.c_str(), &Scene::selectViewpoint, "index"_a); // select a viewpoint by index + + s.func_("viewpoint", ScriptBindings::overload_cast<>(&Scene::addViewpoint)); // PYTHONDEPRECATED save the current camera position etc. + s.func_("viewpoint", ScriptBindings::overload_cast(&Scene::selectViewpoint)); // PYTHONDEPRECATED select a previously saved camera viewpoint } } diff --git a/Source/Falcor/Scene/Scene.h b/Source/Falcor/Scene/Scene.h index 669317c1d..3c5256638 100644 --- a/Source/Falcor/Scene/Scene.h +++ b/Source/Falcor/Scene/Scene.h @@ -66,13 +66,10 @@ namespace Falcor | | one BLAS | per mesh | of a mesh | --------------------------------------------------------------------------------------| - - updateAsToInstanceDataMapping() creates a lookup table that translates "InstanceID() + GeometryIndex()" to the Global Hit ID, which is an index into MeshInstanceData. - - Mesh instance ID = LookupTable[InstanceID() + GeometryIndex()] + - "InstanceID() + GeometryIndex()" is used for indexing into MeshInstanceData. - This is wrapped in getGlobalHitID() in Raytracing.slang. */ - constexpr char kScene[] = "s"; - class dlldecl Scene : public std::enable_shared_from_this { public: @@ -165,17 +162,27 @@ namespace Falcor */ float getCameraSpeed() const { return mCameraSpeed; } - /** Save the current camera viewpoint and returns a reference to it. + /** Add the current camera's viewpoint to the list of viewpoints. + */ + void addViewpoint(); + + deprecate("4.0.1", "Use addViewpoint() instead.") + void saveNewViewpoint() { addViewpoint(); } + + /** Add a new viewpoint to the list of viewpoints. */ - void saveNewViewpoint(); + void addViewpoint(const float3& position, const float3& target, const float3& up); /** Remove the currently active viewpoint. */ void removeViewpoint(); - /** Load a selected camera viewpoint and returns a reference to it. + /** Select a viewpoint and move the camera to it. */ - void gotoViewpoint(uint32_t index); + void selectViewpoint(uint32_t index); + + deprecate("4.0.1", "Use selectViewpoint() instead.") + void gotoViewpoint(uint32_t index) { selectViewpoint(index); } /** Returns true if there are saved viewpoints (used for dumping to config) */ @@ -274,7 +281,7 @@ namespace Falcor /** Render the scene using raytracing */ - void raytrace(RenderContext* pContext, RtProgram* pProgram, const std::shared_ptr& pVars, uvec3 dispatchDims); + void raytrace(RenderContext* pContext, RtProgram* pProgram, const std::shared_ptr& pVars, uint3 dispatchDims); /** Render the UI */ @@ -293,6 +300,11 @@ namespace Falcor */ void setEnvironmentMap(Texture::ConstSharedPtrRef pEnvMap); + /** Load an environment from an image. + \param[in] filename Texture filename. + */ + void loadEnvironmentMap(const std::string& filename); + /** Get the environment map */ Texture::ConstSharedPtrRef getEnvironmentMap() const { return mpEnvMap; } @@ -335,14 +347,15 @@ namespace Falcor */ void setRaytracingShaderData(RenderContext* pContext, const ShaderVar& var, uint32_t rayTypeCount = 1); - std::string getConfig(); + std::string getScript(const std::string& sceneVar); private: friend class SceneBuilder; friend class AnimationController; static constexpr uint32_t kStaticDataBufferIndex = 0; - static constexpr uint32_t kDrawIdBufferIndex = kStaticDataBufferIndex + 1; + static constexpr uint32_t kPrevVertexBufferIndex = kStaticDataBufferIndex + 1; + static constexpr uint32_t kDrawIdBufferIndex = kPrevVertexBufferIndex + 1; static constexpr uint32_t kVertexBufferCount = kDrawIdBufferIndex + 1; static SharedPtr create(); @@ -359,10 +372,6 @@ namespace Falcor */ void uploadMaterial(uint32_t materialID); - /** Verify variable offsets in GPU buffers are consistent with CPU data. - */ - void checkOffsets(); - /** Update the scene's global bounding box. */ void updateBounds(); @@ -379,9 +388,9 @@ namespace Falcor */ void createDrawList(); - /** Sort what meshes go in what BLAS. Results stored in mBlasBuckets. + /** Sort meshes into groups by transform. Updates mMeshInstances and mMeshGroups. */ - void sortBlasMeshes(); + void sortMeshes(); /** Initialize geometry descs for each BLAS */ @@ -401,11 +410,6 @@ namespace Falcor */ void buildTlas(RenderContext* pContext, uint32_t rayCount, bool perMeshHitEntry); - /** Create the buffer that maps Acceleration Structure indices to their location in mMeshInstanceData - mMeshInstanceData should be indexed with [InstanceID() + GeometryIndex] - */ - void updateAsToInstanceDataMapping(); - UpdateFlags updateCamera(bool forceUpdate); UpdateFlags updateLights(bool forceUpdate); UpdateFlags updateMaterials(bool forceUpdate); @@ -425,10 +429,10 @@ namespace Falcor { typename Object::SharedPtr pObject; bool animate = true; - size_t nodeID = kInvalidNode; + uint32_t nodeID = kInvalidNode; bool update(const AnimationController* pAnimCtrl, bool force); bool hasGlobalTransform() const { return nodeID != kInvalidNode; } - void setIntoObject(const vec3& pos, const vec3& up, const vec3& lookAt); + void setIntoObject(const float3& pos, const float3& up, const float3& lookAt); bool enabled(bool force) const; }; @@ -447,16 +451,22 @@ namespace Falcor struct Node { Node() = default; - Node(const std::string& n, uint32_t p, const mat4& t, const mat4& l2b) : parent(p), name(n), transform(t), localToBindSpace(l2b) {}; + Node(const std::string& n, uint32_t p, const glm::mat4& t, const glm::mat4& l2b) : parent(p), name(n), transform(t), localToBindSpace(l2b) {}; std::string name; uint32_t parent = kInvalidNode; - mat4 transform; // The node's transformation matrix - mat4 localToBindSpace; // Local to bind space transformation + glm::mat4 transform; // The node's transformation matrix + glm::mat4 localToBindSpace; // Local to bind space transformation + }; + + struct MeshGroup + { + std::vector meshList; ///< List of meshId's that are part of the group. }; // #SCENE We don't need those vectors on the host std::vector mMeshDesc; ///< Copy of GPU buffer (mpMeshes) std::vector mMeshInstanceData; ///< Copy of GPU buffer (mpMeshInstances) + std::vector mMeshGroups; ///< Groups of meshes with identical transforms. Each group maps to a BLAS for ray tracing. std::vector mSceneGraph; ///< For each index i, the array element indicates the parent node. Indices are in relation to mLocalToWorldMatrices std::vector mMaterials; ///< Bound to parameter block @@ -488,9 +498,9 @@ namespace Falcor // Saved Camera Viewpoints struct Viewpoint { - glm::vec3 position; - glm::vec3 target; - glm::vec3 up; + float3 position; + float3 target; + float3 up; }; std::vector mViewpoints; uint32_t mCurrentViewpoint = 0; @@ -521,14 +531,11 @@ namespace Falcor struct BlasData { - BlasData(const std::vector& meshList) : meshList(meshList) {} - Buffer::SharedPtr pBlas; Buffer::SharedPtr pScratchBuffer; D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuildInfo; std::vector geomDescs; - std::vector meshList; ///< List of meshId's that are part of each BLAS bool hasSkinnedMesh = false; ///< Whether the BLAS contains a skinned mesh, which means the BLAS may need to be updated UpdateMode updateMode = UpdateMode::Refit; ///< Update mode this BLAS was created with. }; @@ -536,7 +543,6 @@ namespace Falcor std::vector mBlasData; ///< All data related to the scene's BLASes bool mHasSkinnedMesh = false; ///< Whether the scene has a skinned mesh at all. - Buffer::SharedPtr mpAsToInstanceMapping; ///< Lookup table from [InstanceID() + GeometryIndex()] to mMeshInstanceData index std::string mFilename; }; diff --git a/Source/Falcor/Scene/Scene.slang b/Source/Falcor/Scene/Scene.slang index 86c8fb363..8c7cdd72f 100644 --- a/Source/Falcor/Scene/Scene.slang +++ b/Source/Falcor/Scene/Scene.slang @@ -33,16 +33,11 @@ __exported import Scene.Lights.LightData; __exported import Scene.Lights.LightProbeData; __exported import Scene.Material.MaterialData; +import HitInfo; import TextureSampler; +import Utils.Attributes; import Experimental.Scene.Lights.LightCollection; - -// Local stuff -struct LocalMesh -{ - uint meshID; - uint meshInstanceID; - uint materialID; -}; +import Experimental.Scene.Material.TexLODHelpers; #ifndef MATERIAL_COUNT // This error occurs when a shader imports Scene.slang without setting the defines @@ -54,27 +49,32 @@ struct LocalMesh */ struct Scene { - StructuredBuffer meshInstances; + // Geometry + [root] StructuredBuffer meshInstances; StructuredBuffer meshes; - StructuredBuffer materials; - StructuredBuffer lights; - Buffer worldMatrices; - Buffer inverseTransposeWorldMatrices; // #SCENEV2 Should this be 3x3? - Buffer previousFrameWorldMatrices; + [root] StructuredBuffer worldMatrices; + [root] StructuredBuffer inverseTransposeWorldMatrices; // TODO: Make this 3x3 matrices (stored as 4x3). See #795. + StructuredBuffer previousFrameWorldMatrices; + + [root] StructuredBuffer vertices; ///< Vertex data for this frame. + StructuredBuffer prevVertices; ///< Vertex data for the previous frame, to handle skinned meshes. + [root] ByteAddressBuffer indices; ///< Vertex indices, three 32-bit indices per triangle packed tightly. + + // Materials + StructuredBuffer materials; MaterialResources materialResources[MATERIAL_COUNT]; + + // Lights and camera + StructuredBuffer lights; LightCollection lightCollection; LightProbeData lightProbe; - Camera camera; Texture2D envMap; + Camera camera; - StructuredBuffer vertices; - ByteAddressBuffer indices; - float4x4 getWorldMatrix(uint meshInstanceID) + float4x4 loadWorldMatrix(uint matrixID) { - uint matrixID = meshInstances[meshInstanceID].globalMatrixID; - float4x4 m = { worldMatrices[matrixID * 4 + 0], @@ -83,21 +83,29 @@ struct Scene worldMatrices[matrixID * 4 + 3] }; return m; - }; + } - float4x4 getInverseTransposeWorldMatrix(uint meshInstanceID) + float4x4 getWorldMatrix(uint meshInstanceID) { uint matrixID = meshInstances[meshInstanceID].globalMatrixID; + return loadWorldMatrix(matrixID); + }; - float4x4 m = + float3x3 loadInverseTransposeWorldMatrix(uint matrixID) + { + float3x3 m = { - inverseTransposeWorldMatrices[matrixID * 4 + 0], - inverseTransposeWorldMatrices[matrixID * 4 + 1], - inverseTransposeWorldMatrices[matrixID * 4 + 2], - inverseTransposeWorldMatrices[matrixID * 4 + 3] + inverseTransposeWorldMatrices[matrixID * 4 + 0].xyz, + inverseTransposeWorldMatrices[matrixID * 4 + 1].xyz, + inverseTransposeWorldMatrices[matrixID * 4 + 2].xyz }; - return m; + } + + float3x3 getInverseTransposeWorldMatrix(uint meshInstanceID) + { + uint matrixID = meshInstances[meshInstanceID].globalMatrixID; + return loadInverseTransposeWorldMatrix(matrixID); }; float4x4 getPrevWorldMatrix(uint meshInstanceID) @@ -124,6 +132,16 @@ struct Scene return MATERIAL_COUNT; } + MaterialData getMaterial(uint materialID) + { + return materials[materialID]; + } + + MeshInstanceData getMeshInstance(uint meshInstanceID) + { + return meshInstances[meshInstanceID]; + } + MeshDesc getMeshDesc(uint meshInstanceID) { return meshes[meshInstances[meshInstanceID].meshID]; @@ -156,12 +174,21 @@ struct Scene */ uint3 getIndices(uint meshInstanceID, uint triangleIndex) { - uint baseIndex = getMeshDesc(meshInstanceID).ibOffset + (triangleIndex * 3); + uint baseIndex = meshInstances[meshInstanceID].ibOffset + (triangleIndex * 3); uint3 vtxIndices = indices.Load3(baseIndex * 4); - vtxIndices += getMeshDesc(meshInstanceID).vbOffset; + vtxIndices += meshInstances[meshInstanceID].vbOffset; return vtxIndices; } + /** Returns vertex data for a vertex. + \param[in] index Global vertex index. + \return Vertex data. + */ + StaticVertexData getVertex(uint index) + { + return vertices[index].unpack(); + } + /** Returns a triangle's face normal in object space. \param[in] vtxIndices Indices into the scene's global vertex buffer. \param[out] Face normal in object space (normalized). Front facing for counter-clockwise winding. @@ -186,7 +213,7 @@ struct Scene float3 p1 = vertices[vtxIndices[1]].position; float3 p2 = vertices[vtxIndices[2]].position; float3 N = cross(p1 - p0, p2 - p0); - float3x3 worldInvTransposeMat = (float3x3) getInverseTransposeWorldMatrix(meshInstanceID); + float3x3 worldInvTransposeMat = getInverseTransposeWorldMatrix(meshInstanceID); return normalize(mul(N, worldInvTransposeMat)); } @@ -259,46 +286,121 @@ struct Scene const uint3 vtxIndices = getIndices(meshInstanceID, triangleIndex); VertexData v = {}; - // Note: dxcompiler.dll version 10.0.18362.1 gives validation errors when [unroll] is specified. - // We'll unroll it manually below instead. TODO: Clean this up when unroll works as expected. - //[unroll] - //for (int i = 0; i < 3; i++) - //{ - // v.posW += vertices[vtxIndices[i]].position * barycentrics[i]; - // v.normalW += vertices[vtxIndices[i]].normal * barycentrics[i]; - // v.bitangentW += vertices[vtxIndices[i]].bitangent * barycentrics[i]; - // v.texC += vertices[vtxIndices[i]].texCrd * barycentrics[i]; - //} - v.posW += vertices[vtxIndices[0]].position * barycentrics[0]; - v.posW += vertices[vtxIndices[1]].position * barycentrics[1]; - v.posW += vertices[vtxIndices[2]].position * barycentrics[2]; - - v.normalW += vertices[vtxIndices[0]].normal * barycentrics[0]; - v.normalW += vertices[vtxIndices[1]].normal * barycentrics[1]; - v.normalW += vertices[vtxIndices[2]].normal * barycentrics[2]; - - v.bitangentW += vertices[vtxIndices[0]].bitangent * barycentrics[0]; - v.bitangentW += vertices[vtxIndices[1]].bitangent * barycentrics[1]; - v.bitangentW += vertices[vtxIndices[2]].bitangent * barycentrics[2]; - - v.texC += vertices[vtxIndices[0]].texCrd * barycentrics[0]; - v.texC += vertices[vtxIndices[1]].texCrd * barycentrics[1]; - v.texC += vertices[vtxIndices[2]].texCrd * barycentrics[2]; + StaticVertexData vtx[3] = { gScene.getVertex(vtxIndices[0]), gScene.getVertex(vtxIndices[1]), gScene.getVertex(vtxIndices[2]) }; + + v.posW += vtx[0].position * barycentrics[0]; + v.posW += vtx[1].position * barycentrics[1]; + v.posW += vtx[2].position * barycentrics[2]; + + v.normalW += vtx[0].normal * barycentrics[0]; + v.normalW += vtx[1].normal * barycentrics[1]; + v.normalW += vtx[2].normal * barycentrics[2]; + + v.bitangentW += vtx[0].bitangent * barycentrics[0]; + v.bitangentW += vtx[1].bitangent * barycentrics[1]; + v.bitangentW += vtx[2].bitangent * barycentrics[2]; + + v.texC += vtx[0].texCrd * barycentrics[0]; + v.texC += vtx[1].texCrd * barycentrics[1]; + v.texC += vtx[2].texCrd * barycentrics[2]; v.faceNormalW = getFaceNormalInObjectSpace(vtxIndices); float4x4 worldMat = getWorldMatrix(meshInstanceID); - float3x3 worldInvTransposeMat = (float3x3) getInverseTransposeWorldMatrix(meshInstanceID); + float3x3 worldInvTransposeMat = getInverseTransposeWorldMatrix(meshInstanceID); v.posW = mul(float4(v.posW, 1.f), worldMat).xyz; - v.normalW = mul(v.normalW, worldInvTransposeMat).xyz; - v.faceNormalW = mul(v.faceNormalW, worldInvTransposeMat).xyz; - v.bitangentW = mul(v.bitangentW, (float3x3)worldMat).xyz; + v.normalW = mul(v.normalW, worldInvTransposeMat); + v.faceNormalW = mul(v.faceNormalW, worldInvTransposeMat); + v.bitangentW = mul(v.bitangentW, (float3x3)worldMat); v.normalW = normalize(v.normalW); v.faceNormalW = normalize(v.faceNormalW); // Handle invalid bitangents gracefully (avoid NaN from normalization). v.bitangentW = dot(v.bitangentW, v.bitangentW) > 0.f ? normalize(v.bitangentW) : float3(0, 0, 0); + return v; + } + + /** Returns the interpolated vertex attributes for a given hitpoint. + \param[in] hit Hit info. + \return Interpolated vertex attributes. + */ + VertexData getVertexData(HitInfo hit) + { + return getVertexData(hit.meshInstanceID, hit.primitiveIndex, hit.getBarycentricWeights()); + } + + /** Returns interpolated vertex attributes in a ray tracing hit program when ray cones are used for texture LOD. + \param[in] meshInstanceID The mesh instance ID. + \param[in] triangleIndex Index of the triangle in the given mesh. + \param[in] barycentrics Barycentric coordinates in the triangle. + \return Interpolated vertex attributes. + */ + VertexData getVertexDataRayCones(uint meshInstanceID, uint triangleIndex, float3 barycentrics) + { + const uint3 vtxIndices = getIndices(meshInstanceID, triangleIndex); + VertexData v = getVertexData(meshInstanceID, triangleIndex, barycentrics); + + float2 txcoords[3]; + float3 vtxs[3]; + txcoords[0] = vertices[vtxIndices[0]].texCrd; + txcoords[1] = vertices[vtxIndices[1]].texCrd; + txcoords[2] = vertices[vtxIndices[2]].texCrd; + vtxs[0] = vertices[vtxIndices[0]].position; + vtxs[1] = vertices[vtxIndices[1]].position; + vtxs[2] = vertices[vtxIndices[2]].position; + + float4x4 worldMat = getWorldMatrix(meshInstanceID); + v.coneTexLODValue = computeRayConeTriangleLODValue(vtxs, txcoords, float3x3(worldMat), v.faceNormalW); + + return v; + } + + /** Returns interpolated vertex attributes in a ray tracing hit program when ray differentials are used for texture LOD. + \param[in] meshInstanceID The mesh instance ID. + \param[in] triangleIndex Index of the triangle in the given mesh. + \param[in] barycentrics Barycentric coordinates in the triangle. + \param[in] rayDir Ray direction. + \param[in] hitT Distance to hit point. + \param[in,out] rayDiff The ray differential used as input and output. + \param[out] dUVdx The differential of the texture coordinates in pixel coordinate x. + \param[out] dUVdy The differential of the texture coordinates in pixel coordinate y. + \return Interpolated vertex attributes. + */ + VertexData getVertexDataRayDiff(uint meshInstanceID, uint triangleIndex, float3 barycentrics, in float3 rayDir, in float hitT, + inout RayDiff rayDiff, out float2 dUVdx, out float2 dUVdy) + { + const uint3 vtxIndices = getIndices(meshInstanceID, triangleIndex); + VertexData v = getVertexData(meshInstanceID, triangleIndex, barycentrics); + + float3 unnormalizedN; + float3 vtxs[3]; + float3 normals[3]; + float2 txcoords[3]; + float2 dBarydx, dBarydy; + float4x4 worldMat = getWorldMatrix(meshInstanceID); + float3x3 worldInvTransposeMat = getInverseTransposeWorldMatrix(meshInstanceID); + + StaticVertexData vtx[3] = { gScene.getVertex(vtxIndices[0]), gScene.getVertex(vtxIndices[1]), gScene.getVertex(vtxIndices[2]) }; + + vtxs[0] = mul(float4(vtx[0].position, 1.0), worldMat).xyz; + vtxs[1] = mul(float4(vtx[1].position, 1.0), worldMat).xyz; + vtxs[2] = mul(float4(vtx[2].position, 1.0), worldMat).xyz; + normals[0] = normalize(mul(vtx[0].normal, worldInvTransposeMat)); + normals[1] = normalize(mul(vtx[1].normal, worldInvTransposeMat)); + normals[2] = normalize(mul(vtx[2].normal, worldInvTransposeMat)); + txcoords[0] = vtx[0].texCrd; + txcoords[1] = vtx[1].texCrd; + txcoords[2] = vtx[2].texCrd; + + unnormalizedN = normals[0] * barycentrics[0]; + unnormalizedN += normals[1] * barycentrics[1]; + unnormalizedN += normals[2] * barycentrics[2]; + + float3 e1 = vtxs[1] - vtxs[0]; + float3 e2 = vtxs[2] - vtxs[0]; + computeDifferentialsBarysAndUVs(rayDiff, rayDir, vtxs, txcoords, e1, e2, v.faceNormalW, hitT, dBarydx, dBarydy, dUVdx, dUVdy); + reflectRayDifferential(rayDiff, rayDir, unnormalizedN, v.normalW, dBarydx, dBarydy, e1, e2, normals); return v; } @@ -317,7 +419,7 @@ struct Scene [unroll] for (int i = 0; i < 3; i++) { - prevPos += vertices[vtxIndices[i]].prevPosition * barycentrics[i]; + prevPos += prevVertices[vtxIndices[i]].position * barycentrics[i]; } float4x4 prevWorldMat = getPrevWorldMatrix(meshInstanceID); diff --git a/Source/Falcor/Scene/SceneBuilder.cpp b/Source/Falcor/Scene/SceneBuilder.cpp index f17e42fa4..82ef72952 100644 --- a/Source/Falcor/Scene/SceneBuilder.cpp +++ b/Source/Falcor/Scene/SceneBuilder.cpp @@ -37,12 +37,12 @@ namespace Falcor class MikkTSpaceWrapper { public: - static std::vector generateBitangents(const vec3* pPositions, const vec3* pNormals, const vec2* pTexCrd, const uint32_t* pIndices, size_t vertexCount, size_t indexCount) + static std::vector generateBitangents(const float3* pPositions, const float3* pNormals, const float2* pTexCrd, const uint32_t* pIndices, size_t vertexCount, size_t indexCount) { if (!pNormals || !pPositions || !pTexCrd || !pIndices) { logWarning("Can't generate tangent space. The mesh doesn't have positions/normals/texCrd/indices"); - return std::vector(vertexCount, vec3(0, 0, 0)); + return std::vector(vertexCount, float3(0, 0, 0)); } SMikkTSpaceInterface mikktspace = {}; @@ -61,40 +61,40 @@ namespace Falcor if (genTangSpaceDefault(&context) == false) { logError("Failed to generate MikkTSpace tangents"); - return std::vector(vertexCount, vec3(0, 0, 0)); + return std::vector(vertexCount, float3(0, 0, 0)); } return wrapper.mBitangents; } private: - MikkTSpaceWrapper(const vec3* pPositions, const vec3* pNormals, const vec2* pTexCrd, const uint32_t* pIndices, size_t vertexCount, size_t indexCount) : + MikkTSpaceWrapper(const float3* pPositions, const float3* pNormals, const float2* pTexCrd, const uint32_t* pIndices, size_t vertexCount, size_t indexCount) : mpPositions(pPositions), mpNormals(pNormals), mpTexCrd(pTexCrd), mpIndices(pIndices), mFaceCount(indexCount / 3), mBitangents(vertexCount) {} - const vec3* mpPositions; - const vec3* mpNormals; - const vec2* mpTexCrd; + const float3* mpPositions; + const float3* mpNormals; + const float2* mpTexCrd; const uint32_t* mpIndices; size_t mFaceCount; - std::vector mBitangents; + std::vector mBitangents; int32_t getFaceCount() const { return (int32_t)mFaceCount; } int32_t getIndex(int32_t face, int32_t vert) { return mpIndices[face * 3 + vert]; } - void getPosition(float position[], int32_t face, int32_t vert) { *(vec3*)position = mpPositions[getIndex(face, vert)]; } - void getNormal(float normal[], int32_t face, int32_t vert) { *(vec3*)normal = mpNormals[getIndex(face, vert)]; } - void getTexCrd(float texCrd[], int32_t face, int32_t vert) { *(vec2*)texCrd = mpTexCrd[getIndex(face, vert)]; } + void getPosition(float position[], int32_t face, int32_t vert) { *(float3*)position = mpPositions[getIndex(face, vert)]; } + void getNormal(float normal[], int32_t face, int32_t vert) { *(float3*)normal = mpNormals[getIndex(face, vert)]; } + void getTexCrd(float texCrd[], int32_t face, int32_t vert) { *(float2*)texCrd = mpTexCrd[getIndex(face, vert)]; } void setTangent(const float tangent[], float sign, int32_t face, int32_t vert) { int32_t index = getIndex(face, vert); - vec3 T(*(vec3*)tangent), N; + float3 T(*(float3*)tangent), N; getNormal(&N[0], face, vert); // bitangent = fSign * cross(vN, tangent); mBitangents[index] = cross(N, T); // Not using fSign because... I don't know why. It flips the tangent space. Need to go read the paper } }; - void validateTangentSpace(const vec3 bitangents[], uint32_t vertexCount) + void validateTangentSpace(const float3 bitangents[], uint32_t vertexCount) { - auto isValid = [](const vec3& bitangent) + auto isValid = [](const float3& bitangent) { if (glm::any(glm::isinf(bitangent) || glm::isnan(bitangent))) return false; if (length(bitangent) < 1e-6f) return false; @@ -146,29 +146,28 @@ namespace Falcor return success; } - size_t SceneBuilder::addNode(const Node& node) + uint32_t SceneBuilder::addNode(const Node& node) { assert(node.parent == kInvalidNode || node.parent < mSceneGraph.size()); - size_t newNodeID = mSceneGraph.size(); - assert(newNodeID <= UINT32_MAX); + assert(mSceneGraph.size() <= UINT32_MAX); + uint32_t newNodeID = (uint32_t)mSceneGraph.size(); mSceneGraph.push_back(InternalNode(node)); if(node.parent != kInvalidNode) mSceneGraph[node.parent].children.push_back(newNodeID); mDirty = true; return newNodeID; } - void SceneBuilder::addMeshInstance(size_t nodeID, size_t meshID) + void SceneBuilder::addMeshInstance(uint32_t nodeID, uint32_t meshID) { assert(meshID < mMeshes.size()); mSceneGraph.at(nodeID).meshes.push_back(meshID); - mMeshes.at(meshID).instances.push_back((uint32_t)nodeID); + mMeshes.at(meshID).instances.push_back(nodeID); mDirty = true; } - size_t SceneBuilder::addMesh(const Mesh& mesh) + uint32_t SceneBuilder::addMesh(const Mesh& mesh) { - assert(mesh.pLightMapUVs == nullptr); const auto& prevMesh = mMeshes.size() ? mMeshes.back() : MeshSpec(); // Create the new mesh spec @@ -212,7 +211,7 @@ namespace Falcor } // Generate tangent space if that's required - std::vector bitangents; + std::vector bitangents; if (!is_set(mFlags, Flags::UseOriginalTangentSpace) || !mesh.pBitangents) { bitangents = MikkTSpaceWrapper::generateBitangents(mesh.pPositions, mesh.pNormals, mesh.pTexCrd, mesh.pIndices, mesh.vertexCount, mesh.indexCount); @@ -226,11 +225,10 @@ namespace Falcor { StaticVertexData s; s.position = mesh.pPositions[v]; - s.normal = mesh.pNormals ? mesh.pNormals[v] : vec3(0, 0, 0); - s.texCrd = mesh.pTexCrd ? mesh.pTexCrd[v] : vec2(0, 0); + s.normal = mesh.pNormals ? mesh.pNormals[v] : float3(0, 0, 0); + s.texCrd = mesh.pTexCrd ? mesh.pTexCrd[v] : float2(0, 0); s.bitangent = bitangents.size() ? bitangents[v] : mesh.pBitangents[v]; - s.prevPosition = s.position; - mBuffersData.staticData.push_back(s); + mBuffersData.staticData.push_back(PackedStaticVertexData(s)); if (mesh.pBoneWeights) { @@ -240,16 +238,12 @@ namespace Falcor d.staticIndex = (uint32_t)mBuffersData.staticData.size() - 1; mBuffersData.dynamicData.push_back(d); } - -// if (mesh.pLightMapUVs) -// { -// spec.optionalData[v].lightmapUV = mesh.pLightMapUVs[v]; -// } } mDirty = true; - return mMeshes.size() - 1; + assert(mMeshes.size() <= UINT32_MAX); + return (uint32_t)mMeshes.size() - 1; } uint32_t SceneBuilder::addMaterial(const Material::SharedPtr& pMaterial, bool removeDuplicate) @@ -278,74 +272,76 @@ namespace Falcor } } + mDirty = true; mMaterials.push_back(pMaterial); assert(mMaterials.size() <= UINT32_MAX); - mDirty = true; return (uint32_t)mMaterials.size() - 1; } - void SceneBuilder::setCamera(const Camera::SharedPtr& pCamera, size_t nodeID) + void SceneBuilder::setCamera(const Camera::SharedPtr& pCamera, uint32_t nodeID) { mCamera.nodeID = nodeID; mCamera.pObject = pCamera; mDirty = true; } - size_t SceneBuilder::addLight(const Light::SharedPtr& pLight, size_t nodeID) + uint32_t SceneBuilder::addLight(const Light::SharedPtr& pLight, uint32_t nodeID) { Scene::AnimatedObject light; light.pObject = pLight; light.nodeID = nodeID; mLights.push_back(light); mDirty = true; - return mLights.size() - 1; + assert(mLights.size() <= UINT32_MAX); + return (uint32_t)mLights.size() - 1; } Vao::SharedPtr SceneBuilder::createVao(uint16_t drawCount) { for (auto& mesh : mMeshes) assert(mesh.topology == mMeshes[0].topology); + const size_t vertexCount = (uint32_t)mBuffersData.staticData.size(); size_t ibSize = sizeof(uint32_t) * mBuffersData.indices.size(); - size_t staticVbSize = sizeof(StaticVertexData) * mBuffersData.staticData.size(); - assert(ibSize <= UINT32_MAX && staticVbSize <= UINT32_MAX); + size_t staticVbSize = sizeof(PackedStaticVertexData) * vertexCount; + size_t prevVbSize = sizeof(PrevVertexData) * vertexCount; + assert(ibSize <= UINT32_MAX && staticVbSize <= UINT32_MAX && prevVbSize <= UINT32_MAX); + + // Create the index buffer ResourceBindFlags ibBindFlags = Resource::BindFlags::Index | ResourceBindFlags::ShaderResource; Buffer::SharedPtr pIB = Buffer::create((uint32_t)ibSize, ibBindFlags, Buffer::CpuAccess::None, mBuffersData.indices.data()); - // Create the static vertex data as a structured-buffer + // Create the vertex data as structured buffers ResourceBindFlags vbBindFlags = ResourceBindFlags::ShaderResource | ResourceBindFlags::UnorderedAccess | ResourceBindFlags::Vertex; - Buffer::SharedPtr pStaticBuffer = Buffer::createStructured(sizeof(StaticVertexData), (uint32_t)mBuffersData.staticData.size(), vbBindFlags); + Buffer::SharedPtr pStaticBuffer = Buffer::createStructured(sizeof(PackedStaticVertexData), (uint32_t)vertexCount, vbBindFlags, Buffer::CpuAccess::None, nullptr, false); + Buffer::SharedPtr pPrevBuffer = Buffer::createStructured(sizeof(PrevVertexData), (uint32_t)vertexCount, vbBindFlags, Buffer::CpuAccess::None, nullptr, false); Vao::BufferVec pVBs(Scene::kVertexBufferCount); pVBs[Scene::kStaticDataBufferIndex] = pStaticBuffer; + pVBs[Scene::kPrevVertexBufferIndex] = pPrevBuffer; std::vector drawIDs(drawCount); for (uint32_t i = 0; i < drawCount; i++) drawIDs[i] = i; - pVBs[Scene::kDrawIdBufferIndex] = Buffer::create(drawCount*sizeof(uint16_t), ResourceBindFlags::Vertex, Buffer::CpuAccess::None, drawIDs.data()); + pVBs[Scene::kDrawIdBufferIndex] = Buffer::create(drawCount * sizeof(uint16_t), ResourceBindFlags::Vertex, Buffer::CpuAccess::None, drawIDs.data()); - // The layout only initialized the static and optional data. The skinning data doesn't get passed into the vertex-shader + // The layout only initializes the vertex data and draw ID layout. The skinning data doesn't get passed into the vertex shader. VertexLayout::SharedPtr pLayout = VertexLayout::create(); - // Static data + // Add the packed static vertex data layout VertexBufferLayout::SharedPtr pStaticLayout = VertexBufferLayout::create(); - pStaticLayout->addElement(VERTEX_POSITION_NAME, offsetof(StaticVertexData, position), ResourceFormat::RGB32Float, 1, VERTEX_POSITION_LOC); - pStaticLayout->addElement(VERTEX_NORMAL_NAME, offsetof(StaticVertexData, normal), ResourceFormat::RGB32Float, 1, VERTEX_NORMAL_LOC); - pStaticLayout->addElement(VERTEX_BITANGENT_NAME, offsetof(StaticVertexData, bitangent), ResourceFormat::RGB32Float, 1, VERTEX_BITANGENT_LOC); - pStaticLayout->addElement(VERTEX_TEXCOORD_NAME, offsetof(StaticVertexData, texCrd), ResourceFormat::RG32Float, 1, VERTEX_TEXCOORD_LOC); - pStaticLayout->addElement(VERTEX_PREV_POSITION_NAME, offsetof(StaticVertexData, prevPosition), ResourceFormat::RGB32Float, 1, VERTEX_PREV_POSITION_LOC); + pStaticLayout->addElement(VERTEX_POSITION_NAME, offsetof(PackedStaticVertexData, position), ResourceFormat::RGB32Float, 1, VERTEX_POSITION_LOC); + pStaticLayout->addElement(VERTEX_PACKED_NORMAL_BITANGENT_NAME, offsetof(PackedStaticVertexData, packedNormalBitangent), ResourceFormat::RGB32Float, 1, VERTEX_PACKED_NORMAL_BITANGENT_LOC); + pStaticLayout->addElement(VERTEX_TEXCOORD_NAME, offsetof(PackedStaticVertexData, texCrd), ResourceFormat::RG32Float, 1, VERTEX_TEXCOORD_LOC); pLayout->addBufferLayout(Scene::kStaticDataBufferIndex, pStaticLayout); + // Add the previous vertex data layout + VertexBufferLayout::SharedPtr pPrevLayout = VertexBufferLayout::create(); + pPrevLayout->addElement(VERTEX_PREV_POSITION_NAME, offsetof(PrevVertexData, position), ResourceFormat::RGB32Float, 1, VERTEX_PREV_POSITION_LOC); + pLayout->addBufferLayout(Scene::kPrevVertexBufferIndex, pPrevLayout); + // Add the draw ID layout VertexBufferLayout::SharedPtr pInstLayout = VertexBufferLayout::create(); pInstLayout->addElement(INSTANCE_DRAW_ID_NAME, 0, ResourceFormat::R16Uint, 1, INSTANCE_DRAW_ID_LOC); pInstLayout->setInputClass(VertexBufferLayout::InputClass::PerInstanceData, 1); pLayout->addBufferLayout(Scene::kDrawIdBufferIndex, pInstLayout); -// // #SCENE optional data -// if (pVBs[sOptionalDataIndex]) -// { -// VertexBufferLayout::SharedPtr pOptionalLayout = VertexBufferLayout::create(); -// pOptionalLayout->addElement(VERTEX_LIGHTMAP_UV_NAME, offsetof(SceneBuilder::MeshSpec::OptionalData, lightmapUV), ResourceFormat::RGB32Float, 1, VERTEX_LIGHTMAP_UV_LOC); -// pLayout->addBufferLayout(sOptionalDataIndex, pOptionalLayout); -// } - Vao::SharedPtr pVao = Vao::create(mMeshes[0].topology, pLayout, pVBs, pIB, ResourceFormat::R32Uint); return pVao; } @@ -354,10 +350,10 @@ namespace Falcor { pScene->mSceneGraph.resize(mSceneGraph.size()); - for (uint32_t i = 0; i < mSceneGraph.size(); i++) + for (size_t i = 0; i < mSceneGraph.size(); i++) { assert(mSceneGraph[i].parent <= UINT32_MAX); - pScene->mSceneGraph[i] = Scene::Node( mSceneGraph[i].name, (uint32_t)mSceneGraph[i].parent, mSceneGraph[i].transform, mSceneGraph[i].localToBindPose); + pScene->mSceneGraph[i] = Scene::Node(mSceneGraph[i].name, (uint32_t)mSceneGraph[i].parent, mSceneGraph[i].transform, mSceneGraph[i].localToBindPose); } } @@ -389,6 +385,8 @@ namespace Falcor meshInstance.globalMatrixID = instance; meshInstance.materialID = mesh.materialId; meshInstance.meshID = meshID; + meshInstance.vbOffset = mesh.staticVertexOffset; + meshInstance.ibOffset = mesh.indexOffset; } if (mesh.hasDynamicData) @@ -430,6 +428,7 @@ namespace Falcor createGlobalMatricesBuffer(mpScene.get()); uint32_t drawCount = createMeshData(mpScene.get()); + assert(drawCount <= UINT16_MAX); mpScene->mpVao = createVao(drawCount); calculateMeshBoundingBoxes(mpScene.get()); createAnimationController(mpScene.get()); @@ -443,11 +442,11 @@ namespace Falcor { // Calculate mesh bounding boxes pScene->mMeshBBs.resize(mMeshes.size()); - for (uint32_t i = 0; i < (uint32_t)mMeshes.size(); i++) + for (size_t i = 0; i < mMeshes.size(); i++) { const auto& mesh = mMeshes[i]; - vec3 boxMin(FLT_MAX); - vec3 boxMax(-FLT_MAX); + float3 boxMin(FLT_MAX); + float3 boxMax(-FLT_MAX); const auto* staticData = &mBuffersData.staticData[mesh.staticVertexOffset]; for (uint32_t v = 0; v < mesh.vertexCount; v++) @@ -460,12 +459,13 @@ namespace Falcor } } - size_t SceneBuilder::addAnimation(size_t meshID, Animation::ConstSharedPtrRef pAnimation) + uint32_t SceneBuilder::addAnimation(uint32_t meshID, Animation::ConstSharedPtrRef pAnimation) { assert(meshID < mMeshes.size()); mMeshes[meshID].animations.push_back(pAnimation); mDirty = true; - return mMeshes[meshID].animations.size() - 1; + assert(mMeshes[meshID].animations.size() <= UINT32_MAX); + return (uint32_t)mMeshes[meshID].animations.size() - 1; } void SceneBuilder::createAnimationController(Scene* pScene) diff --git a/Source/Falcor/Scene/SceneBuilder.h b/Source/Falcor/Scene/SceneBuilder.h index ece9c7a2d..31e7313bd 100644 --- a/Source/Falcor/Scene/SceneBuilder.h +++ b/Source/Falcor/Scene/SceneBuilder.h @@ -59,28 +59,28 @@ namespace Falcor std::string name; // The mesh's name uint32_t vertexCount = 0; // The number of vertices the mesh has uint32_t indexCount = 0; // The number of indices the mesh has. Can't be zero - the scene doesn't support non-indexed meshes. If you'd like us to support non-indexed meshes, please open an issue - const uint32_t* pIndices = nullptr; // Array of indices. The element count must match `indexCount` - const vec3* pPositions = nullptr; // Array of vertex positions. The element count must match `vertexCount`. This field is required - const vec3* pNormals = nullptr; // Array of vertex normals. The element count must match `vertexCount`. This field is required - const vec3* pBitangents = nullptr; // Array of vertex bitangent. The element count must match `vertexCount`. Optional. If set to nullptr, or if BuildFlags::UseOriginalTangentSpace is not set, the tangents will be generated using MikkTSpace - const vec2* pTexCrd = nullptr; // Array of vertex texture coordinates. The element count must match `vertexCount`. This field is required - const vec3* pLightMapUVs = nullptr; // Array of light-map UVs. The element count must match `vertexCount`. This field is optional - const uvec4* pBoneIDs = nullptr; // Array of bone IDs. The element count must match `vertexCount`. This field is optional. If it's set, that means that the mesh is animated, in which case pBoneWeights can't be nullptr - const vec4* pBoneWeights = nullptr; // Array of bone weights. The element count must match `vertexCount`. This field is optional. If it's set, that means that the mesh is animated, in which case pBoneIDs can't be nullptr + const uint32_t* pIndices = nullptr; // Array of indices. The element count must match `indexCount` + const float3* pPositions = nullptr; // Array of vertex positions. The element count must match `vertexCount`. This field is required + const float3* pNormals = nullptr; // Array of vertex normals. The element count must match `vertexCount`. This field is required + const float3* pBitangents = nullptr; // Array of vertex bitangent. The element count must match `vertexCount`. Optional. If set to nullptr, or if BuildFlags::UseOriginalTangentSpace is not set, the tangents will be generated using MikkTSpace + const float2* pTexCrd = nullptr; // Array of vertex texture coordinates. The element count must match `vertexCount`. This field is required + const uint4* pBoneIDs = nullptr; // Array of bone IDs. The element count must match `vertexCount`. This field is optional. If it's set, that means that the mesh is animated, in which case pBoneWeights can't be nullptr + const float4* pBoneWeights = nullptr; // Array of bone weights. The element count must match `vertexCount`. This field is optional. If it's set, that means that the mesh is animated, in which case pBoneIDs can't be nullptr Vao::Topology topology = Vao::Topology::Undefined; // The primitive topology of the mesh Material::SharedPtr pMaterial; // The mesh's material. Can't be nullptr }; static const uint32_t kInvalidNode = Scene::kInvalidNode; + struct Node { std::string name; - mat4 transform; - mat4 localToBindPose; // For bones - size_t parent = kInvalidNode; + glm::mat4 transform; + glm::mat4 localToBindPose; // For bones + uint32_t parent = kInvalidNode; }; - using InstanceMatrices = std::vector; + using InstanceMatrices = std::vector; /** Construct a new object */ @@ -110,27 +110,29 @@ namespace Falcor */ Scene::SharedPtr getScene(); - /** Adds a node to the graph + /** Adds a node to the graph. Note that if the node contains data other then the transform matrix (such as meshes or lights), you'll need to add those objects before adding the node. + \return The node ID. */ - size_t addNode(const Node& node); + uint32_t addNode(const Node& node); /** Add a mesh instance to a node */ - void addMeshInstance(size_t nodeID, size_t meshID); + void addMeshInstance(uint32_t nodeID, uint32_t meshID); /** Add a mesh. This function will throw an exception if something went wrong \param mesh The mesh's desc \param flags The build flags - \return The ID of the mesh in the scene. Note that all of the instances share the same mesh ID + \return The ID of the mesh in the scene. Note that all of the instances share the same mesh ID. */ - size_t addMesh(const Mesh& mesh); + uint32_t addMesh(const Mesh& mesh); /** Add a light source \param pLight The light object. Can't be nullptr + \param nodeID The node ID of the light. \return The light ID */ - size_t addLight(const Light::SharedPtr& pLight, size_t nodeID = kInvalidNode); + uint32_t addLight(const Light::SharedPtr& pLight, uint32_t nodeID = kInvalidNode); /** Get the number of attached lights */ @@ -148,7 +150,7 @@ namespace Falcor /** Set the camera */ - void setCamera(const Camera::SharedPtr& pCamera, size_t nodeID = kInvalidNode); + void setCamera(const Camera::SharedPtr& pCamera, uint32_t nodeID = kInvalidNode); /** Get the build flags */ @@ -159,7 +161,7 @@ namespace Falcor \param animation The animation \return The ID of the animation. The ID is relative to number of animations which are associated with the specified mesh, it's not a global ID */ - size_t addAnimation(size_t meshID, Animation::ConstSharedPtrRef pAnimation); + uint32_t addAnimation(uint32_t meshID, Animation::ConstSharedPtrRef pAnimation); /** Set the camera's speed */ @@ -168,13 +170,14 @@ namespace Falcor /** Check if a camera exists */ bool hasCamera() const { return mCamera.pObject != nullptr; } + private: struct InternalNode : Node { InternalNode() = default; InternalNode(const Node& n) : Node(n) {} - std::vector children; - std::vector meshes; + std::vector children; + std::vector meshes; }; struct MeshSpec @@ -196,7 +199,7 @@ namespace Falcor struct BuffersData { std::vector indices; - std::vector staticData; + std::vector staticData; std::vector dynamicData; } mBuffersData; diff --git a/Source/Falcor/Scene/SceneTypes.slang b/Source/Falcor/Scene/SceneTypes.slang index a736379e0..da1fd29df 100644 --- a/Source/Falcor/Scene/SceneTypes.slang +++ b/Source/Falcor/Scene/SceneTypes.slang @@ -27,6 +27,9 @@ **************************************************************************/ #pragma once #include "Utils/HostDeviceShared.slangh" +#ifdef HOST_CODE +#include "glm/packing.hpp" +#endif BEGIN_NAMESPACE_FALCOR @@ -45,12 +48,16 @@ enum MeshInstanceFlags Flipped = 0x1 }; +// TODO: Pack into 16B by encoding IDs and flags with fewer bits. See #795. struct MeshInstanceData { uint globalMatrixID; uint materialID; uint meshID; uint flags; ///< MeshInstanceFlags + uint vbOffset; + uint ibOffset; + uint pad[2]; }; struct StaticVertexData @@ -59,7 +66,71 @@ struct StaticVertexData float3 normal; float3 bitangent; float2 texCrd; - float3 prevPosition; +}; + +/** Vertex data packed into 32B for aligned access. +*/ +struct PackedStaticVertexData +{ + float3 position; + float3 packedNormalBitangent; // 3xfp16 each + float2 texCrd; + +#ifdef HOST_CODE + PackedStaticVertexData(const StaticVertexData& v) { pack(v); } + void pack(const StaticVertexData& v) + { + position = v.position; + texCrd = v.texCrd; + + auto asfloat = [](uint32_t v) { return *reinterpret_cast(&v); }; + //auto asfloat = [](uint32_t v) { return std::bit_cast(v); }; // TODO: Not yet available in VS2019 + + packedNormalBitangent.x = asfloat(glm::packHalf2x16({ v.normal.x, v.normal.y })); + packedNormalBitangent.y = asfloat(glm::packHalf2x16({ v.normal.z, v.bitangent.x })); + packedNormalBitangent.z = asfloat(glm::packHalf2x16({ v.bitangent.y, v.bitangent.z })); + } + +#else // !HOST_CODE + [mutating] void pack(const StaticVertexData v) + { + position = v.position; + texCrd = v.texCrd; + + uint3 n = f32tof16(v.normal); + uint3 b = f32tof16(v.bitangent); + + packedNormalBitangent.x = asfloat((n.y << 16) | n.x); + packedNormalBitangent.y = asfloat((b.x << 16) | n.z); + packedNormalBitangent.z = asfloat((b.z << 16) | b.y); + } + + StaticVertexData unpack() + { + StaticVertexData v; + v.position = position; + v.texCrd = texCrd; + + float3 n; + n.x = f16tof32(asuint(packedNormalBitangent.x) & 0xffff); + n.y = f16tof32(asuint(packedNormalBitangent.x) >> 16); + n.z = f16tof32(asuint(packedNormalBitangent.y) & 0xffff); + v.normal = normalize(n); + + float3 b; + b.x = f16tof32(asuint(packedNormalBitangent.y) >> 16); + b.y = f16tof32(asuint(packedNormalBitangent.z) & 0xffff); + b.z = f16tof32(asuint(packedNormalBitangent.z) >> 16); + v.bitangent = normalize(b); + + return v; + } +#endif +}; + +struct PrevVertexData +{ + float3 position; }; struct DynamicVertexData @@ -77,6 +148,7 @@ struct VertexData float3 bitangentW; ///< Shading bitangent in world space. float2 texC; ///< Texture coordinate. float3 faceNormalW; ///< Face normal in world space. + float coneTexLODValue; ///< Texture LOD data for cone tracing. This is zero, unless getVertexDataRayCones() is used }; END_NAMESPACE_FALCOR diff --git a/Source/Falcor/Scene/ShadingData.slang b/Source/Falcor/Scene/ShadingData.slang index 0e83f55da..1e9d11c18 100644 --- a/Source/Falcor/Scene/ShadingData.slang +++ b/Source/Falcor/Scene/ShadingData.slang @@ -293,6 +293,36 @@ ShadingData prepareShadingData(VertexData v, uint materialID, MaterialData md, M return _prepareShadingData(v, materialID, md, mr, viewDir, explicitLOD, true); } +/** Prepare the hit-point data when using ray cones for texture LOD. + \param[in] v Vertex data. + \param[in] materialID Material identifier. + \param[in] md Material data. + \param[in] mr Material resources. + \param[in] camPosW Position of camera in world space. + \param[in] lodMinusTexDim Texture level-of-details for ray cones with the texture dimensions subtracted out. See TextureSampler and TexLODHelpers. +*/ +ShadingData prepareShadingDataUsingRayConesLOD(VertexData v, uint materialID, MaterialData md, MaterialResources mr, float3 camPosW, float lodMinusTexDim) +{ + ExplicitRayConesLodTextureSampler explicitRayConesLOD = { lodMinusTexDim }; + return _prepareShadingData(v, materialID, md, mr, camPosW, explicitRayConesLOD, true); +} + +/** Prepare the hit-point data when using ray differentials for texture LOD. + \param[in] v Vertex data. + \param[in] materialID Material identifier. + \param[in] md Material data. + \param[in] mr Material resources. + \param[in] camPosW Position of camera in world space. + \param[in] dUVdx Differential texture coordinates in x. + \param[in] dUVdy Differential texture coordinates in y. +*/ +ShadingData prepareShadingDataUsingRayDiffsLOD(VertexData v, uint materialID, MaterialData md, MaterialResources mr, float3 camPosW, float2 dUVdx, float2 dUVdy) +{ + ExplicitRayDiffsLodTextureSampler explicitRayDiffsLOD = { dUVdx, dUVdy }; + return _prepareShadingData(v, materialID, md, mr, camPosW, explicitRayDiffsLOD, true); +} + + /** Prepare the hit-point data The `gradX` and `gradY` parameters should be the screen-space gradients of diff --git a/Source/Falcor/Scene/TextureSampler.slang b/Source/Falcor/Scene/TextureSampler.slang index 75ea256eb..a0da24bc1 100644 --- a/Source/Falcor/Scene/TextureSampler.slang +++ b/Source/Falcor/Scene/TextureSampler.slang @@ -59,6 +59,55 @@ struct ExplicitLodTextureSampler : ITextureSampler } }; +/** Texture sampling using an explicit scalar level of detail using ray cones (with texture dimensions + "subtracted" from the LOD value, and added back in before SampleLevel()). +*/ +struct ExplicitRayConesLodTextureSampler : ITextureSampler +{ + float rayconesLODWithoutTexDims; ///< this is \Delta_t, which is texture independent, plus the rest of the terms, except the texture size, which is added below + + float4 sampleTexture(Texture2D t, SamplerState s, float2 uv) + { + uint txw, txh; + t.GetDimensions(txw, txh); + float lambda = 0.5 * log2(txw * txh) + rayconesLODWithoutTexDims; + return t.SampleLevel(s, uv, lambda); + } +}; + + +/** Texture sampling using an explicit scalar level of detail using ray diffs, + with the final LOD computations done below, since they are dependent on texture dimensions. +*/ +enum class RayDiffsLODComputationMode { OpenGLStyle, PBRTStyle }; +static const RayDiffsLODComputationMode rayDiffsLODComputationMode = RayDiffsLODComputationMode::OpenGLStyle; + +struct ExplicitRayDiffsLodTextureSampler : ITextureSampler +{ + float2 dUVdx; ///< derivatives in x over uv + float2 dUVdy; ///< derivatives in y over uv + + float4 sampleTexture(Texture2D t, SamplerState s, float2 uv) + { + uint txw, txh; + float lambda; + t.GetDimensions(txw, txh); + if (rayDiffsLODComputationMode == RayDiffsLODComputationMode::OpenGLStyle) // sharper, but alias sometimes for sharp edges textures, for example + { + const float2 duvdx = dUVdx * txw; + const float2 duvdy = dUVdy * txh; + lambda = 0.5 * log2(max(dot(duvdx, duvdx), dot(duvdy, duvdy))); + } + else // RayDiffsLODComputationMode::PBRTStyle + { + float filterWidth = 2.0 * max(txw * max(abs(dUVdx.x), abs(dUVdy.x)), txh * max(abs(dUVdx.y), abs(dUVdy.y))); // PBRT style (much blurrier, but never (?) aliases) + lambda = log2(filterWidth); + } + return t.SampleLevel(s, uv, lambda); + } +}; + + /** Texture sampling using explicit screen-space gradients */ struct ExplicitGradientTextureSampler : ITextureSampler diff --git a/Source/Falcor/Scene/VertexAttrib.slangh b/Source/Falcor/Scene/VertexAttrib.slangh index 040c372fb..a915bd1e0 100644 --- a/Source/Falcor/Scene/VertexAttrib.slangh +++ b/Source/Falcor/Scene/VertexAttrib.slangh @@ -30,39 +30,21 @@ BEGIN_NAMESPACE_FALCOR -enum class VertexElement -{ - Position, - Normal, - Bitangent, - TexCoord, - LightmapUV, - PrevPosition, - DrawID, - // Many places in code iterate based on VertexElement, or check element index directly, so instance data isn't part of this enum - - Count // Must be last -}; - -#define VERTEX_POSITION_LOC 0 -#define VERTEX_NORMAL_LOC 1 -#define VERTEX_BITANGENT_LOC 2 -#define VERTEX_TEXCOORD_LOC 3 -#define VERTEX_LIGHTMAP_UV_LOC 4 -#define VERTEX_PREV_POSITION_LOC 6 -#define INSTANCE_DRAW_ID_LOC 7 - -#define VERTEX_LOCATION_COUNT 8 - -#define VERTEX_USER_ELEM_COUNT 4 -#define VERTEX_USER0_LOC (VERTEX_LOCATION_COUNT) - -#define VERTEX_POSITION_NAME "POSITION" -#define VERTEX_NORMAL_NAME "NORMAL" -#define VERTEX_BITANGENT_NAME "BITANGENT" -#define VERTEX_TEXCOORD_NAME "TEXCOORD" -#define VERTEX_LIGHTMAP_UV_NAME "LIGHTMAP_UV" -#define VERTEX_PREV_POSITION_NAME "PREV_POSITION" -#define INSTANCE_DRAW_ID_NAME "DRAW_ID" +#define VERTEX_POSITION_LOC 0 +#define VERTEX_PACKED_NORMAL_BITANGENT_LOC 1 +#define VERTEX_TEXCOORD_LOC 2 +#define VERTEX_PREV_POSITION_LOC 3 +#define INSTANCE_DRAW_ID_LOC 4 + +#define VERTEX_LOCATION_COUNT 5 + +#define VERTEX_USER_ELEM_COUNT 4 +#define VERTEX_USER0_LOC (VERTEX_LOCATION_COUNT) + +#define VERTEX_POSITION_NAME "POSITION" +#define VERTEX_PACKED_NORMAL_BITANGENT_NAME "PACKED_NORMAL_BITANGENT" +#define VERTEX_TEXCOORD_NAME "TEXCOORD" +#define VERTEX_PREV_POSITION_NAME "PREV_POSITION" +#define INSTANCE_DRAW_ID_NAME "DRAW_ID" END_NAMESPACE_FALCOR diff --git a/Source/Falcor/Testing/UnitTest.cpp b/Source/Falcor/Testing/UnitTest.cpp index b169a676e..8d70d436f 100644 --- a/Source/Falcor/Testing/UnitTest.cpp +++ b/Source/Falcor/Testing/UnitTest.cpp @@ -123,7 +123,7 @@ namespace Falcor result.messages = test.cpuFunc ? cpuCtx.getFailureMessages() : gpuCtx.getFailureMessages(); if (!result.messages.empty()) result.status = TestResult::Status::Failed; - + if (!extraMessage.empty()) result.messages.push_back(extraMessage); auto endTime = std::chrono::steady_clock::now(); @@ -224,7 +224,7 @@ namespace Falcor } } - void GPUUnitTestContext::runProgram(const glm::uvec3& dimensions) + void GPUUnitTestContext::runProgram(const uint3& dimensions) { assert(mpVars); for (const auto& buffer : mStructuredBuffers) @@ -232,7 +232,7 @@ namespace Falcor mpVars->setBuffer(buffer.first, buffer.second.pBuffer); } - uvec3 groups = div_round_up(dimensions, mThreadGroupSize); + uint3 groups = div_round_up(dimensions, mThreadGroupSize); #ifdef FALCOR_D3D12 // Check dispatch dimensions. TODO: Should be moved into Falcor. diff --git a/Source/Falcor/Testing/UnitTest.h b/Source/Falcor/Testing/UnitTest.h index 4d6a0b349..40f0f1dba 100644 --- a/Source/Falcor/Testing/UnitTest.h +++ b/Source/Falcor/Testing/UnitTest.h @@ -152,13 +152,13 @@ namespace Falcor given by the product of the three provided dimensions. \param[in] dimensions Number of threads to dispatch in each dimension. */ - void runProgram(const glm::uvec3& dimensions); + void runProgram(const uint3& dimensions); /** runProgram runs the compute program that was specified in |createProgram|, where the total number of threads that runs is given by the product of the three provided dimensions. */ - void runProgram(uint32_t width = 1, uint32_t height = 1, uint32_t depth = 1) { runProgram(glm::uvec3(width, height, depth)); } + void runProgram(uint32_t width = 1, uint32_t height = 1, uint32_t depth = 1) { runProgram(uint3(width, height, depth)); } /** mapBuffer returns a pointer to the named structured buffer. Returns nullptr if no such buffer exists. SFINAE is used to @@ -191,7 +191,7 @@ namespace Falcor ComputeState::SharedPtr mpState; ComputeProgram::SharedPtr mpProgram; ComputeVars::SharedPtr mpVars; - glm::uvec3 mThreadGroupSize = { 0, 0, 0 }; + uint3 mThreadGroupSize = { 0, 0, 0 }; struct ParameterBuffer { diff --git a/Source/Falcor/Utils/Algorithm/ComputeParallelReduction.cpp b/Source/Falcor/Utils/Algorithm/ComputeParallelReduction.cpp index 0100ab693..ff129dba1 100644 --- a/Source/Falcor/Utils/Algorithm/ComputeParallelReduction.cpp +++ b/Source/Falcor/Utils/Algorithm/ComputeParallelReduction.cpp @@ -59,13 +59,13 @@ namespace Falcor if (mpBuffers[0] == nullptr || mpBuffers[0]->getElementCount() < elementCount) { // Buffer 0 has one element per tile. - mpBuffers[0] = Buffer::createTyped(elementCount); + mpBuffers[0] = Buffer::createTyped(elementCount); // Buffer 1 has one element per N elements in buffer 0. const uint32_t numElem1 = div_round_up(elementCount, mpFinalProgram->getReflector()->getThreadGroupSize().x); if (mpBuffers[1] == nullptr || mpBuffers[1]->getElementCount() < numElem1) { - mpBuffers[1] = Buffer::createTyped(numElem1); + mpBuffers[1] = Buffer::createTyped(numElem1); } } } @@ -113,10 +113,10 @@ namespace Falcor } // Allocate intermediate buffers if needed. - const glm::uvec2 resolution = glm::uvec2(pInput->getWidth(), pInput->getHeight()); + const uint2 resolution = uint2(pInput->getWidth(), pInput->getHeight()); assert(resolution.x > 0 && resolution.y > 0); - const glm::uvec2 numTiles = div_round_up(resolution, glm::uvec2(mpInitialProgram->getReflector()->getThreadGroupSize())); + const uint2 numTiles = div_round_up(resolution, uint2(mpInitialProgram->getReflector()->getThreadGroupSize())); allocate(numTiles.x * numTiles.y); assert(mpBuffers[0]); assert(mpBuffers[1]); @@ -137,7 +137,7 @@ namespace Falcor mpVars->setBuffer("gResult", mpBuffers[0]); mpState->setProgram(mpInitialProgram); - glm::uvec3 numGroups = div_round_up(glm::uvec3(resolution.x, resolution.y, 1), mpInitialProgram->getReflector()->getThreadGroupSize()); + uint3 numGroups = div_round_up(uint3(resolution.x, resolution.y, 1), mpInitialProgram->getReflector()->getThreadGroupSize()); pRenderContext->dispatch(mpState.get(), mpVars.get(), numGroups); // Final pass(es): Reduction by a factor N for each pass. @@ -183,7 +183,7 @@ namespace Falcor } // Explicit template instantiation of the supported types. - template dlldecl bool ComputeParallelReduction::execute(RenderContext* pRenderContext, const Texture::SharedPtr& pInput, Type operation, glm::vec4* pResult, Buffer::SharedPtr pResultBuffer, uint64_t resultOffset); - template dlldecl bool ComputeParallelReduction::execute(RenderContext* pRenderContext, const Texture::SharedPtr& pInput, Type operation, glm::ivec4* pResult, Buffer::SharedPtr pResultBuffer, uint64_t resultOffset); - template dlldecl bool ComputeParallelReduction::execute(RenderContext* pRenderContext, const Texture::SharedPtr& pInput, Type operation, glm::uvec4* pResult, Buffer::SharedPtr pResultBuffer, uint64_t resultOffset); + template dlldecl bool ComputeParallelReduction::execute(RenderContext* pRenderContext, const Texture::SharedPtr& pInput, Type operation, float4* pResult, Buffer::SharedPtr pResultBuffer, uint64_t resultOffset); + template dlldecl bool ComputeParallelReduction::execute(RenderContext* pRenderContext, const Texture::SharedPtr& pInput, Type operation, int4* pResult, Buffer::SharedPtr pResultBuffer, uint64_t resultOffset); + template dlldecl bool ComputeParallelReduction::execute(RenderContext* pRenderContext, const Texture::SharedPtr& pInput, Type operation, uint4* pResult, Buffer::SharedPtr pResultBuffer, uint64_t resultOffset); } diff --git a/Source/Falcor/Utils/Algorithm/ComputeParallelReduction.h b/Source/Falcor/Utils/Algorithm/ComputeParallelReduction.h index 572f3998f..5509b587c 100644 --- a/Source/Falcor/Utils/Algorithm/ComputeParallelReduction.h +++ b/Source/Falcor/Utils/Algorithm/ComputeParallelReduction.h @@ -61,9 +61,9 @@ namespace Falcor /** Perform parallel reduction. The computations are performed in type T, which must be compatible with the texture format: - - glm::vec4 for floating-point texture formats (float, snorm, unorm). - - glm::uvec4 for unsigned integer texture formats. - - glm::ivec4 for signed integer texture formats. + - float4 for floating-point texture formats (float, snorm, unorm). + - uint4 for unsigned integer texture formats. + - int4 for signed integer texture formats. Note that unused components are set to zero if texture format has < 4 components. For performance reasons, it is advisable to store the result in a buffer on the GPU, and then issue an asynchronous readback in user code to avoid a full GPU flush. diff --git a/Source/Falcor/Utils/Algorithm/ParallelReduction.cpp b/Source/Falcor/Utils/Algorithm/ParallelReduction.cpp index 24a11a33c..5f7118b9d 100644 --- a/Source/Falcor/Utils/Algorithm/ParallelReduction.cpp +++ b/Source/Falcor/Utils/Algorithm/ParallelReduction.cpp @@ -74,8 +74,8 @@ namespace Falcor width = (width + kTileSize - 1) / kTileSize;; height = (height + kTileSize - 1) / kTileSize;; - width = max(width, 1u); - height = max(height, 1u); + width = std::max(width, 1u); + height = std::max(height, 1u); Fbo::Desc fboDesc; fboDesc.setColorTarget(0, texFormat); @@ -96,7 +96,7 @@ namespace Falcor pPass->execute(pRenderCtx, pDst); } - glm::vec4 ParallelReduction::reduce(RenderContext* pRenderCtx, Texture::SharedPtr pInput) + float4 ParallelReduction::reduce(RenderContext* pRenderCtx, Texture::SharedPtr pInput) { FullScreenPass::SharedPtr pPass = mpFirstIterProg; @@ -111,7 +111,7 @@ namespace Falcor mResultData[mCurFbo].pReadTask = pRenderCtx->asyncReadTextureSubresource(mResultData[mCurFbo].pFbo->getColorTexture(0).get(), 0); // Read back the results mCurFbo = (mCurFbo + 1) % mResultData.size(); - glm::vec4 result(0); + float4 result(0); if(mResultData[mCurFbo].pReadTask) { auto texData = mResultData[mCurFbo].pReadTask->getData(); @@ -120,7 +120,7 @@ namespace Falcor switch (mReductionType) { case Type::MinMax: - result = vec4(*reinterpret_cast(texData.data()), 0, 0); + result = float4(*reinterpret_cast(texData.data()), 0, 0); break; default: should_not_get_here(); diff --git a/Source/Falcor/Utils/Algorithm/ParallelReduction.h b/Source/Falcor/Utils/Algorithm/ParallelReduction.h index 1df83ca8e..a5073d7ea 100644 --- a/Source/Falcor/Utils/Algorithm/ParallelReduction.h +++ b/Source/Falcor/Utils/Algorithm/ParallelReduction.h @@ -51,7 +51,7 @@ namespace Falcor */ static UniquePtr create(Type reductionType, uint32_t readbackLatency, uint32_t width, uint32_t height, uint32_t sampleCount = 1); - glm::vec4 reduce(RenderContext* pRenderCtx, Texture::SharedPtr pInput); + float4 reduce(RenderContext* pRenderCtx, Texture::SharedPtr pInput); private: ParallelReduction(Type reductionType, uint32_t readbackLatency, uint32_t width, uint32_t height, uint32_t sampleCount); diff --git a/Source/Falcor/Utils/Algorithm/PrefixSum.cpp b/Source/Falcor/Utils/Algorithm/PrefixSum.cpp index 19fda1e8d..90536a1a9 100644 --- a/Source/Falcor/Utils/Algorithm/PrefixSum.cpp +++ b/Source/Falcor/Utils/Algorithm/PrefixSum.cpp @@ -81,13 +81,13 @@ namespace Falcor } // Compute number of thread groups in the first pass. Each thread operates on two elements. - const uint32_t numPrefixGroups = max(1u, div_round_up(elementCount, kGroupSize * 2)); + const uint32_t numPrefixGroups = std::max(1u, div_round_up(elementCount, kGroupSize * 2)); assert(numPrefixGroups > 0 && numPrefixGroups < kGroupSize); // Pass 1: compute per-thread group prefix sums. { // Clear group sums to zero. - pRenderContext->clearUAV(mpPrefixGroupSums->getUAV().get(), glm::uvec4(0)); + pRenderContext->clearUAV(mpPrefixGroupSums->getUAV().get(), uint4(0)); // Set constants and data. mpPrefixSumGroupVars["CB"]["gNumGroups"] = numPrefixGroups; diff --git a/Source/Falcor/Utils/Attributes.slang b/Source/Falcor/Utils/Attributes.slang new file mode 100644 index 000000000..5bc0fa17d --- /dev/null +++ b/Source/Falcor/Utils/Attributes.slang @@ -0,0 +1,32 @@ +/*************************************************************************** + # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** Attribute for tagging resources that should be bound to a root descriptor. +*/ +[__AttributeUsage(_AttributeTargets.Var)] +struct rootAttribute {}; diff --git a/Source/Falcor/Utils/Color/ColorUtils.h b/Source/Falcor/Utils/Color/ColorUtils.h index 6bb08ba60..2144e1676 100644 --- a/Source/Falcor/Utils/Color/ColorUtils.h +++ b/Source/Falcor/Utils/Color/ColorUtils.h @@ -111,23 +111,23 @@ namespace Falcor /** Transforms an RGB color in Rec.709 to CIE XYZ. */ - static glm::float3 RGBtoXYZ_Rec709(glm::float3 c) + static float3 RGBtoXYZ_Rec709(float3 c) { return kColorTransform_RGBtoXYZ_Rec709 * c; } /** Transforms an XYZ color to RGB in Rec.709. */ - static glm::float3 XYZtoRGB_Rec709(glm::float3 c) + static float3 XYZtoRGB_Rec709(float3 c) { return kColorTransform_XYZtoRGB_Rec709 * c; } /** Converts (chromaticities, luminance) to XYZ color. */ - static glm::float3 xyYtoXYZ(float x, float y, float Y) + static float3 xyYtoXYZ(float x, float y, float Y) { - return glm::float3(x * Y / y, Y, (1.f - x - y) * Y / y); + return float3(x * Y / y, Y, (1.f - x - y) * Y / y); } /** Transforms color temperature of a blackbody emitter to color in CIE XYZ. @@ -139,12 +139,12 @@ namespace Falcor \param[in] Y Luminance. \return CIE XYZ color. */ - static glm::float3 colorTemperatureToXYZ(float T, float Y = 1.f) + static float3 colorTemperatureToXYZ(float T, float Y = 1.f) { if (T < 1667.f || T > 25000.f) { logError("colorTemperatureToXYZ() - T is out of range"); - return glm::float3(0, 0, 0); + return float3(0, 0, 0); } // We do the computations in double @@ -203,13 +203,13 @@ namespace Falcor static const glm::float3x3 invMA = kColorTransform_XYZtoRGB_Rec709 * kColorTransform_LMStoXYZ_CAT02; // LMS -> RGB // Compute destination reference white in LMS space. - static const glm::float3 wd = kColorTransform_XYZtoLMS_CAT02 * colorTemperatureToXYZ(6500.f); + static const float3 wd = kColorTransform_XYZtoLMS_CAT02 * colorTemperatureToXYZ(6500.f); // Compute source reference white in LMS space. - const glm::float3 ws = kColorTransform_XYZtoLMS_CAT02 * colorTemperatureToXYZ(T); + const float3 ws = kColorTransform_XYZtoLMS_CAT02 * colorTemperatureToXYZ(T); // Derive final 3x3 transform in RGB space. - glm::float3 scale = wd / ws; + float3 scale = wd / ws; glm::float3x3 D = glm::diagonal3x3(scale); return invMA * D * MA; diff --git a/Source/Falcor/Utils/Debug/PixelDebug.cpp b/Source/Falcor/Utils/Debug/PixelDebug.cpp index ae0ebf07d..c6ace448f 100644 --- a/Source/Falcor/Utils/Debug/PixelDebug.cpp +++ b/Source/Falcor/Utils/Debug/PixelDebug.cpp @@ -41,7 +41,7 @@ namespace Falcor return SharedPtr(new PixelDebug(logSize)); } - void PixelDebug::beginFrame(RenderContext* pRenderContext, const glm::uvec2& frameDim) + void PixelDebug::beginFrame(RenderContext* pRenderContext, const uint2& frameDim) { mFrameDim = frameDim; if (mRunning) @@ -114,17 +114,19 @@ namespace Falcor { assert(mRunning); - // Configure program. - pProgram->addDefine("_PIXEL_DEBUG_ENABLED", mEnabled ? "1" : "0"); - if (mEnabled) { + pProgram->addDefine("_PIXEL_DEBUG_ENABLED"); var["gPixelLog"] = mpPixelLog; var["gAssertLog"] = mpAssertLog; var["PixelDebugCB"]["gPixelLogSelected"] = mSelectedPixel; var["PixelDebugCB"]["gPixelLogSize"] = mLogSize; var["PixelDebugCB"]["gAssertLogSize"] = mLogSize; } + else + { + pProgram->removeDefine("_PIXEL_DEBUG_ENABLED"); + } } void PixelDebug::renderUI(Gui::Widgets& widget) @@ -207,7 +209,7 @@ namespace Falcor { if (mouseEvent.type == MouseEvent::Type::LeftButtonDown) { - mSelectedPixel = glm::uvec2(mouseEvent.pos * glm::vec2(mFrameDim)); + mSelectedPixel = uint2(mouseEvent.pos * float2(mFrameDim)); return true; } } diff --git a/Source/Falcor/Utils/Debug/PixelDebug.h b/Source/Falcor/Utils/Debug/PixelDebug.h index 9afb9474c..afb024a1f 100644 --- a/Source/Falcor/Utils/Debug/PixelDebug.h +++ b/Source/Falcor/Utils/Debug/PixelDebug.h @@ -65,7 +65,7 @@ namespace Falcor */ static SharedPtr create(uint32_t logSize = 100); - void beginFrame(RenderContext* pRenderContext, const glm::uvec2& frameDim); + void beginFrame(RenderContext* pRenderContext, const uint2& frameDim); void endFrame(RenderContext* pRenderContext); void prepareProgram(const Program::SharedPtr& pProgram, const ShaderVar& var); @@ -87,10 +87,10 @@ namespace Falcor // Configuration bool mEnabled = false; ///< Enables debugging features. - glm::uvec2 mSelectedPixel = { 0, 0 }; ///< Currently selected pixel. + uint2 mSelectedPixel = { 0, 0 }; ///< Currently selected pixel. // Runtime data - glm::uvec2 mFrameDim = { 0, 0 }; + uint2 mFrameDim = { 0, 0 }; bool mRunning = false; ///< True when data collection is running (inbetween begin()/end() calls). bool mWaitingForData = false; ///< True if we are waiting for data to become available on the GPU. diff --git a/Source/Falcor/Utils/Debug/PixelDebug.slang b/Source/Falcor/Utils/Debug/PixelDebug.slang index 74ba283b5..62b06d649 100644 --- a/Source/Falcor/Utils/Debug/PixelDebug.slang +++ b/Source/Falcor/Utils/Debug/PixelDebug.slang @@ -49,18 +49,18 @@ cbuffer PixelDebugCB RWStructuredBuffer gPixelLog; RWStructuredBuffer gAssertLog; -#if _PIXEL_DEBUG_ENABLED +#ifdef _PIXEL_DEBUG_ENABLED static uint2 gPixelDebugPixel; #endif void printSetPixel(uint2 pixel) { -#if _PIXEL_DEBUG_ENABLED +#ifdef _PIXEL_DEBUG_ENABLED gPixelDebugPixel = pixel; #endif } -#if _PIXEL_DEBUG_ENABLED +#ifdef _PIXEL_DEBUG_ENABLED /** Define overloaded 'void print(Type x)' functions. Each takes a different basic type as parameter and appends it in encoded form to the log. @@ -68,7 +68,7 @@ void printSetPixel(uint2 pixel) #define PRINT_FUNC(Type, Count, ValueType) \ void print(vector v) \ { \ - if (all(gPixelDebugPixel == gPixelLogSelected)) \ + if (all(gPixelDebugPixel == gPixelLogSelected)) \ { \ uint i = gPixelLog.IncrementCounter(); \ if (i < gPixelLogSize) \ diff --git a/Source/Falcor/Utils/Helpers.slang b/Source/Falcor/Utils/Helpers.slang index 013628877..190179e5c 100644 --- a/Source/Falcor/Utils/Helpers.slang +++ b/Source/Falcor/Utils/Helpers.slang @@ -156,6 +156,8 @@ float4 applyAmbientOcclusion(float4 color, Texture2D aoTex, SamplerState s, floa return float4(color.rgb * aoFactor, color.a); } +// TODO: this function is broken an may return negative values. +// Issue #780 float getMetallic(float3 diffuse, float3 spec) { // This is based on the way that UE4 and Substance Painter 2 converts base+metallic+specular level to diffuse/spec colors @@ -163,6 +165,7 @@ float getMetallic(float3 diffuse, float3 spec) // Note that I'm using the luminance here instead of the actual colors. The reason is that there's no guaraentee that all RGB channels will end up with the same metallic value float d = luminance(diffuse); float s = luminance(spec); + if (s == 0) return 0; float a = 0.04; float b = s + d - 0.08; float c = 0.04 - s; diff --git a/Source/Falcor/Utils/HostDeviceShared.slangh b/Source/Falcor/Utils/HostDeviceShared.slangh index f98e5da28..e36015f89 100644 --- a/Source/Falcor/Utils/HostDeviceShared.slangh +++ b/Source/Falcor/Utils/HostDeviceShared.slangh @@ -40,6 +40,12 @@ /******************************************************************* CPU declarations *******************************************************************/ + +using uint = uint32_t; +using float3x3 = glm::float3x3; +using float3x4 = glm::float3x4; +using float4x4 = glm::float4x4; + #define BEGIN_NAMESPACE_FALCOR namespace Falcor{ #define END_NAMESPACE_FALCOR } #define SETTER_DECL @@ -49,7 +55,7 @@ /******************************************************************* HLSL declarations *******************************************************************/ -#define inline +#define inline #define SETTER_DECL [mutating] #define BEGIN_NAMESPACE_FALCOR #define END_NAMESPACE_FALCOR diff --git a/Source/Falcor/Utils/Math/AABB.h b/Source/Falcor/Utils/Math/AABB.h index be245b480..601f197e6 100644 --- a/Source/Falcor/Utils/Math/AABB.h +++ b/Source/Falcor/Utils/Math/AABB.h @@ -34,8 +34,8 @@ namespace Falcor */ struct BoundingBox { - glm::vec3 center; ///< Center position of the bounding box - glm::vec3 extent; ///< Half length of each side. Essentially the coordinates to the max corner relative to the center. + float3 center; ///< Center position of the bounding box + float3 extent; ///< Half length of each side. Essentially the coordinates to the max corner relative to the center. /** Checks whether two bounding boxes are equivalent in position and size */ @@ -50,27 +50,27 @@ namespace Falcor */ BoundingBox transform(const glm::mat4& mat) const { - glm::vec3 min = center - extent; - glm::vec3 max = center + extent; + float3 min = center - extent; + float3 max = center + extent; - glm::vec3 xa = glm::vec3(mat[0] * min.x); - glm::vec3 xb = glm::vec3(mat[0] * max.x); - glm::vec3 xMin = glm::min(xa, xb); - glm::vec3 xMax = glm::max(xa, xb); + float3 xa = float3(mat[0] * min.x); + float3 xb = float3(mat[0] * max.x); + float3 xMin = glm::min(xa, xb); + float3 xMax = glm::max(xa, xb); - glm::vec3 ya = glm::vec3(mat[1] * min.y); - glm::vec3 yb = glm::vec3(mat[1] * max.y); - glm::vec3 yMin = glm::min(ya, yb); - glm::vec3 yMax = glm::max(ya, yb); + float3 ya = float3(mat[1] * min.y); + float3 yb = float3(mat[1] * max.y); + float3 yMin = glm::min(ya, yb); + float3 yMax = glm::max(ya, yb); - glm::vec3 za = glm::vec3(mat[2] * min.z); - glm::vec3 zb = glm::vec3(mat[2] * max.z); - glm::vec3 zMin = glm::min(za, zb); - glm::vec3 zMax = glm::max(za, zb); + float3 za = float3(mat[2] * min.z); + float3 zb = float3(mat[2] * max.z); + float3 zMin = glm::min(za, zb); + float3 zMax = glm::max(za, zb); - glm::vec3 newMin = xMin + yMin + zMin + glm::vec3(mat[3]); - glm::vec3 newMax = xMax + yMax + zMax + glm::vec3(mat[3]); + float3 newMin = xMin + yMin + zMin + float3(mat[3]); + float3 newMax = xMax + yMax + zMax + float3(mat[3]); return BoundingBox::fromMinMax(newMin, newMax); } @@ -78,7 +78,7 @@ namespace Falcor /** Gets the minimum position of the bounding box \return Minimum position */ - glm::vec3 getMinPos() const + float3 getMinPos() const { return center - extent; } @@ -86,7 +86,7 @@ namespace Falcor /** Gets the maximum position of the bounding box \return Maximum position */ - glm::vec3 getMaxPos() const + float3 getMaxPos() const { return center + extent; } @@ -94,7 +94,7 @@ namespace Falcor /** Gets the size of each dimension of the bounding box. \return X,Y and Z lengths of the bounding box */ - glm::vec3 getSize() const + float3 getSize() const { return extent * 2.0f; } @@ -104,11 +104,11 @@ namespace Falcor \param[in] max Maximum point \return A bounding box */ - static BoundingBox fromMinMax(const glm::vec3& min, const glm::vec3& max) + static BoundingBox fromMinMax(const float3& min, const float3& max) { BoundingBox box; - box.center = (max + min) * glm::vec3(0.5f); - box.extent = (max - min) * glm::vec3(0.5f); + box.center = (max + min) * float3(0.5f); + box.extent = (max - min) * float3(0.5f); return box; } diff --git a/Source/Falcor/Utils/Math/BBox.h b/Source/Falcor/Utils/Math/BBox.h index 4eca0deba..74d5b0551 100644 --- a/Source/Falcor/Utils/Math/BBox.h +++ b/Source/Falcor/Utils/Math/BBox.h @@ -37,8 +37,8 @@ namespace Falcor */ struct BBox { - glm::float3 minPoint = glm::float3(std::numeric_limits::infinity()); // +inf - glm::float3 maxPoint = glm::float3(-std::numeric_limits::infinity()); // -inf + float3 minPoint = float3(std::numeric_limits::infinity()); // +inf + float3 maxPoint = float3(-std::numeric_limits::infinity()); // -inf BBox() {} BBox(const glm::float3& p) : minPoint(p), maxPoint(p) {} @@ -47,15 +47,15 @@ namespace Falcor bool valid() const { return maxPoint.x >= minPoint.x && maxPoint.y >= minPoint.y && maxPoint.z >= minPoint.z; } /** Returns the dimensions of the bounding box. */ - glm::float3 dimensions() const { return maxPoint - minPoint; } + float3 dimensions() const { return maxPoint - minPoint; } /** Returns the centroid of the bounding box. */ - glm::float3 centroid() const { return (minPoint + maxPoint) * 0.5f; } + float3 centroid() const { return (minPoint + maxPoint) * 0.5f; } /** Returns the surface area of the bounding box. */ float surfaceArea() const { - const glm::float3 dims = dimensions(); + const float3 dims = dimensions(); return 2.0f * (dims.x * dims.y + dims.y * dims.z + dims.x * dims.z); } @@ -70,7 +70,7 @@ namespace Falcor return -std::numeric_limits::infinity(); } - const glm::float3 dims = glm::max(glm::vec3(epsilon), dimensions()); + const float3 dims = glm::max(float3(epsilon), dimensions()); return dims.x * dims.y * dims.z; } diff --git a/Source/Falcor/Utils/Math/FalcorMath.h b/Source/Falcor/Utils/Math/FalcorMath.h index b1303cea3..2b0488dad 100644 --- a/Source/Falcor/Utils/Math/FalcorMath.h +++ b/Source/Falcor/Utils/Math/FalcorMath.h @@ -43,11 +43,11 @@ namespace Falcor \param[in] from The source vector \param[in] to The destination vector */ - inline glm::quat createQuaternionFromVectors(const glm::vec3& from, const glm::vec3& to) + inline glm::quat createQuaternionFromVectors(const float3& from, const float3& to) { glm::quat quat; - glm::vec3 nFrom = glm::normalize(from); - glm::vec3 nTo = glm::normalize(to); + float3 nFrom = glm::normalize(from); + float3 nTo = glm::normalize(to); float dot = glm::dot(nFrom, nTo); dot = clamp(dot, -1.0f, 1.0f); @@ -55,8 +55,8 @@ namespace Falcor { float angle = acosf(dot); - glm::vec3 cross = glm::cross(nFrom, nTo); - glm::vec3 axis = glm::normalize(cross); + float3 cross = glm::cross(nFrom, nTo); + float3 axis = glm::normalize(cross); quat = glm::angleAxis(angle, axis); } @@ -70,22 +70,22 @@ namespace Falcor \param[in] projMat Projection matrix from the camera. \return World space ray direction coming from the camera position in the direction of the mouse position */ - inline glm::vec3 mousePosToWorldRay(const glm::vec2& mousePos, const glm::mat4& viewMat, const glm::mat4& projMat) + inline float3 mousePosToWorldRay(const float2& mousePos, const glm::mat4& viewMat, const glm::mat4& projMat) { // Convert from [0, 1] to [-1, 1] range const float x = mousePos.x * 2.0f - 1.0f; // Vulkan has flipped Y in clip space. Otherwise Y has to be flipped - const float y = + const float y = #ifdef FALCOR_VK mousePos.y #else - (1.0f - mousePos.y) + (1.0f - mousePos.y) #endif * 2.0f - 1.0f; // NDC/Clip - glm::vec4 ray(x, y, -1.0f, 1.0f); + float4 ray(x, y, -1.0f, 1.0f); // View ray = glm::inverse(projMat) * ray; @@ -101,11 +101,11 @@ namespace Falcor \param[in] up Up vector. \return 3x3 rotation matrix. */ - inline glm::mat3 createMatrixFromBasis(const glm::vec3& forward, const glm::vec3& up) + inline glm::mat3 createMatrixFromBasis(const float3& forward, const float3& up) { - glm::vec3 f = glm::normalize(forward); - glm::vec3 s = glm::normalize(glm::cross(up, forward)); - glm::vec3 u = glm::cross(f, s); + float3 f = glm::normalize(forward); + float3 s = glm::normalize(glm::cross(up, forward)); + float3 u = glm::cross(f, s); return glm::mat3(s, u, f); } @@ -116,7 +116,7 @@ namespace Falcor \param[in] up Object's up vector. \return 3x3 rotation matrix. */ - inline glm::mat3 createMatrixFromLookAt(const glm::vec3& position, const glm::vec3& target, const glm::vec3& up) + inline glm::mat3 createMatrixFromLookAt(const float3& position, const float3& target, const float3& up) { return createMatrixFromBasis(target - position, up); } @@ -124,7 +124,7 @@ namespace Falcor /** Projects a 2D coordinate onto a unit sphere \param xy The 2D coordinate. if x and y are in the [0,1) range, then a z value can be calculate. Otherwise, xy is normalized and z is zero. */ - inline glm::vec3 project2DCrdToUnitSphere(glm::vec2 xy) + inline float3 project2DCrdToUnitSphere(float2 xy) { float xyLengthSquared = glm::dot(xy, xy); @@ -137,7 +137,7 @@ namespace Falcor { xy = glm::normalize(xy); } - return glm::vec3(xy.x, xy.y, z); + return float3(xy.x, xy.y, z); } /** Calculates vertical FOV in radians from camera parameters. @@ -193,26 +193,26 @@ namespace Falcor return float(i) * 2.3283064365386963e-10f; } - inline vec3 hammersleyUniform(uint32_t i, uint32_t n) + inline float3 hammersleyUniform(uint32_t i, uint32_t n) { - vec2 uv((float)i / (float)n, radicalInverse(i)); + float2 uv((float)i / (float)n, radicalInverse(i)); // Map to radius 1 hemisphere float phi = uv.y * 2.0f * (float)M_PI; float t = 1.0f - uv.x; float s = sqrt(1.0f - t * t); - return vec3(s * cos(phi), s * sin(phi), t); + return float3(s * cos(phi), s * sin(phi), t); } - inline vec3 hammersleyCosine(uint32_t i, uint32_t n) + inline float3 hammersleyCosine(uint32_t i, uint32_t n) { - vec2 uv((float)i / (float)n, radicalInverse(i)); + float2 uv((float)i / (float)n, radicalInverse(i)); // Map to radius 1 hemisphere float phi = uv.y * 2.0f * (float)M_PI; float t = sqrt(1.0f - uv.x); float s = sqrt(1.0f - t * t); - return vec3(s * cos(phi), s * sin(phi), t); + return float3(s * cos(phi), s * sin(phi), t); } #ifndef GLM_CLIP_SPACE_Y_TOPDOWN diff --git a/Source/Falcor/Utils/Math/Vector.h b/Source/Falcor/Utils/Math/Vector.h index 3664f08ca..d4fe226b8 100644 --- a/Source/Falcor/Utils/Math/Vector.h +++ b/Source/Falcor/Utils/Math/Vector.h @@ -33,7 +33,9 @@ namespace Falcor { - using namespace glm; + using float2 = glm::vec2; + using float3 = glm::vec3; + using float4 = glm::vec4; using uint2 = glm::uvec2; using uint3 = glm::uvec3; @@ -43,18 +45,23 @@ namespace Falcor using int3 = glm::ivec3; using int4 = glm::ivec4; - // We cannot use glm::to_string inline because including "glm/gtx/string_cast.hpp" together - // with "using namespace glm" pollutes the namespace with many to_string functions. + using bool2 = glm::bvec2; + using bool3 = glm::bvec3; + using bool4 = glm::bvec4; - inline std::string to_string(const glm::vec2& v) { return "vec2(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")"; } - inline std::string to_string(const glm::vec3& v) { return "vec3(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + ")"; } - inline std::string to_string(const glm::vec4& v) { return "vec4(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + "," + std::to_string(v.w) + ")"; } + inline std::string to_string(const float2& v) { return "float2(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")"; } + inline std::string to_string(const float3& v) { return "float3(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + ")"; } + inline std::string to_string(const float4& v) { return "float4(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + "," + std::to_string(v.w) + ")"; } - inline std::string to_string(const glm::uvec2& v) { return "uvec2(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")"; } - inline std::string to_string(const glm::uvec3& v) { return "uvec3(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + ")"; } - inline std::string to_string(const glm::uvec4& v) { return "uvec4(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + "," + std::to_string(v.w) + ")"; } + inline std::string to_string(const uint2& v) { return "uint2(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")"; } + inline std::string to_string(const uint3& v) { return "uint3(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + ")"; } + inline std::string to_string(const uint4& v) { return "uint4(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + "," + std::to_string(v.w) + ")"; } - inline std::string to_string(const glm::ivec2& v) { return "ivec2(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")"; } - inline std::string to_string(const glm::ivec3& v) { return "ivec3(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + ")"; } - inline std::string to_string(const glm::ivec4& v) { return "ivec4(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + "," + std::to_string(v.w) + ")"; } + inline std::string to_string(const int2& v) { return "int2(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")"; } + inline std::string to_string(const int3& v) { return "int3(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + ")"; } + inline std::string to_string(const int4& v) { return "int4(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + "," + std::to_string(v.w) + ")"; } + + inline std::string to_string(const bool2& v) { return "bool2(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")"; } + inline std::string to_string(const bool3& v) { return "bool3(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + ")"; } + inline std::string to_string(const bool4& v) { return "bool4(" + std::to_string(v.x) + "," + std::to_string(v.y) + "," + std::to_string(v.z) + "," + std::to_string(v.w) + ")"; } } diff --git a/Source/Falcor/Utils/SampleGenerators/CPUSampleGenerator.h b/Source/Falcor/Utils/SampleGenerators/CPUSampleGenerator.h index 64cbbec79..70643c44d 100644 --- a/Source/Falcor/Utils/SampleGenerators/CPUSampleGenerator.h +++ b/Source/Falcor/Utils/SampleGenerators/CPUSampleGenerator.h @@ -49,7 +49,7 @@ namespace Falcor /** Return the next two-dimensional sample. \return Sample in the range [-0.5, 0.5) in each dimension. */ - virtual glm::vec2 next() = 0; + virtual float2 next() = 0; protected: CPUSampleGenerator() = default; diff --git a/Source/Falcor/Utils/SampleGenerators/DxSamplePattern.cpp b/Source/Falcor/Utils/SampleGenerators/DxSamplePattern.cpp index 071e146f5..924176ea2 100644 --- a/Source/Falcor/Utils/SampleGenerators/DxSamplePattern.cpp +++ b/Source/Falcor/Utils/SampleGenerators/DxSamplePattern.cpp @@ -30,7 +30,7 @@ namespace Falcor { - const vec2 DxSamplePattern::kPattern[] = { { 1.0f / 16.0f, -3.0f / 16.0f }, + const float2 DxSamplePattern::kPattern[] = { { 1.0f / 16.0f, -3.0f / 16.0f }, { -1.0f / 16.0f, 3.0f / 16.0f }, { 5.0f / 16.0f, 1.0f / 16.0f }, { -3.0f / 16.0f, -5.0f / 16.0f }, diff --git a/Source/Falcor/Utils/SampleGenerators/DxSamplePattern.h b/Source/Falcor/Utils/SampleGenerators/DxSamplePattern.h index 2fc75a71d..447cac2fa 100644 --- a/Source/Falcor/Utils/SampleGenerators/DxSamplePattern.h +++ b/Source/Falcor/Utils/SampleGenerators/DxSamplePattern.h @@ -49,7 +49,7 @@ namespace Falcor virtual void reset(uint32_t startID = 0) override { mCurSample = 0; } - virtual vec2 next() override + virtual float2 next() override { return kPattern[(mCurSample++) % kSampleCount]; } @@ -58,6 +58,6 @@ namespace Falcor uint32_t mCurSample = 0; static const uint32_t kSampleCount = 8; - static const vec2 kPattern[kSampleCount]; + static const float2 kPattern[kSampleCount]; }; } diff --git a/Source/Falcor/Utils/SampleGenerators/HaltonSamplePattern.cpp b/Source/Falcor/Utils/SampleGenerators/HaltonSamplePattern.cpp index fd252581b..23e174f77 100644 --- a/Source/Falcor/Utils/SampleGenerators/HaltonSamplePattern.cpp +++ b/Source/Falcor/Utils/SampleGenerators/HaltonSamplePattern.cpp @@ -30,7 +30,7 @@ namespace Falcor { - const vec2 HaltonSamplePattern::kPattern[8] = { { 1.0f / 2.0f - 0.5f, 1.0f / 3.0f - 0.5f }, + const float2 HaltonSamplePattern::kPattern[8] = { { 1.0f / 2.0f - 0.5f, 1.0f / 3.0f - 0.5f }, { 1.0f / 4.0f - 0.5f, 2.0f / 3.0f - 0.5f }, { 3.0f / 4.0f - 0.5f, 1.0f / 9.0f - 0.5f }, { 1.0f / 8.0f - 0.5f, 4.0f / 9.0f - 0.5f }, diff --git a/Source/Falcor/Utils/SampleGenerators/HaltonSamplePattern.h b/Source/Falcor/Utils/SampleGenerators/HaltonSamplePattern.h index d98883f0c..dfb6a0096 100644 --- a/Source/Falcor/Utils/SampleGenerators/HaltonSamplePattern.h +++ b/Source/Falcor/Utils/SampleGenerators/HaltonSamplePattern.h @@ -47,7 +47,7 @@ namespace Falcor virtual void reset(uint32_t startID = 0) override { mCurSample = 0; } - virtual vec2 next() override + virtual float2 next() override { return kPattern[(mCurSample++) % mSampleCount]; } @@ -56,6 +56,6 @@ namespace Falcor uint32_t mCurSample = 0; uint32_t mSampleCount = 0; - static const vec2 kPattern[]; + static const float2 kPattern[]; }; } diff --git a/Source/Falcor/Utils/SampleGenerators/StratifiedSamplePattern.cpp b/Source/Falcor/Utils/SampleGenerators/StratifiedSamplePattern.cpp index a2e0d4fac..314e9949e 100644 --- a/Source/Falcor/Utils/SampleGenerators/StratifiedSamplePattern.cpp +++ b/Source/Falcor/Utils/SampleGenerators/StratifiedSamplePattern.cpp @@ -65,7 +65,7 @@ namespace Falcor mRng = std::mt19937(); } - glm::vec2 StratifiedSamplePattern::next() + float2 StratifiedSamplePattern::next() { auto dist = std::uniform_real_distribution(); auto u = [&]() { return dist(mRng); }; @@ -82,6 +82,6 @@ namespace Falcor assert(i < mBinsX && j < mBinsY); float x = ((float)i + u()) / mBinsX; float y = ((float)j + u()) / mBinsY; - return glm::vec2(x, y) - 0.5f; + return float2(x, y) - 0.5f; } } diff --git a/Source/Falcor/Utils/SampleGenerators/StratifiedSamplePattern.h b/Source/Falcor/Utils/SampleGenerators/StratifiedSamplePattern.h index 277e799b9..2ae189f35 100644 --- a/Source/Falcor/Utils/SampleGenerators/StratifiedSamplePattern.h +++ b/Source/Falcor/Utils/SampleGenerators/StratifiedSamplePattern.h @@ -56,7 +56,7 @@ namespace Falcor virtual uint32_t getSampleCount() const override { return mBinsX * mBinsY; } virtual void reset(uint32_t startID = 0) override; - virtual vec2 next() override; + virtual float2 next() override; protected: StratifiedSamplePattern(uint32_t sampleCount); diff --git a/Source/Falcor/Utils/Scripting/ScriptBindings.cpp b/Source/Falcor/Utils/Scripting/ScriptBindings.cpp index 4f8a8c2d4..31eea69b2 100644 --- a/Source/Falcor/Utils/Scripting/ScriptBindings.cpp +++ b/Source/Falcor/Utils/Scripting/ScriptBindings.cpp @@ -97,20 +97,25 @@ namespace Falcor::ScriptBindings PYBIND11_EMBEDDED_MODULE(falcor, m) { - // Alias python's True/False to true/false - m.attr("true") = true; - m.attr("false") = false; + // bool2, bool3, bool4 + addVecType(m, "bool2"); + addVecType(m, "bool3"); + addVecType(m, "bool4"); - // Bind glm vectors to Python - addVecType(m, "vec2"); - addVecType(m, "vec3"); - addVecType(m, "vec4"); - addVecType(m, "uvec2"); - addVecType(m, "uvec3"); - addVecType(m, "uvec4"); - addVecType(m, "ivec2"); - addVecType(m, "ivec3"); - addVecType(m, "ivec4"); + // float2, float3, float4 + addVecType(m, "float2"); + addVecType(m, "float3"); + addVecType(m, "float4"); + + // int2, int3, int4 + addVecType(m, "int2"); + addVecType(m, "int3"); + addVecType(m, "int4"); + + // uint2, uint3, uint4 + addVecType(m, "uint2"); + addVecType(m, "uint3"); + addVecType(m, "uint4"); if (gBindFuncs) { diff --git a/Source/Falcor/Utils/Scripting/Scripting.cpp b/Source/Falcor/Utils/Scripting/Scripting.cpp index 5c9eab6f2..ec232b1ce 100644 --- a/Source/Falcor/Utils/Scripting/Scripting.cpp +++ b/Source/Falcor/Utils/Scripting/Scripting.cpp @@ -63,11 +63,11 @@ namespace Falcor case 1: falcorDict[name] = floatVec[0]; break; case 2: - falcorDict[name] = vec2(floatVec[0], floatVec[1]); break; + falcorDict[name] = float2(floatVec[0], floatVec[1]); break; case 3: - falcorDict[name] = vec3(floatVec[0], floatVec[1], floatVec[2]); break; + falcorDict[name] = float3(floatVec[0], floatVec[1], floatVec[2]); break; case 4: - falcorDict[name] = vec4(floatVec[0], floatVec[1], floatVec[2], floatVec[3]); break; + falcorDict[name] = float4(floatVec[0], floatVec[1], floatVec[2], floatVec[3]); break; default: falcorDict[name] = floatVec; } diff --git a/Source/Falcor/Utils/Scripting/Scripting.h b/Source/Falcor/Utils/Scripting/Scripting.h index 63a3a4299..d019922dd 100644 --- a/Source/Falcor/Utils/Scripting/Scripting.h +++ b/Source/Falcor/Utils/Scripting/Scripting.h @@ -129,6 +129,25 @@ namespace Falcor s += std::string(".") + makeFunc(func, first, args...); return s; } + + static std::string makeGetProperty(const std::string& var, const std::string& property) + { + return var + "." + property + "\n"; + } + + template + static std::string makeSetProperty(const std::string& var, const std::string& property, Arg arg) + { + return var + "." + property + " = " + getArgString(arg) + "\n"; + } + + static std::string getFilenameString(const std::string& s, bool stripDataDirs = true) + { + std::string filename = stripDataDirs ? stripDataDirectories(s) : s; + std::replace(filename.begin(), filename.end(), '\\', '/'); + return filename; + } + private: static bool sRunning; }; diff --git a/Source/Falcor/Utils/StringUtils.h b/Source/Falcor/Utils/StringUtils.h index 5bd14d872..e49fc9e3b 100644 --- a/Source/Falcor/Utils/StringUtils.h +++ b/Source/Falcor/Utils/StringUtils.h @@ -27,6 +27,8 @@ **************************************************************************/ #pragma once #include +#include +#include #include #include #include @@ -252,11 +254,32 @@ namespace Falcor */ inline void copyStringToBuffer(char* buffer, uint32_t bufferSize, const std::string& s) { - const uint32_t length = min(bufferSize - 1, (uint32_t)s.length()); + const uint32_t length = std::min(bufferSize - 1, (uint32_t)s.length()); s.copy(buffer, length); buffer[length] = '\0'; } + /** Converts a size in bytes to a human readable string: + - prints bytes (B) if size < 512 bytes + - prints kilobytes (KB) if size < 512 kilobytes + - prints megabytes (MB) if size < 512 megabytes + - otherwise prints gigabytes (GB) + \param[in] size Size in bytes + \return Returns a human readable string. + */ + inline std::string formatByteSize(size_t size) + { + std::ostringstream oss; + oss << std::fixed << std::setprecision(1); + + if (size < 512) oss << size << "B"; + else if (size < 512 * 1024) oss << (size / 1024.0) << "KB"; + else if (size < 512 * 1024 * 1024) oss << (size / (1024.0 * 1024.0)) << "MB"; + else oss << (size / (1024.0 * 1024.0 * 1024.0)) << "GB"; + + return oss.str(); + } + /** Convert an ASCII string to a UTF-8 wstring */ inline std::wstring string_2_wstring(const std::string& s) diff --git a/Source/Falcor/Utils/Timing/Clock.cpp b/Source/Falcor/Utils/Timing/Clock.cpp index dbb51f5ef..408c11d77 100644 --- a/Source/Falcor/Utils/Timing/Clock.cpp +++ b/Source/Falcor/Utils/Timing/Clock.cpp @@ -32,14 +32,16 @@ namespace Falcor { namespace { - constexpr char kNow[] = "now"; + constexpr char kTime[] = "time"; + constexpr char kFrame[] = "frame"; + constexpr char kFramerate[] = "framerate"; + constexpr char kTimeScale[] = "timeScale"; + constexpr char kExitTime[] = "exitTime"; + constexpr char kExitFrame[] = "exitFrame"; constexpr char kPause[] = "pause"; constexpr char kPlay[] = "play"; constexpr char kStop[] = "stop"; - constexpr char kSimFps[] = "fpsSim"; - constexpr char kFrame[] = "frame"; constexpr char kStep[] = "step"; - constexpr char kFramerate[] = "framerate"; std::optional fpsDropdown(Gui::Window& w, uint32_t curVal) { @@ -93,26 +95,45 @@ namespace Falcor } } - Clock::Clock() { now(0); } + Clock::Clock() { setTime(0); } - Clock& Clock::framerate(uint32_t fps) + Clock& Clock::setFramerate(uint32_t fps) { mFramerate = fps; mTicksPerFrame = 0; if(fps) { - if (kTicksPerSecond % fps) logWarning("Clock::framerate() - requesetd FPS can't be accurately representated. Expect roudning errors"); + if (kTicksPerSecond % fps) logWarning("Clock::setFramerate() - requested FPS can't be accurately representated. Expect roudning errors"); mTicksPerFrame = kTicksPerSecond / fps; } - if(!mDeferredFrameID && !mDeferredTime) now(mTime.now); + if(!mDeferredFrameID && !mDeferredTime) setTime(mTime.now); + return *this; + } + + Clock& Clock::setExitTime(double seconds) + { + mExitTime = seconds; + mExitFrame = 0; return *this; } + Clock& Clock::setExitFrame(uint64_t frame) + { + mExitFrame = frame; + mExitTime = 0.0; + return *this; + } + + bool Clock::shouldExit() const + { + return ((mExitTime && getTime() >= mExitTime) || (mExitFrame && getFrame() >= mExitFrame)); + } + Clock& Clock::tick() { - if (mDeferredFrameID) frame(mDeferredFrameID.value()); - else if (mDeferredTime) now(mDeferredTime.value()); + if (mDeferredFrameID) setFrame(mDeferredFrameID.value()); + else if (mDeferredTime) setTime(mDeferredTime.value()); else if(!mPaused) step(); return *this; } @@ -129,7 +150,7 @@ namespace Falcor mDeferredFrameID = std::nullopt; } - Clock& Clock::now(double seconds, bool deferToNextTick) + Clock& Clock::setTime(double seconds, bool deferToNextTick) { resetDeferredObjects(); @@ -153,7 +174,7 @@ namespace Falcor return *this; } - Clock& Clock::frame(uint64_t f, bool deferToNextTick) + Clock& Clock::setFrame(uint64_t f, bool deferToNextTick) { resetDeferredObjects(); @@ -188,7 +209,7 @@ namespace Falcor else mFrames += frames; updateTimer(); - double t = simulatingFps() ? timeFromFrame(mFrames, mTicksPerFrame) : ((mTimer.delta() * mScale) + mTime.now); + double t = isSimulatingFps() ? timeFromFrame(mFrames, mTicksPerFrame) : ((mTimer.delta() * mScale) + mTime.now); mTime.update(t); return *this; } @@ -197,16 +218,16 @@ namespace Falcor { const auto& tex = gClockTextures; - float time = (float)now(); - float scale = (float)timeScale(); - if (w.var("Time##Cur", time, 0.f, FLT_MAX, 0.001f, false, "%.3f")) now(time); - if (!simulatingFps() && w.var("Scale", scale)) timeScale(scale); - bool showStep = mPaused && simulatingFps(); + float time = (float)getTime(); + float scale = (float)getTimeScale(); + if (w.var("Time##Cur", time, 0.f, FLT_MAX, 0.001f, false, "%.3f")) setTime(time); + if (!isSimulatingFps() && w.var("Scale", scale)) setTimeScale(scale); + bool showStep = mPaused && isSimulatingFps(); float indent = showStep ? 10.0f : 60.0f; w.indent(indent); - static const uvec2 iconSize = { 25, 25 }; - if (w.imageButton("Rewind", tex.pRewind, iconSize)) now(0); + static const uint2 iconSize = { 25, 25 }; + if (w.imageButton("Rewind", tex.pRewind, iconSize)) setTime(0); if (showStep && w.imageButton("PrevFrame", tex.pPrevFrame, iconSize, true, true)) step(-1); if (w.imageButton("Stop", tex.pStop, iconSize, true, true)) stop(); auto pTex = mPaused ? tex.pPlay : tex.pPause; @@ -220,34 +241,33 @@ namespace Falcor w.tooltip("Simulate a constant frame rate. The time will advance by 1/FPS each frame, regardless of the actual frame rendering time"); auto fps = fpsDropdown(w, mFramerate); - if (fps) framerate(fps.value()); + if (fps) setFramerate(fps.value()); - if (simulatingFps()) + if (isSimulatingFps()) { - uint64_t curFrame = frame(); - if (w.var("Frame ID", curFrame)) frame(curFrame); + uint64_t curFrame = getFrame(); + if (w.var("Frame ID", curFrame)) setFrame(curFrame); } } SCRIPT_BINDING(Clock) { auto c = m.regClass(Clock); - c.func_(kNow, ScriptBindings::overload_cast<>(&Clock::now, ScriptBindings::const_)); - - auto now = [](Clock* pClock, double secs) {pClock->now(secs, true); }; - c.func_(kNow, now, "seconds"_a); - - c.func_(kFrame, ScriptBindings::overload_cast<>(&Clock::frame, ScriptBindings::const_)); - auto frame = [](Clock* pClock, uint64_t f) {pClock->frame(f, true); }; - c.func_(kFrame, frame, "frameID"_a); + + auto setTime = [](Clock* pClock, double t) {pClock->setTime(t, true); }; + c.property(kTime, &Clock::getTime, setTime); + auto setFrame = [](Clock* pClock, uint64_t f) {pClock->setFrame(f, true); }; + c.property(kFrame, &Clock::getFrame, setFrame); + c.property(kFramerate, &Clock::getFramerate, &Clock::setFramerate); + c.property(kTimeScale, &Clock::getTimeScale, &Clock::setTimeScale); + c.property(kExitTime, &Clock::getExitTime, &Clock::setExitTime); + c.property(kExitFrame, &Clock::getExitFrame, &Clock::setExitFrame); c.func_(kPause, &Clock::pause); c.func_(kPlay, &Clock::play); c.func_(kStop, &Clock::stop); - c.func_(kPause, &Clock::pause); c.func_(kStep, &Clock::step, "frames"_a = 1); - c.func_(kFramerate, ScriptBindings::overload_cast(&Clock::framerate)); - c.func_(kFramerate, ScriptBindings::overload_cast<>(&Clock::framerate, ScriptBindings::const_)); + } void Clock::start() @@ -274,10 +294,12 @@ namespace Falcor std::string Clock::getScript(const std::string& var) const { std::string s; - s += Scripting::makeMemberFunc(var, kNow, 0); - s += Scripting::makeMemberFunc(var, kFramerate, mFramerate); - s += std::string("# If ") + kFramerate + "() is not zero, you can use the following function to set the start frame\n"; - s += "# " + Scripting::makeMemberFunc(var, kFrame, 0); + s += Scripting::makeSetProperty(var, kTime, 0); + s += Scripting::makeSetProperty(var, kFramerate, mFramerate); + if (mExitTime) s += Scripting::makeSetProperty(var, kExitTime, mExitTime); + if (mExitFrame) s += Scripting::makeSetProperty(var, kExitFrame, mExitFrame); + s += std::string("# If ") + kFramerate + " is not zero, you can use the frame property to set the start frame\n"; + s += "# " + Scripting::makeSetProperty(var, kFrame, 0); if (mPaused) s += Scripting::makeMemberFunc(var, kPause); return s; } diff --git a/Source/Falcor/Utils/Timing/Clock.h b/Source/Falcor/Utils/Timing/Clock.h index 5911d793a..15f5cb567 100644 --- a/Source/Falcor/Utils/Timing/Clock.h +++ b/Source/Falcor/Utils/Timing/Clock.h @@ -50,17 +50,26 @@ namespace Falcor \param[in] seconds The time in seconds \param[in] deferToNextTick Apply the change on the next tick. No changes will be made to the clock until the next tick */ - Clock& now(double seconds, bool deferToNextTick = false); + Clock& setTime(double seconds, bool deferToNextTick = false); + + deprecate("4.0.1", "Use setTime() instead.") + Clock& now(double seconds, bool deferToNextTick = false) { return setTime(seconds, deferToNextTick); } /** Get the time of the last `tick()` call */ - double now() const { return mTime.now; } + double getTime() const { return mTime.now; } + + deprecate("4.0.1", "Use getTime() instead.") + double now() const { return getTime(); } /** Get the time delta between the 2 previous ticks. This function respects the FPS simulation setting Note that due to floating-point precision, this function won't necessarily return exactly (1/FPS) when simulating framerate. This function will potentially return a negative number, for example when resetting the time to zero */ - double delta() const { return mTime.delta; } + double getDelta() const { return mTime.delta; } + + deprecate("4.0.1", "Use getDelta() instead.") + double delta() const { return getDelta(); } /** Set the current frame ID. Calling this will cause the next `tick()` call to be skipped When running in real-time mode, it will only change the frame number without affecting the time @@ -68,21 +77,48 @@ namespace Falcor \param[in] seconds The frame ID \param[in] deferToNextTick Apply the change on the next tick. No changes will be made to the clock until the next tick */ - Clock& frame(uint64_t f, bool deferToNextTick = false); + Clock& setFrame(uint64_t f, bool deferToNextTick = false); + + deprecate("4.0.1", "Use setFame() instead.") + Clock& frame(uint64_t f, bool deferToNextTick = false) { return setFrame(f, deferToNextTick); } /** Get the current frame ID. When running in real-time mode, this is the number of frames since the last time the time was set. When simulating FPS, the number of frames according to the time */ - uint64_t frame() const { return mFrames; } + uint64_t getFrame() const { return mFrames; } + + deprecate("4.0.1", "Use getFrame() instead.") + uint64_t frame() const { return getFrame(); } /** Get the real-time delta between the 2 previous ticks. This function returns the actual time that passed between the 2 `tick()` calls. It doesn't any time-manipulation setting like time-scaling and FPS simulation */ - double realTimeDelta() const { return mRealtime.delta; } + double getRealTimeDelta() const { return mRealtime.delta; } + + deprecate("4.0.1", "Use getRealTimeDelta() instead.") + double realTimeDelta() const { return getRealTimeDelta(); } - /** Get the real-time time in seconds. + /** Set the time at which to terminate the application. */ + Clock& setExitTime(double seconds); + + /** Get the time at which to terminate the application. + */ + double getExitTime() const { return mExitTime; } + + /** Set the frame at which to terminate the application. + */ + Clock& setExitFrame(uint64_t frame); + + /** Get the frame at which to terminate the application. + */ + uint64_t getExitFrame() const { return mExitFrame; } + + /** Check if the application should be terminated. + */ + bool shouldExit() const; + /** Tick the clock. Calling this function has no effect if the clock is paused */ Clock& tick(); @@ -91,11 +127,17 @@ namespace Falcor When enabling FPS simulation, calls to tick() will change the time by `1/FPS` seconds. If FPS simulation is disabled, calling `tick()` will add the actual time that passed since the previous `tick()` call */ - Clock& framerate(uint32_t fps); + Clock& setFramerate(uint32_t fps); + + deprecate("4.0.1", "Use setFramerate() instead.") + Clock& framerate(uint32_t fps) { return setFramerate(fps); } /** Get the requested FPS value */ - uint32_t framerate() const { return mFramerate; } + uint32_t getFramerate() const { return mFramerate; } + + deprecate("4.0.1", "Use getFramerate() instead.") + uint32_t framerate() const { return getFramerate(); } /** Pause the clock */ @@ -107,7 +149,7 @@ namespace Falcor /** Stop the clock (pause + reset) */ - Clock& stop() { now(0); return pause(); } + Clock& stop() { setTime(0); return pause(); } /** Step forward or backward. Ignored if the Clock is running or not in FPS simulation mode \param[in] frames The number of frames to step. Can be negative @@ -117,11 +159,17 @@ namespace Falcor /** Set the time scale. This value is ignored when simulating FPS */ - Clock& timeScale(double scale) { mScale = scale; return *this; } + Clock& setTimeScale(double scale) { mScale = scale; return *this; } + + deprecate("4.0.1", "Use setTimeScale() instead.") + Clock& timeScale(double scale) { return setTimeScale(scale); } /** Get the scale */ - double timeScale() const { return mScale; } + double getTimeScale() const { return mScale; } + + deprecate("4.0.1", "Use getTimeScale() instead.") + double timeScale() const { return getTimeScale(); } /** Check if the clock is paused */ @@ -129,7 +177,10 @@ namespace Falcor /** Check if the clock is in real-time mode */ - bool simulatingFps() const { return mFramerate != 0; } + bool isSimulatingFps() const { return mFramerate != 0; } + + deprecate("4.0.1", "Use isSimulatingFps() instead.") + bool simulatingFps() const { return isSimulatingFps(); } /** Render the UI */ @@ -160,6 +211,9 @@ namespace Falcor std::optional mDeferredTime; std::optional mDeferredFrameID; + double mExitTime = 0.0; + uint64_t mExitFrame = 0; + void updateTimer(); void resetDeferredObjects(); }; diff --git a/Source/Falcor/Utils/Timing/FrameRate.h b/Source/Falcor/Utils/Timing/FrameRate.h index 01d37f1bb..52ce35bb6 100644 --- a/Source/Falcor/Utils/Timing/FrameRate.h +++ b/Source/Falcor/Utils/Timing/FrameRate.h @@ -48,7 +48,7 @@ namespace Falcor void reset() { mFrameCount = 0; - mClock.now(0).tick(); + mClock.setTime(0).tick(); } /** Tick the timer. @@ -57,15 +57,15 @@ namespace Falcor void newFrame() { mFrameCount++; - mFrameTimes[mFrameCount % sFrameWindow] = mClock.tick().realTimeDelta(); - mClock.now(0).tick(); + mFrameTimes[mFrameCount % sFrameWindow] = mClock.tick().getRealTimeDelta(); + mClock.setTime(0).tick(); } /** Get the time in ms it took to render a frame */ double getAverageFrameTime() const { - uint64_t frames = min(mFrameCount, sFrameWindow); + uint64_t frames = std::min(mFrameCount, sFrameWindow); double elapsedTime = 0; for(uint64_t i = 0; i < frames; i++) elapsedTime += mFrameTimes[i]; double time = elapsedTime / double(frames) * 1000; diff --git a/Source/Falcor/Utils/UI/DebugDrawer.cpp b/Source/Falcor/Utils/UI/DebugDrawer.cpp index 5ef37b74a..4cc092b00 100644 --- a/Source/Falcor/Utils/UI/DebugDrawer.cpp +++ b/Source/Falcor/Utils/UI/DebugDrawer.cpp @@ -38,7 +38,7 @@ namespace Falcor return SharedPtr(new DebugDrawer(maxVertices)); } - void DebugDrawer::addLine(const glm::vec3& a, const glm::vec3& b) + void DebugDrawer::addLine(const float3& a, const float3& b) { if (mVertexData.capacity() - mVertexData.size() >= 2) { @@ -58,13 +58,13 @@ namespace Falcor void DebugDrawer::addBoundingBox(const BoundingBox& aabb) { - glm::vec3 min = aabb.center - aabb.extent; - glm::vec3 max = aabb.center + aabb.extent; + float3 min = aabb.center - aabb.extent; + float3 max = aabb.center + aabb.extent; - Quad bottomFace = { min, glm::vec3(max.x, min.y, min.z), glm::vec3(max.x, min.y, max.z), glm::vec3(min.x, min.y, max.z) }; + Quad bottomFace = { min, float3(max.x, min.y, min.z), float3(max.x, min.y, max.z), float3(min.x, min.y, max.z) }; addQuad(bottomFace); - Quad topFace = { glm::vec3(min.x, max.y, min.z), glm::vec3(max.x, max.y, min.z), max, glm::vec3(min.x, max.y, max.z) }; + Quad topFace = { float3(min.x, max.y, min.z), float3(max.x, max.y, min.z), max, float3(min.x, max.y, max.z) }; addQuad(topFace); addLine(bottomFace[0], topFace[0]); @@ -73,14 +73,14 @@ namespace Falcor addLine(bottomFace[3], topFace[3]); } - DebugDrawer::Quad buildQuad(const glm::vec3& center, const glm::vec3& up, const glm::vec3& right) + DebugDrawer::Quad buildQuad(const float3& center, const float3& up, const float3& right) { // Length of each quad side static const float size = 0.08f; // Half widths based on size constant - glm::vec3 upOffset = glm::normalize(up) * size / 2.0f; - glm::vec3 rightOffset = glm::normalize(right) * size / 2.0f; + float3 upOffset = glm::normalize(up) * size / 2.0f; + float3 rightOffset = glm::normalize(right) * size / 2.0f; // CCW from top left DebugDrawer::Quad quad; @@ -94,35 +94,35 @@ namespace Falcor // Generates a quad centered at currFrame's position facing nextFrame's position // DebugDrawer::Quad createQuadForFrame(const ObjectPath::Frame& currFrame, const ObjectPath::Frame& nextFrame) // { -// glm::vec3 forward = nextFrame.position - currFrame.position; -// glm::vec3 right = glm::cross(forward, currFrame.up); -// glm::vec3 up = glm::cross(right, forward); -// +// float3 forward = nextFrame.position - currFrame.position; +// float3 right = glm::cross(forward, currFrame.up); +// float3 up = glm::cross(right, forward); +// // return buildQuad(currFrame.position, up, right); // } // // Generates a quad centered at currFrame's position oriented halfway between direction to prevFrame and direction to nextFrame // DebugDrawer::Quad createQuadForFrame(const ObjectPath::Frame& prevFrame, const ObjectPath::Frame& currFrame, const ObjectPath::Frame& nextFrame) // { -// glm::vec3 lastToCurrFoward = currFrame.position - prevFrame.position; -// glm::vec3 lastToCurrRight = glm::normalize(glm::cross(lastToCurrFoward, prevFrame.up)); -// glm::vec3 lastToCurrUp = glm::normalize(glm::cross(lastToCurrRight, lastToCurrFoward)); -// -// glm::vec3 currToNextFoward = nextFrame.position - currFrame.position; -// +// float3 lastToCurrFoward = currFrame.position - prevFrame.position; +// float3 lastToCurrRight = glm::normalize(glm::cross(lastToCurrFoward, prevFrame.up)); +// float3 lastToCurrUp = glm::normalize(glm::cross(lastToCurrRight, lastToCurrFoward)); +// +// float3 currToNextFoward = nextFrame.position - currFrame.position; +// // // If curr and next are the same, use the direction from prev to curr // if (glm::length(currToNextFoward) < 0.001f) // { // currToNextFoward = lastToCurrFoward; // } -// -// glm::vec3 currToNextRight = glm::normalize(glm::cross(currToNextFoward, currFrame.up)); -// glm::vec3 currToNextUp = glm::normalize(glm::cross(currToNextRight, currToNextFoward)); -// +// +// float3 currToNextRight = glm::normalize(glm::cross(currToNextFoward, currFrame.up)); +// float3 currToNextUp = glm::normalize(glm::cross(currToNextRight, currToNextFoward)); +// // // Half vector between two direction normals -// glm::vec3 midUp = (lastToCurrUp + currToNextUp) / 2.0f; -// glm::vec3 midRight = (lastToCurrRight + currToNextRight) / 2.0f; -// +// float3 midUp = (lastToCurrUp + currToNextUp) / 2.0f; +// float3 midRight = (lastToCurrRight + currToNextRight) / 2.0f; +// // return buildQuad(currFrame.position, midUp, midRight); // } @@ -133,49 +133,49 @@ namespace Falcor // { // return; // } -// +// // const float step = 1.0f / (float)kPathDetail; // const float epsilon = 1.0e-6f; // A bit more than glm::epsilon -// +// // ObjectPath::Frame prevFrame; // pPath->getFrameAt(0, 0.0f, prevFrame); -// +// // ObjectPath::Frame currFrame; // pPath->getFrameAt(0, step, currFrame); -// +// // Quad lastQuad = createQuadForFrame(prevFrame, currFrame); // Quad currQuad; -// +// // // Draw quad to cap path beginning // addQuad(lastQuad); -// +// // const float maxFrameIndex = (float)(pPath->getKeyFrameCount() - 1); -// +// // // Add epsilon so loop's <= works properly // const float pathEnd = maxFrameIndex + epsilon; -// +// // for (float frame = step; frame <= pathEnd; frame += step) // { // // Loop can overshoot the max index // // Clamp frame to right below max index so interpolation on the path will work // frame = std::min(frame, maxFrameIndex - epsilon); -// +// // uint32_t frameID = (uint32_t)(glm::floor(frame)); // float t = frame - (float)frameID; -// +// // ObjectPath::Frame nextFrame; // pPath->getFrameAt(frameID, t + step, nextFrame); // currQuad = createQuadForFrame(prevFrame, currFrame, nextFrame); -// +// // // Draw current quad // addQuad(currQuad); -// +// // // Connect last quad to current // addLine(lastQuad[0], currQuad[0]); // addLine(lastQuad[1], currQuad[1]); // addLine(lastQuad[2], currQuad[2]); // addLine(lastQuad[3], currQuad[3]); -// +// // prevFrame = currFrame; // lastQuad = currQuad; // currFrame = nextFrame; @@ -208,7 +208,7 @@ namespace Falcor VertexBufferLayout::SharedPtr pBufferLayout = VertexBufferLayout::create(); pBufferLayout->addElement("POSITION", 0, ResourceFormat::RGB32Float, 1, 0); - pBufferLayout->addElement("COLOR", sizeof(glm::vec3), ResourceFormat::RGB32Float, 1, 1); + pBufferLayout->addElement("COLOR", sizeof(float3), ResourceFormat::RGB32Float, 1, 1); VertexLayout::SharedPtr pVertexLayout = VertexLayout::create(); pVertexLayout->addBufferLayout(0, pBufferLayout); diff --git a/Source/Falcor/Utils/UI/DebugDrawer.h b/Source/Falcor/Utils/UI/DebugDrawer.h index 267bb9d69..92bc48d71 100644 --- a/Source/Falcor/Utils/UI/DebugDrawer.h +++ b/Source/Falcor/Utils/UI/DebugDrawer.h @@ -48,7 +48,7 @@ namespace Falcor static const uint32_t kMaxVertices = 10000; ///< Default max number of vertices per DebugDrawer instance static const uint32_t kPathDetail = 10; ///< Segments between keyframes - using Quad = std::array; + using Quad = std::array; /** Create a new object for drawing debug geometry. \param[in] maxVertices Maximum number of vertices that will be drawn. @@ -58,11 +58,11 @@ namespace Falcor /** Sets the color for following geometry */ - void setColor(const glm::vec3& color) { mCurrentColor = color; } + void setColor(const float3& color) { mCurrentColor = color; } /** Adds a line segment */ - void addLine(const glm::vec3& a, const glm::vec3& b); + void addLine(const float3& a, const float3& b); /** Adds a quad described by four corner points */ @@ -94,12 +94,12 @@ namespace Falcor DebugDrawer(uint32_t maxVertices); - glm::vec3 mCurrentColor; + float3 mCurrentColor; struct LineVertex { - glm::vec3 position; - glm::vec3 color; + float3 position; + float3 color; }; Vao::SharedPtr mpVao; diff --git a/Source/Falcor/Utils/UI/Font.cpp b/Source/Falcor/Utils/UI/Font.cpp index 4ba6a2102..54c7baf6a 100644 --- a/Source/Falcor/Utils/UI/Font.cpp +++ b/Source/Falcor/Utils/UI/Font.cpp @@ -124,7 +124,7 @@ namespace Falcor mCharDesc[i].topLeft.y = CharData.TopLeftY; mCharDesc[i].size.x = CharData.Width; mCharDesc[i].size.y = CharData.Height; - mLetterSpacing = max(mLetterSpacing, CharData.Width); + mLetterSpacing = std::max(mLetterSpacing, CharData.Width); } // Load the texture diff --git a/Source/Falcor/Utils/UI/Font.h b/Source/Falcor/Utils/UI/Font.h index 7d5c32330..3165f5b7a 100644 --- a/Source/Falcor/Utils/UI/Font.h +++ b/Source/Falcor/Utils/UI/Font.h @@ -50,8 +50,8 @@ namespace Falcor */ struct CharTexCrdDesc { - glm::vec2 topLeft; ///< Non-normalized origin of the character in the texture - glm::vec2 size; ///< Size in pixels of the character. This should be used to initialize the texture-coordinate when rendering. + float2 topLeft; ///< Non-normalized origin of the character in the texture + float2 size; ///< Size in pixels of the character. This should be used to initialize the texture-coordinate when rendering. }; /** Get the texture containing the characters diff --git a/Source/Falcor/Utils/UI/Gui.cpp b/Source/Falcor/Utils/UI/Gui.cpp index a1b6bf46d..cfc224bb9 100644 --- a/Source/Falcor/Utils/UI/Gui.cpp +++ b/Source/Falcor/Utils/UI/Gui.cpp @@ -90,7 +90,7 @@ namespace Falcor bool addMenuItem(const char label[], bool& var, const char shortcut[] = nullptr); bool addMenuItem(const char label[], const char shortcut[] = nullptr); - bool pushWindow(const char label[], bool& open, uvec2 size = { 250, 200 }, uvec2 pos = { 20, 40 }, Gui::WindowFlags flags = Gui::WindowFlags::Default); + bool pushWindow(const char label[], bool& open, uint2 size = { 250, 200 }, uint2 pos = { 20, 40 }, Gui::WindowFlags flags = Gui::WindowFlags::Default); void popWindow(); void setCurrentWindowPos(uint32_t x, uint32_t y); void setCurrentWindowSize(uint32_t width, uint32_t height); @@ -103,31 +103,31 @@ namespace Falcor void indent(float i); void addSeparator(uint32_t count = 1); - void addDummyItem(const char label[], const glm::vec2& size, bool sameLine = false); - void addRect(const glm::vec2& size, const glm::vec4& color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), bool filled = false, bool sameLine = false); + void addDummyItem(const char label[], const float2& size, bool sameLine = false); + void addRect(const float2& size, const float4& color = float4(1.0f, 1.0f, 1.0f, 1.0f), bool filled = false, bool sameLine = false); bool addDropdown(const char label[], const Gui::DropdownList& values, uint32_t& var, bool sameLine = false); bool addButton(const char label[], bool sameLine = false); bool addRadioButtons(const Gui::RadioButtonGroup& buttons, uint32_t& activeID); - bool addDirectionWidget(const char label[], glm::vec3& direction); + bool addDirectionWidget(const char label[], float3& direction); bool addCheckbox(const char label[], bool& var, bool sameLine = false); bool addCheckbox(const char label[], int& var, bool sameLine = false); template bool addBoolVecVar(const char label[], T& var, bool sameLine = false); bool addDragDropSource(const char label[], const char dataLabel[], const std::string& payloadString); bool addDragDropDest(const char dataLabel[], std::string& payloadString); - + void addText(const char text[], bool sameLine = false); bool addTextbox(const char label[], std::string& text, uint32_t lineCount = 1, Gui::TextFlags flags = Gui::TextFlags::Empty); bool addTextbox(const char label[], char buf[], size_t bufSize, uint32_t lineCount = 1, Gui::TextFlags flags = Gui::TextFlags::Empty); bool addMultiTextbox(const char label[], const std::vector& textLabels, std::vector& textEntries); void addTooltip(const char tip[], bool sameLine = true); - bool addRgbColor(const char label[], glm::vec3& var, bool sameLine = false); - bool addRgbaColor(const char label[], glm::vec4& var, bool sameLine = false); + bool addRgbColor(const char label[], float3& var, bool sameLine = false); + bool addRgbaColor(const char label[], float4& var, bool sameLine = false); + + void addImage(const char label[], const Texture::SharedPtr& pTex, float2 size = float2(0), bool maintainRatio = true, bool sameLine = false); + bool addImageButton(const char label[], const Texture::SharedPtr& pTex, float2 size, bool maintainRatio = true, bool sameLine = false); - void addImage(const char label[], const Texture::SharedPtr& pTex, glm::vec2 size = vec2(0), bool maintainRatio = true, bool sameLine = false); - bool addImageButton(const char label[], const Texture::SharedPtr& pTex, glm::vec2 size, bool maintainRatio = true, bool sameLine = false); - template bool addScalarVar(const char label[], T& var, T minVal = std::numeric_limits::lowest(), T maxVal = std::numeric_limits::max(), float step = 1.0f, bool sameLine = false, const char* displayFormat = nullptr); template @@ -330,7 +330,7 @@ namespace Falcor return ImGui::MenuItem(label, shortcut, &var); } - bool GuiImpl::pushWindow(const char label[], bool& open, uvec2 size, uvec2 pos, Gui::WindowFlags flags) + bool GuiImpl::pushWindow(const char label[], bool& open, uint2 size, uint2 pos, Gui::WindowFlags flags) { bool allowClose = is_set(flags, Gui::WindowFlags::CloseButton); if (allowClose) @@ -342,7 +342,7 @@ namespace Falcor } } - vec2 posFloat(pos); + float2 posFloat(pos); posFloat *= mScaleFactor; ImVec2 fPos(posFloat.x, posFloat.y); ImVec2 fSize(float(size.x), float(size.y)); @@ -425,7 +425,7 @@ namespace Falcor for (uint32_t i = 0; i < count; i++) ImGui::Separator(); } - void GuiImpl::addDummyItem(const char label[], const glm::vec2& size, bool sameLine) + void GuiImpl::addDummyItem(const char label[], const float2& size, bool sameLine) { if (sameLine) ImGui::SameLine(); ImGui::PushID(label); @@ -433,7 +433,7 @@ namespace Falcor ImGui::PopID(); } - void GuiImpl::addRect(const glm::vec2& size, const glm::vec4& color, bool filled, bool sameLine) + void GuiImpl::addRect(const float2& size, const float4& color, bool filled, bool sameLine) { if (sameLine) ImGui::SameLine(); @@ -510,9 +510,9 @@ namespace Falcor return oldValue != activeID; } - bool GuiImpl::addDirectionWidget(const char label[], glm::vec3& direction) + bool GuiImpl::addDirectionWidget(const char label[], float3& direction) { - glm::vec3 dir = direction; + float3 dir = direction; bool b = addVecVar(label, dir, -1.f, 1.f, 0.001f, false, "%.3f"); direction = glm::normalize(dir); return b; @@ -632,22 +632,22 @@ namespace Falcor } } - bool GuiImpl::addRgbColor(const char label[], glm::vec3& var, bool sameLine) + bool GuiImpl::addRgbColor(const char label[], float3& var, bool sameLine) { if (sameLine) ImGui::SameLine(); return ImGui::ColorEdit3(label, glm::value_ptr(var)); } - bool GuiImpl::addRgbaColor(const char label[], glm::vec4& var, bool sameLine) + bool GuiImpl::addRgbaColor(const char label[], float4& var, bool sameLine) { if (sameLine) ImGui::SameLine(); return ImGui::ColorEdit4(label, glm::value_ptr(var)); } - void GuiImpl::addImage(const char label[], const Texture::SharedPtr& pTex, glm::vec2 size, bool maintainRatio, bool sameLine) + void GuiImpl::addImage(const char label[], const Texture::SharedPtr& pTex, float2 size, bool maintainRatio, bool sameLine) { assert(pTex); - if (size == vec2(0)) + if (size == float2(0)) { ImVec2 windowSize = ImGui::GetWindowSize(); size = { windowSize.x, windowSize.y }; @@ -661,7 +661,7 @@ namespace Falcor ImGui::PopID(); } - bool GuiImpl::addImageButton(const char label[], const Texture::SharedPtr& pTex, glm::vec2 size, bool maintainRatio, bool sameLine) + bool GuiImpl::addImageButton(const char label[], const Texture::SharedPtr& pTex, float2 size, bool maintainRatio, bool sameLine) { assert(pTex); mpImages.push_back(pTex); @@ -879,7 +879,7 @@ namespace Falcor return pGui; } - glm::vec4 Gui::pickUniqueColor(const std::string& key) + float4 Gui::pickUniqueColor(const std::string& key) { union hashedValue { @@ -889,7 +889,7 @@ namespace Falcor hashedValue color; color.st = std::hash()(key); - return glm::vec4(color.i32[0] % 1000 / 2000.0f, color.i32[1] % 1000 / 2000.0f, (color.i32[0] * color.i32[1]) % 1000 / 2000.0f, 1.0f); + return float4(color.i32[0] % 1000 / 2000.0f, color.i32[1] % 1000 / 2000.0f, (color.i32[0] * color.i32[1]) % 1000 / 2000.0f, 1.0f); } void Gui::addFont(const std::string& name, const std::string& filename) @@ -1019,11 +1019,11 @@ namespace Falcor io.DisplaySize.x = (float)width; io.DisplaySize.y = (float)height; #ifdef FALCOR_VK - mpWrapper->mpProgramVars["PerFrameCB"]["scale"] = 2.0f / vec2(io.DisplaySize.x, io.DisplaySize.y); - mpWrapper->mpProgramVars["PerFrameCB"]["offset"] = vec2(-1.0f); + mpWrapper->mpProgramVars["PerFrameCB"]["scale"] = 2.0f / float2(io.DisplaySize.x, io.DisplaySize.y); + mpWrapper->mpProgramVars["PerFrameCB"]["offset"] = float2(-1.0f); #else - mpWrapper->mpProgramVars["PerFrameCB"]["scale"] = 2.0f / vec2(io.DisplaySize.x, -io.DisplaySize.y); - mpWrapper->mpProgramVars["PerFrameCB"]["offset"] = vec2(-1.0f, 1.0f); + mpWrapper->mpProgramVars["PerFrameCB"]["scale"] = 2.0f / float2(io.DisplaySize.x, -io.DisplaySize.y); + mpWrapper->mpProgramVars["PerFrameCB"]["offset"] = float2(-1.0f, 1.0f); #endif } @@ -1108,12 +1108,12 @@ namespace Falcor if (mpGui) mpGui->mpWrapper->addSeparator(count); } - void Gui::Widgets::dummy(const char label[], const glm::vec2& size, bool sameLine) + void Gui::Widgets::dummy(const char label[], const float2& size, bool sameLine) { if (mpGui) mpGui->mpWrapper->addDummyItem(label, size, sameLine); } - void Gui::Widgets::rect(const glm::vec2& size, const glm::vec4& color, bool filled, bool sameLine) + void Gui::Widgets::rect(const float2& size, const float4& color, bool filled, bool sameLine) { if (mpGui) mpGui->mpWrapper->addRect(size, color, filled, sameLine); } @@ -1133,7 +1133,7 @@ namespace Falcor return mpGui ? mpGui->mpWrapper->addRadioButtons(buttons, activeID) : false; } - bool Gui::Widgets::direction(const char label[], glm::vec3& direction) + bool Gui::Widgets::direction(const char label[], float3& direction) { return mpGui ? mpGui->mpWrapper->addDirectionWidget(label, direction) : false; } @@ -1158,9 +1158,9 @@ namespace Falcor #define add_bool_vec_type(TypeName) template dlldecl bool Gui::Widgets::checkbox(const char[], TypeName&, bool) - add_bool_vec_type(glm::bvec2); - add_bool_vec_type(glm::bvec3); - add_bool_vec_type(glm::bvec4); + add_bool_vec_type(bool2); + add_bool_vec_type(bool3); + add_bool_vec_type(bool4); #undef add_bool_vec_type @@ -1214,15 +1214,15 @@ namespace Falcor #define add_vecVar_type(TypeName) template dlldecl bool Gui::Widgets::var(const char[], TypeName&, typename TypeName::value_type, typename TypeName::value_type, float, bool, const char*) - add_vecVar_type(ivec2); - add_vecVar_type(ivec3); - add_vecVar_type(ivec4); - add_vecVar_type(uvec2); - add_vecVar_type(uvec3); - add_vecVar_type(uvec4); - add_vecVar_type(vec2); - add_vecVar_type(vec3); - add_vecVar_type(vec4); + add_vecVar_type(int2); + add_vecVar_type(int3); + add_vecVar_type(int4); + add_vecVar_type(uint2); + add_vecVar_type(uint3); + add_vecVar_type(uint4); + add_vecVar_type(float2); + add_vecVar_type(float3); + add_vecVar_type(float4); #undef add_vecVar_type @@ -1236,15 +1236,15 @@ namespace Falcor #define add_vecSlider_type(TypeName) template dlldecl bool Gui::Widgets::slider(const char[], TypeName&, typename TypeName::value_type, typename TypeName::value_type, bool, const char*) - add_vecSlider_type(ivec2); - add_vecSlider_type(ivec3); - add_vecSlider_type(ivec4); - add_vecSlider_type(uvec2); - add_vecSlider_type(uvec3); - add_vecSlider_type(uvec4); - add_vecSlider_type(vec2); - add_vecSlider_type(vec3); - add_vecSlider_type(vec4); + add_vecSlider_type(int2); + add_vecSlider_type(int3); + add_vecSlider_type(int4); + add_vecSlider_type(uint2); + add_vecSlider_type(uint3); + add_vecSlider_type(uint4); + add_vecSlider_type(float2); + add_vecSlider_type(float3); + add_vecSlider_type(float4); #undef add_vecSlider_type @@ -1273,22 +1273,22 @@ namespace Falcor if (mpGui) mpGui->mpWrapper->addTooltip(text.c_str(), sameLine); } - bool Gui::Widgets::rgbColor(const char label[], glm::vec3& var, bool sameLine) + bool Gui::Widgets::rgbColor(const char label[], float3& var, bool sameLine) { return mpGui ? mpGui->mpWrapper->addRgbColor(label, var, sameLine) : false; } - bool Gui::Widgets::rgbaColor(const char label[], glm::vec4& var, bool sameLine) + bool Gui::Widgets::rgbaColor(const char label[], float4& var, bool sameLine) { return mpGui ? mpGui->mpWrapper->addRgbaColor(label, var, sameLine) : false; } - bool Gui::Widgets::imageButton(const char label[], const Texture::SharedPtr& pTex, glm::vec2 size, bool maintainRatio, bool sameLine) + bool Gui::Widgets::imageButton(const char label[], const Texture::SharedPtr& pTex, float2 size, bool maintainRatio, bool sameLine) { return mpGui ? mpGui->mpWrapper->addImageButton(label, pTex, size, maintainRatio, sameLine) : false; } - void Gui::Widgets::image(const char label[], const Texture::SharedPtr& pTex, glm::vec2 size, bool maintainRatio, bool sameLine) + void Gui::Widgets::image(const char label[], const Texture::SharedPtr& pTex, float2 size, bool maintainRatio, bool sameLine) { if (mpGui) mpGui->mpWrapper->addImage(label, pTex, size, maintainRatio, sameLine); } @@ -1397,14 +1397,14 @@ namespace Falcor { if (mpGui) mpGui->mpWrapper->endGroup(); mpGui = nullptr; } - - Gui::Window::Window(Gui* pGui, const char* name, uvec2 size, uvec2 pos, Gui::WindowFlags flags) + + Gui::Window::Window(Gui* pGui, const char* name, uint2 size, uint2 pos, Gui::WindowFlags flags) { bool open = true; if (pGui->mpWrapper->pushWindow(name, open, size, pos, flags)) mpGui = pGui; } - Gui::Window::Window(Gui* pGui, const char* name, bool& open, uvec2 size, uvec2 pos, Gui::WindowFlags flags) + Gui::Window::Window(Gui* pGui, const char* name, bool& open, uint2 size, uint2 pos, Gui::WindowFlags flags) { if (pGui->mpWrapper->pushWindow(name, open, size, pos, flags)) mpGui = pGui; } diff --git a/Source/Falcor/Utils/UI/Gui.h b/Source/Falcor/Utils/UI/Gui.h index 4d123f5e8..5abb7cc37 100644 --- a/Source/Falcor/Utils/UI/Gui.h +++ b/Source/Falcor/Utils/UI/Gui.h @@ -118,15 +118,15 @@ namespace Falcor \param[in] size. size in pixels of the item. \param[in] sameLine Optional. If set to true, the widget will appear on the same line as the previous widget */ - void dummy(const char label[], const glm::vec2& size, bool sameLine = false); + void dummy(const char label[], const float2& size, bool sameLine = false); /** Display rectangle with specified color \param[in] size size in pixels of rectangle - \param[in] color Optional. color as an rgba vec4 + \param[in] color Optional. color as an rgba float4 \param[in] filled Optional. If set to true, rectangle will be filled \param[in] sameLine Optional. If set to true, the widget will appear on the same line as the previous widget */ - void rect(const glm::vec2& size, const glm::vec4& color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), bool filled = false, bool sameLine = false); + void rect(const float2& size, const float4& color = float4(1.0f, 1.0f, 1.0f, 1.0f), bool filled = false, bool sameLine = false); /** Adds a dropdown menu. This will update a user variable directly, so the user has to keep track of that for changes. If you want notifications whenever the select option changed, use Gui#addDropdownWithCallback(). @@ -156,7 +156,7 @@ namespace Falcor \param[in] direction A reference for the direction variable \return true if the value changed, otherwise false */ - bool direction(const char label[], glm::vec3& direction); + bool direction(const char label[], float3& direction); /** Adds a UI widget for multiple checkboxes. \param[in] label The name of the widget. @@ -223,7 +223,7 @@ namespace Falcor \param[in] sameLine Optional. If set to true, the widget will appear on the same line as the previous widget \return true if the value changed, otherwise false */ - bool rgbColor(const char label[], glm::vec3& var, bool sameLine = false); + bool rgbColor(const char label[], float3& var, bool sameLine = false); /** Adds an RGBA color UI widget. \param[in] label The name of the widget. @@ -231,7 +231,7 @@ namespace Falcor \param[in] sameLine Optional. If set to true, the widget will appear on the same line as the previous widget \return true if the value changed, otherwise false */ - bool rgbaColor(const char label[], glm::vec4& var, bool sameLine = false); + bool rgbaColor(const char label[], float4& var, bool sameLine = false); // Images /** Display image within imgui @@ -240,8 +240,8 @@ namespace Falcor \param[in] size. Size in pixels of the image to draw. 0 means fit to window \param[in] sameLine Optional. If set to true, the widget will appear on the same line as the previous widget */ - void image(const char label[], const Texture::SharedPtr& pTex, glm::vec2 size = vec2(0), bool maintainRatio = true, bool sameLine = false); - bool imageButton(const char label[], const Texture::SharedPtr& pTex, glm::vec2 size, bool maintainRatio = true, bool sameLine = false); + void image(const char label[], const Texture::SharedPtr& pTex, float2 size = float2(0), bool maintainRatio = true, bool sameLine = false); + bool imageButton(const char label[], const Texture::SharedPtr& pTex, float2 size, bool maintainRatio = true, bool sameLine = false); // Scalars /** Adds a UI element for setting scalar values. @@ -424,8 +424,8 @@ namespace Falcor \param[in] pos position in pixels of the window \param[in] flags Window flags to apply */ - Window(Gui* pGui, const char* name, uvec2 size = { 0, 0 }, uvec2 pos = { 0, 0 }, Gui::WindowFlags flags = Gui::WindowFlags::Default); - Window(Gui* pGui, const char* name, bool& open, uvec2 size = { 0, 0 }, uvec2 pos = { 0, 0 }, Gui::WindowFlags flags = Gui::WindowFlags::Default); + Window(Gui* pGui, const char* name, uint2 size = { 0, 0 }, uint2 pos = { 0, 0 }, Gui::WindowFlags flags = Gui::WindowFlags::Default); + Window(Gui* pGui, const char* name, bool& open, uint2 size = { 0, 0 }, uint2 pos = { 0, 0 }, Gui::WindowFlags flags = Gui::WindowFlags::Default); /** Create a new window \param[in] w a reference to a Widgets object @@ -433,8 +433,8 @@ namespace Falcor \param[in] pos position in pixels of the window \param[in] flags Window flags to apply */ - Window(const Widgets& w, const char* name, uvec2 size = { 0, 0 }, uvec2 pos = { 0, 0 }, Gui::WindowFlags flags = Gui::WindowFlags::Default) : Window(w.gui(), name, size, pos, flags) {} - Window(const Widgets& w, const char* name, bool& open, uvec2 size = { 0, 0 }, uvec2 pos = { 0, 0 }, Gui::WindowFlags flags = Gui::WindowFlags::Default) : Window(w.gui(), name, open, size, pos, flags) {} + Window(const Widgets& w, const char* name, uint2 size = { 0, 0 }, uint2 pos = { 0, 0 }, Gui::WindowFlags flags = Gui::WindowFlags::Default) : Window(w.gui(), name, size, pos, flags) {} + Window(const Widgets& w, const char* name, bool& open, uint2 size = { 0, 0 }, uint2 pos = { 0, 0 }, Gui::WindowFlags flags = Gui::WindowFlags::Default) : Window(w.gui(), name, open, size, pos, flags) {} ~Window(); @@ -491,7 +491,7 @@ namespace Falcor ~Gui(); - static glm::vec4 pickUniqueColor(const std::string& key); + static float4 pickUniqueColor(const std::string& key); /** Add a font */ diff --git a/Source/Falcor/Utils/UI/PixelZoom.cpp b/Source/Falcor/Utils/UI/PixelZoom.cpp index 4bc45b79e..7e05dcea7 100644 --- a/Source/Falcor/Utils/UI/PixelZoom.cpp +++ b/Source/Falcor/Utils/UI/PixelZoom.cpp @@ -32,10 +32,10 @@ namespace Falcor { - static void clampToEdge(vec2& pix, uint32_t width, uint32_t height, uint32_t offset) + static void clampToEdge(float2& pix, uint32_t width, uint32_t height, uint32_t offset) { - vec2 posOffset = pix + vec2(offset, offset); - vec2 negOffset = pix - vec2(offset, offset); + float2 posOffset = pix + float2(offset, offset); + float2 negOffset = pix - float2(offset, offset); //x if (posOffset.x > width) @@ -88,17 +88,17 @@ namespace Falcor //blit src blit fbo into dst blit fbo uint32_t offset = mSrcZoomSize / 2; - vec2 srcPix = vec2(mMousePos.x * backBuffer->getWidth(), mMousePos.y * backBuffer->getHeight()); + float2 srcPix = float2(mMousePos.x * backBuffer->getWidth(), mMousePos.y * backBuffer->getHeight()); clampToEdge(srcPix, backBuffer->getWidth(), backBuffer->getHeight(), offset); - vec4 srcRect = vec4(srcPix.x - offset, srcPix.y - offset, srcPix.x + offset, srcPix.y + offset); - vec4 dstRect = vec4(0, 0, mDstZoomSize, mDstZoomSize); + float4 srcRect = float4(srcPix.x - offset, srcPix.y - offset, srcPix.x + offset, srcPix.y + offset); + float4 dstRect = float4(0, 0, mDstZoomSize, mDstZoomSize); pCtx->blit(mpSrcBlitFbo->getColorTexture(0)->getSRV(), mpDstBlitFbo->getColorTexture(0)->getRTV(), srcRect, dstRect, Sampler::Filter::Point); //blit dst blt fbo into back buffer offset = mDstZoomSize / 2; clampToEdge(srcPix, backBuffer->getWidth(), backBuffer->getHeight(), offset); srcRect = dstRect; - dstRect = vec4(srcPix.x - offset, srcPix.y - offset, srcPix.x + offset, srcPix.y + offset); + dstRect = float4(srcPix.x - offset, srcPix.y - offset, srcPix.x + offset, srcPix.y + offset); pCtx->blit(mpDstBlitFbo->getColorTexture(0)->getSRV(), backBuffer->getColorTexture(0)->getRTV(), srcRect, dstRect, Sampler::Filter::Point); } } @@ -110,7 +110,7 @@ namespace Falcor mMousePos = me.pos; //negative to swap scroll up to zoom in and scroll down to zoom out int32_t zoomDelta = -1 * mZoomCoefficient * (int32_t)me.wheelDelta.y; - mSrcZoomSize = max(mSrcZoomSize + zoomDelta, 3); + mSrcZoomSize = std::max(mSrcZoomSize + zoomDelta, 3); return me.type != MouseEvent::Type::Move; // Do not inhibit other passes from receiving mouse movement events. } return false; diff --git a/Source/Falcor/Utils/UI/PixelZoom.h b/Source/Falcor/Utils/UI/PixelZoom.h index 83da3715f..07a3b443e 100644 --- a/Source/Falcor/Utils/UI/PixelZoom.h +++ b/Source/Falcor/Utils/UI/PixelZoom.h @@ -76,7 +76,7 @@ namespace Falcor Fbo::SharedPtr mpSrcBlitFbo; Fbo::SharedPtr mpDstBlitFbo; - glm::vec2 mMousePos = {}; + float2 mMousePos = {}; bool mShouldZoom = false; }; } diff --git a/Source/Falcor/Utils/UI/TextRenderer.cpp b/Source/Falcor/Utils/UI/TextRenderer.cpp index 1bf46883d..657b5eeba 100644 --- a/Source/Falcor/Utils/UI/TextRenderer.cpp +++ b/Source/Falcor/Utils/UI/TextRenderer.cpp @@ -35,19 +35,19 @@ namespace Falcor { struct Vertex { - glm::vec2 screenPos; - glm::vec2 texCoord; + float2 screenPos; + float2 texCoord; }; - const glm::vec2 kVertexPos[] = + const float2 kVertexPos[] = { - glm::vec2(0, 0), - glm::vec2(0, 1), - glm::vec2(1, 0), + float2(0, 0), + float2(0, 1), + float2(1, 0), - glm::vec2(1, 0), - glm::vec2(0, 1), - glm::vec2(1, 1), + float2(1, 0), + float2(0, 1), + float2(1, 1), }; const uint32_t kMaxCharCount = 1000; @@ -68,7 +68,7 @@ namespace Falcor { bool init = false; TextRenderer::Flags flags = TextRenderer::Flags::Shadowed; - vec3 color = vec3(1, 1, 1); + float3 color = float3(1, 1, 1); Buffer::SharedPtr pVb; RasterPass::SharedPtr pPass; Font::UniquePtr pFont; @@ -95,7 +95,7 @@ namespace Falcor gTextData.pPass["PerFrameCB"]["gFontColor"] = gTextData.color; } - void renderText(RenderContext* pRenderContext, const std::string& text, const Fbo::SharedPtr& pDstFbo, vec2 pos) + void renderText(RenderContext* pRenderContext, const std::string& text, const Fbo::SharedPtr& pDstFbo, float2 pos) { // Make sure we enough space for the next char assert(text.size() < kMaxCharCount); @@ -121,8 +121,8 @@ namespace Falcor const Font::CharTexCrdDesc& desc = gTextData.pFont->getCharDesc(c); for (uint32_t i = 0; i < arraysize(kVertexPos); i++, vertexCount++) { - vec2 posScale = kVertexPos[i]; - vec2 charPos = desc.size * posScale; + float2 posScale = kVertexPos[i]; + float2 charPos = desc.size * posScale; charPos += pos; verts[vertexCount].screenPos = charPos; verts[vertexCount].texCoord = desc.topLeft + desc.size * kVertexPos[i]; @@ -138,8 +138,8 @@ namespace Falcor } } - const vec3& TextRenderer::getColor() { return gTextData.color; } - void TextRenderer::setColor(const glm::vec3& color) { gTextData.color = color; } + const float3& TextRenderer::getColor() { return gTextData.color; } + void TextRenderer::setColor(const float3& color) { gTextData.color = color; } TextRenderer::Flags TextRenderer::getFlags() { return gTextData.flags; } void TextRenderer::setFlags(Flags f) { gTextData.flags = f; } @@ -162,7 +162,7 @@ namespace Falcor DepthStencilState::Desc dsDesc; dsDesc.setDepthEnabled(false); pState->setDepthStencilState(DepthStencilState::create(dsDesc)); - + // Rasterizer state RasterizerState::Desc rsState; rsState.setCullMode(RasterizerState::CullMode::None); @@ -190,13 +190,13 @@ namespace Falcor gTextData = {}; } - void TextRenderer::render(RenderContext* pRenderContext, const std::string& text, const Fbo::SharedPtr& pDstFbo, vec2 pos) + void TextRenderer::render(RenderContext* pRenderContext, const std::string& text, const Fbo::SharedPtr& pDstFbo, float2 pos) { if (is_set(gTextData.flags, TextRenderer::Flags::Shadowed)) { - vec3 oldColor = getColor(); - setColor(vec3(0)); - renderText(pRenderContext, text, pDstFbo, pos + vec2(1)); + float3 oldColor = getColor(); + setColor(float3(0)); + renderText(pRenderContext, text, pDstFbo, pos + float2(1)); setColor(oldColor); } renderText(pRenderContext, text, pDstFbo, pos); diff --git a/Source/Falcor/Utils/UI/TextRenderer.h b/Source/Falcor/Utils/UI/TextRenderer.h index 629c8dd40..bb0fef160 100644 --- a/Source/Falcor/Utils/UI/TextRenderer.h +++ b/Source/Falcor/Utils/UI/TextRenderer.h @@ -58,17 +58,17 @@ namespace Falcor \param[in] pDstFbo The target FBO \param[in] pos Text position */ - static void render(RenderContext* pRenderContext, const std::string& text, const Fbo::SharedPtr& pDstFbo, vec2 pos); - + static void render(RenderContext* pRenderContext, const std::string& text, const Fbo::SharedPtr& pDstFbo, float2 pos); + /** Returns the color of the text being rendered \return current color The text color */ - static const glm::vec3& getColor(); + static const float3& getColor(); /** Set the color of the text being rendered \param[in] color The text color */ - static void setColor(const glm::vec3& color); + static void setColor(const float3& color); /** Get the active flags */ diff --git a/Source/Falcor/Utils/UI/UserInput.h b/Source/Falcor/Utils/UI/UserInput.h index 4013d659e..550e73e1d 100644 --- a/Source/Falcor/Utils/UI/UserInput.h +++ b/Source/Falcor/Utils/UI/UserInput.h @@ -28,7 +28,7 @@ #pragma once namespace Falcor -{ +{ /** Input modifiers used with some events */ struct InputModifiers @@ -57,9 +57,9 @@ namespace Falcor }; Type type; ///< Event Type. - glm::vec2 pos; ///< Normalized coordinates x,y in range [0, 1]. (0,0) is the top-left corner of the window. - glm::vec2 screenPos; ///< Screen-space coordinates in range [0, clientSize]. (0,0) is the top-left corner of the window. - glm::vec2 wheelDelta; ///< If the current event is CMouseEvent#Type#Wheel, the change in wheel scroll. Otherwise zero. + float2 pos; ///< Normalized coordinates x,y in range [0, 1]. (0,0) is the top-left corner of the window. + float2 screenPos; ///< Screen-space coordinates in range [0, clientSize]. (0,0) is the top-left corner of the window. + float2 wheelDelta; ///< If the current event is CMouseEvent#Type#Wheel, the change in wheel scroll. Otherwise zero. InputModifiers mods; ///< Keyboard modifiers. Only valid if the event Type is one the button events }; @@ -73,7 +73,7 @@ namespace Falcor KeyReleased, ///< Key was released. Input ///< Character input }; - + /** Use this enum to find out which key was pressed. Alpha-numeric keys use their uppercase ASCII code, so you can use that as well. */ enum class Key : uint32_t diff --git a/Source/Falcor/dependencies.xml b/Source/Falcor/dependencies.xml index 4301f9c1c..07ff63039 100644 --- a/Source/Falcor/dependencies.xml +++ b/Source/Falcor/dependencies.xml @@ -18,12 +18,15 @@ + + + - - + + diff --git a/Source/Mogwai/AppData.cpp b/Source/Mogwai/AppData.cpp new file mode 100644 index 000000000..ee4559030 --- /dev/null +++ b/Source/Mogwai/AppData.cpp @@ -0,0 +1,150 @@ +/*************************************************************************** + # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#include "stdafx.h" +#include "AppData.h" +#define RAPIDJSON_HAS_STDSTRING 1 +#include "rapidjson/document.h" +#include "rapidjson/istreamwrapper.h" +#include "rapidjson/ostreamwrapper.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/error/en.h" +#include + +using namespace Falcor; + +namespace Mogwai +{ + namespace + { + const char kRecentScripts[] = "recentScripts"; + const char kRecentScenes[] = "recentScenes"; + + size_t kMaxRecentFiles = 25; + } + + AppData::AppData(const std::filesystem::path& path) + : mPath(path.lexically_normal()) + { + // Make sure directories exist. + std::filesystem::create_directories(mPath.parent_path()); + + loadFromFile(mPath); + } + + void AppData::addRecentScript(const std::string& filename) + { + addRecentFile(mRecentScripts, filename); + } + + void AppData::addRecentScene(const std::string& filename) + { + addRecentFile(mRecentScenes, filename); + } + + void AppData::addRecentFile(std::vector& recentFiles, const std::string& filename) + { + if (!doesFileExist(filename)) return; + std::string path = canonicalizeFilename(filename); + recentFiles.erase(std::remove(recentFiles.begin(), recentFiles.end(), path), recentFiles.end()); + recentFiles.insert(recentFiles.begin(), path); + if (recentFiles.size() > kMaxRecentFiles) recentFiles.resize(kMaxRecentFiles); + save(); + } + + void AppData::removeNonExistingFiles(std::vector& files) + { + files.erase(std::remove_if(files.begin(), files.end(), [](const std::string& filename) { + return !doesFileExist(filename); + }), files.end()); + } + + void AppData::save() + { + saveToFile(mPath); + } + + void AppData::loadFromFile(const std::filesystem::path& path) + { + rapidjson::Document document; + + std::ifstream ifs(path); + if (!ifs.good()) return; + + rapidjson::IStreamWrapper isw(ifs); + document.ParseStream(isw); + + if (document.HasParseError()) + { + logWarning("Failed to parse Mogwai settings file " + path.string() + ": " + rapidjson::GetParseError_En(document.GetParseError())); + return; + } + + auto readStringArray = [](const rapidjson::Value& value) + { + std::vector strings; + if (value.IsArray()) + { + for (const auto& item : value.GetArray()) + { + if (item.IsString()) strings.push_back(item.GetString()); + } + } + return strings; + }; + + mRecentScripts = readStringArray(document[kRecentScripts]); + mRecentScenes = readStringArray(document[kRecentScenes]); + + removeNonExistingFiles(mRecentScripts); + removeNonExistingFiles(mRecentScenes); + } + + void AppData::saveToFile(const std::filesystem::path& path) + { + rapidjson::Document document; + document.SetObject(); + auto& allocator = document.GetAllocator(); + + auto writeStringArray = [&allocator](const std::vector& strings) + { + rapidjson::Value value(rapidjson::kArrayType); + for (const auto& item : strings) value.PushBack(rapidjson::StringRef(item), allocator); + return value; + }; + + document.AddMember(kRecentScripts, writeStringArray(mRecentScripts), allocator); + document.AddMember(kRecentScenes, writeStringArray(mRecentScenes), allocator); + + std::ofstream ofs(path); + if (!ofs.good()) return; + + rapidjson::OStreamWrapper osw(ofs); + rapidjson::PrettyWriter writer(osw); + document.Accept(writer); + } +} diff --git a/Source/Mogwai/AppData.h b/Source/Mogwai/AppData.h new file mode 100644 index 000000000..18e712d3a --- /dev/null +++ b/Source/Mogwai/AppData.h @@ -0,0 +1,61 @@ +/*************************************************************************** + # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#pragma once +#include "Falcor.h" +#include + +namespace Mogwai +{ + /** Holds a set of persistent application data stored in the user directory. + */ + class AppData + { + public: + AppData(const std::filesystem::path& path); + + const std::vector& getRecentScripts() const { return mRecentScripts; } + const std::vector& getRecentScenes() const { return mRecentScenes; } + + void addRecentScript(const std::string& filename); + void addRecentScene(const std::string& filename); + + private: + void addRecentFile(std::vector& recentFiles, const std::string& filename); + void removeNonExistingFiles(std::vector& files); + + void save(); + + void loadFromFile(const std::filesystem::path& path); + void saveToFile(const std::filesystem::path& path); + + std::filesystem::path mPath; + + std::vector mRecentScripts; + std::vector mRecentScenes; + }; +} diff --git a/Source/Mogwai/Data/Config.py b/Source/Mogwai/Data/Config.py index 31ef54cbc..e36c37f85 100644 --- a/Source/Mogwai/Data/Config.py +++ b/Source/Mogwai/Data/Config.py @@ -6,27 +6,24 @@ # Window Configuration m.resizeSwapChain(1920, 1080) -m.ui(true) +m.ui = True # Global Settings -t.now(0) -t.framerate(60) -# If framerate() is not zero, you can use the following function to set the start frame -# t.frame(0) - -t.exitTime(600) +t.time = 0 +t.framerate = 60 +# If framerate is not zero, you can use the frame property to set the start frame +# t.frame = 0 # Frame Capture -fc.outputDir("../../../Source/Mogwai") -fc.baseFilename("Mogwai") -g = m.activeGraph(); -#fc.frames(g, [20, 50, 32]) +fc.outputDir = "../../../Source/Mogwai" +fc.baseFilename = "Mogwai" +#fc.addFrames(m.activeGraph, [20, 50, 32]) # Video Capture -vc.outputDir(".") -vc.baseFilename("Mogwai") -vc.codec(Codec.H264) -vc.fps(60) -vc.bitrate(4.000000) -vc.gopSize(10) -#vc.ranges(g, [[30, 300]]); +vc.outputDir = "." +vc.baseFilename = "Mogwai" +vc.codec = Codec.H264 +vc.fps = 60 +vc.bitrate = 4.0 +vc.gopSize = 10 +#vc.addRanges(m.activeGraph, [[30, 300]]) diff --git a/Source/Mogwai/Data/ForwardRenderer.py b/Source/Mogwai/Data/ForwardRenderer.py index efbdc702d..40fd13b1c 100644 --- a/Source/Mogwai/Data/ForwardRenderer.py +++ b/Source/Mogwai/Data/ForwardRenderer.py @@ -14,7 +14,7 @@ def render_graph_forward_renderer(): forward_renderer.addPass(RenderPass("ForwardLightingPass"), "LightingPass") forward_renderer.addPass(RenderPass("CSM"), "ShadowPass") forward_renderer.addPass(RenderPass("BlitPass"), "BlitPass") - forward_renderer.addPass(RenderPass("ToneMapper"), "ToneMapping") + forward_renderer.addPass(RenderPass("ToneMapper", {'autoExposure': True}), "ToneMapping") forward_renderer.addPass(RenderPass("SSAO"), "SSAO") forward_renderer.addPass(RenderPass("FXAA"), "FXAA") diff --git a/Source/Mogwai/Data/PathTracer.py b/Source/Mogwai/Data/PathTracer.py index e89d0c764..b8021104e 100644 --- a/Source/Mogwai/Data/PathTracer.py +++ b/Source/Mogwai/Data/PathTracer.py @@ -3,14 +3,14 @@ def render_graph_PathTracerGraph(): loadRenderPassLibrary("AccumulatePass.dll") loadRenderPassLibrary("GBuffer.dll") loadRenderPassLibrary("ToneMapper.dll") - loadRenderPassLibrary("WavefrontPathTracer.dll") + loadRenderPassLibrary("MegakernelPathTracer.dll") AccumulatePass = RenderPass("AccumulatePass", {'enableAccumulation': True}) g.addPass(AccumulatePass, "AccumulatePass") - ToneMappingPass = RenderPass("ToneMapper") + ToneMappingPass = RenderPass("ToneMapper", {'autoExposure': False, 'exposureValue': 0.0}) g.addPass(ToneMappingPass, "ToneMappingPass") GBufferRT = RenderPass("GBufferRT", {'forceCullMode': False, 'cull': CullMode.CullBack, 'samplePattern': SamplePattern.Stratified, 'sampleCount': 16}) g.addPass(GBufferRT, "GBufferRT") - MegakernelPathTracer = RenderPass("MegakernelPathTracer", {'mSharedParams': PathTracerParams(useVBuffer=0)}) + MegakernelPathTracer = RenderPass("MegakernelPathTracer", {'mSharedParams': PathTracerParams(useVBuffer=0, useAnalyticLights=0)}) g.addPass(MegakernelPathTracer, "MegakernelPathTracer") g.addEdge("GBufferRT.posW", "MegakernelPathTracer.posW") g.addEdge("GBufferRT.normW", "MegakernelPathTracer.normalW") diff --git a/Source/Mogwai/Data/VBufferPathTracer.py b/Source/Mogwai/Data/VBufferPathTracer.py index 5ee292738..301062f91 100644 --- a/Source/Mogwai/Data/VBufferPathTracer.py +++ b/Source/Mogwai/Data/VBufferPathTracer.py @@ -3,14 +3,14 @@ def render_graph_VBufferPathTracerGraph(): loadRenderPassLibrary("AccumulatePass.dll") loadRenderPassLibrary("GBuffer.dll") loadRenderPassLibrary("ToneMapper.dll") - loadRenderPassLibrary("WavefrontPathTracer.dll") + loadRenderPassLibrary("MegakernelPathTracer.dll") AccumulatePass = RenderPass("AccumulatePass", {'enableAccumulation': True}) g.addPass(AccumulatePass, "AccumulatePass") - ToneMappingPass = RenderPass("ToneMapper") + ToneMappingPass = RenderPass("ToneMapper", {'autoExposure': False, 'exposureValue': 0.0}) g.addPass(ToneMappingPass, "ToneMappingPass") VBufferRT = RenderPass("VBufferRT", {'samplePattern': SamplePattern.Stratified, 'sampleCount': 16}) g.addPass(VBufferRT, "VBufferRT") - MegakernelPathTracer = RenderPass("MegakernelPathTracer", {'mSharedParams': PathTracerParams(useVBuffer=1)}) + MegakernelPathTracer = RenderPass("MegakernelPathTracer", {'mSharedParams': PathTracerParams(useVBuffer=1, useAnalyticLights=0)}) g.addPass(MegakernelPathTracer, "MegakernelPathTracer") g.addEdge("VBufferRT.vbuffer", "MegakernelPathTracer.vbuffer") g.addEdge("MegakernelPathTracer.color", "AccumulatePass.input") diff --git a/Source/Mogwai/Extensions/Capture/CaptureTrigger.cpp b/Source/Mogwai/Extensions/Capture/CaptureTrigger.cpp index 9ef108287..f5d053591 100644 --- a/Source/Mogwai/Extensions/Capture/CaptureTrigger.cpp +++ b/Source/Mogwai/Extensions/Capture/CaptureTrigger.cpp @@ -96,7 +96,7 @@ namespace Mogwai { RenderGraph* pGraph = mpRenderer->getActiveGraph(); if (!pGraph) return; - uint64_t frameId = gpFramework->getGlobalClock().frame(); + uint64_t frameId = gpFramework->getGlobalClock().getFrame(); if (mGraphRanges.find(pGraph) == mGraphRanges.end()) return; const auto& ranges = mGraphRanges.at(pGraph); @@ -118,11 +118,11 @@ namespace Mogwai } } } - + void CaptureTrigger::endFrame(RenderContext* pRenderContext, const Fbo::SharedPtr& pTargetFbo) { if (!mCurrent.pGraph) return; - uint64_t frameId = gpFramework->getGlobalClock().frame(); + uint64_t frameId = gpFramework->getGlobalClock().getFrame(); const auto& ranges = mGraphRanges.at(mCurrent.pGraph); triggerFrame(pRenderContext, mCurrent.pGraph, frameId); @@ -163,6 +163,11 @@ namespace Mogwai else mOutputDir = outDir; } + void CaptureTrigger::setBaseFilename(const std::string& baseFilename) + { + mBaseFilename = baseFilename; + } + void CaptureTrigger::scriptBindings(Bindings& bindings) { auto& m = bindings.getModule(); @@ -170,25 +175,18 @@ namespace Mogwai auto ct = m.class_("CaptureTrigger"); // Members - ct.func_(kReset.c_str(), &CaptureTrigger::reset, "renderGraph"_a = nullptr); - - // Output dir - ct.func_(kOutputDir.c_str(), &CaptureTrigger::setOutputDirectory); - auto printOutDir = [](CaptureTrigger* pCT) {pybind11::print(pCT->mOutputDir); }; - ct.func_(kOutputDir.c_str(), printOutDir); - - // Base filename - auto setBase = [](CaptureTrigger* pCT, const std::string& name) { pCT->mBaseFilename = name; }; - ct.func_(kBaseFilename.c_str(), setBase); - auto printBase = [](CaptureTrigger* pCT) {pybind11::print(pCT->mBaseFilename); }; - ct.func_(kBaseFilename.c_str(), printBase); + ct.func_(kReset.c_str(), &CaptureTrigger::reset, "graph"_a = nullptr); + + // Properties + ct.property(kOutputDir.c_str(), &CaptureTrigger::getOutputDirectory, &CaptureTrigger::setOutputDirectory); + ct.property(kBaseFilename.c_str(), &CaptureTrigger::getBaseFilename, &CaptureTrigger::setBaseFilename); } std::string CaptureTrigger::getScript(const std::string& var) { std::string s; - s += Scripting::makeMemberFunc(var, kOutputDir, filenameString(mOutputDir, false)); - s += Scripting::makeMemberFunc(var, kBaseFilename, mBaseFilename); + s += Scripting::makeSetProperty(var, kOutputDir, Scripting::getFilenameString(mOutputDir, false)); + s += Scripting::makeSetProperty(var, kBaseFilename, mBaseFilename); return s; } diff --git a/Source/Mogwai/Extensions/Capture/CaptureTrigger.h b/Source/Mogwai/Extensions/Capture/CaptureTrigger.h index 5dc452421..880b155e5 100644 --- a/Source/Mogwai/Extensions/Capture/CaptureTrigger.h +++ b/Source/Mogwai/Extensions/Capture/CaptureTrigger.h @@ -51,7 +51,13 @@ namespace Mogwai void addRange(const RenderGraph* pGraph, uint64_t startFrame, uint64_t count); void reset(const RenderGraph* pGraph = nullptr); void renderUI(Gui::Window& w); + void setOutputDirectory(const std::string& outDir); + const std::string& getOutputDirectory() const { return mOutputDir; } + + void setBaseFilename(const std::string& baseFilename); + const std::string& getBaseFilename() const { return mBaseFilename; } + std::string getScript(const std::string& var); std::string getOutputNamePrefix(const std::string& output) const; @@ -63,7 +69,7 @@ namespace Mogwai bool mAbsolutePath = false; bool mShowUI = false; - struct + struct { RenderGraph* pGraph = nullptr; Range range; diff --git a/Source/Mogwai/Extensions/Capture/FrameCapture.cpp b/Source/Mogwai/Extensions/Capture/FrameCapture.cpp index 06e94daf6..91bfee555 100644 --- a/Source/Mogwai/Extensions/Capture/FrameCapture.cpp +++ b/Source/Mogwai/Extensions/Capture/FrameCapture.cpp @@ -33,9 +33,10 @@ namespace Mogwai { namespace { + const std::string kScriptVar = "fc"; const std::string kPrintFrames = "print"; const std::string kFrames = "frames"; - const std::string kScriptVar = "fc"; + const std::string kAddFrames = "addFrames"; const std::string kUI = "ui"; const std::string kOutputs = "outputs"; const std::string kCapture = "capture"; @@ -74,11 +75,13 @@ namespace Mogwai bindings.addGlobalObject(kScriptVar, this, "Frame Capture Helpers"); // Members - fc.func_(kFrames.c_str(), ScriptBindings::overload_cast(&FrameCapture::frames)); - fc.func_(kFrames.c_str(), ScriptBindings::overload_cast(&FrameCapture::frames)); + fc.func_(kFrames.c_str(), ScriptBindings::overload_cast(&FrameCapture::addFrames)); // PYTHONDEPRECATED + fc.func_(kFrames.c_str(), ScriptBindings::overload_cast(&FrameCapture::addFrames)); // PYTHONDEPRECATED + fc.func_(kAddFrames.c_str(), ScriptBindings::overload_cast(&FrameCapture::addFrames), "graph"_a, "frames"_a); + fc.func_(kAddFrames.c_str(), ScriptBindings::overload_cast(&FrameCapture::addFrames), "name"_a, "frames"_a); auto printGraph = [](FrameCapture* pFC, RenderGraph* pGraph) { pybind11::print(pFC->graphFramesStr(pGraph)); }; - fc.func_(kPrintFrames.c_str(), printGraph); + fc.func_(kPrintFrames.c_str(), printGraph, "graph"_a); fc.func_(kCapture.c_str(), &FrameCapture::capture); auto printAllGraphs = [](FrameCapture* pFC) { @@ -89,8 +92,9 @@ namespace Mogwai fc.func_(kPrintFrames.c_str(), printAllGraphs); // Settings - auto showUI = [](FrameCapture* pFC, bool show) { pFC->mShowUI = show; }; - fc.func_(kUI.c_str(), showUI, "show"_a = true); + auto getUI = [](FrameCapture* pFC) { return pFC->mShowUI; }; + auto setUI = [](FrameCapture* pFC, bool show) { pFC->mShowUI = show; }; + fc.property(kUI.c_str(), getUI, setUI); } std::string FrameCapture::getScript() @@ -102,7 +106,7 @@ namespace Mogwai for (const auto& g : mGraphRanges) { - s += Scripting::makeMemberFunc(kScriptVar, kFrames, g.first->getName(), getFirstOfPair(g.second)); + s += Scripting::makeMemberFunc(kScriptVar, kAddFrames, g.first->getName(), getFirstOfPair(g.second)); } return s; } @@ -113,7 +117,7 @@ namespace Mogwai { Texture* pTex = pGraph->getOutput(i)->asTexture().get(); assert(pTex); - std::string filename = getOutputNamePrefix(pGraph->getOutputName(i)) + to_string(gpFramework->getGlobalClock().frame()) + ".";; + std::string filename = getOutputNamePrefix(pGraph->getOutputName(i)) + to_string(gpFramework->getGlobalClock().getFrame()) + ".";; auto ext = Bitmap::getFileExtFromResourceFormat(pTex->getFormat()); filename += ext; auto format = Bitmap::getFormatFromFileExtension(ext); @@ -121,16 +125,16 @@ namespace Mogwai } } - void FrameCapture::frames(const RenderGraph* pGraph, const uint64_vec& frames) + void FrameCapture::addFrames(const RenderGraph* pGraph, const uint64_vec& frames) { for (auto f : frames) addRange(pGraph, f, 1); } - void FrameCapture::frames(const std::string& graphName, const uint64_vec& frames) + void FrameCapture::addFrames(const std::string& graphName, const uint64_vec& frames) { auto pGraph = mpRenderer->getGraph(graphName).get(); if (!pGraph) throw std::runtime_error("Can't find a graph named `" + graphName + "`"); - this->frames(pGraph, frames); + this->addFrames(pGraph, frames); } std::string FrameCapture::graphFramesStr(const RenderGraph* pGraph) @@ -145,7 +149,7 @@ namespace Mogwai { auto pGraph = mpRenderer->getActiveGraph(); if (!pGraph) return; - uint64_t frameID = gpFramework->getGlobalClock().frame(); + uint64_t frameID = gpFramework->getGlobalClock().getFrame(); triggerFrame(gpDevice->getRenderContext(), pGraph, frameID); } } diff --git a/Source/Mogwai/Extensions/Capture/FrameCapture.h b/Source/Mogwai/Extensions/Capture/FrameCapture.h index 8beef0eb4..bd841592a 100644 --- a/Source/Mogwai/Extensions/Capture/FrameCapture.h +++ b/Source/Mogwai/Extensions/Capture/FrameCapture.h @@ -44,8 +44,8 @@ namespace Mogwai FrameCapture(Renderer* pRenderer) : CaptureTrigger(pRenderer) {} bool mShowUI = false; using uint64_vec = std::vector; - void frames(const RenderGraph* pGraph, const uint64_vec& frames); - void frames(const std::string& graphName, const uint64_vec& frames); + void addFrames(const RenderGraph* pGraph, const uint64_vec& frames); + void addFrames(const std::string& graphName, const uint64_vec& frames); std::string graphFramesStr(const RenderGraph* pGraph); }; } diff --git a/Source/Mogwai/Extensions/Capture/VideoCapture.cpp b/Source/Mogwai/Extensions/Capture/VideoCapture.cpp index 93421ec4a..a7ea08ced 100644 --- a/Source/Mogwai/Extensions/Capture/VideoCapture.cpp +++ b/Source/Mogwai/Extensions/Capture/VideoCapture.cpp @@ -39,6 +39,7 @@ namespace Mogwai const std::string kBitrate = "bitrate"; const std::string kGopSize = "gopSize"; const std::string kRanges = "ranges"; + const std::string kAddRanges = "addRanges"; const std::string kPrint = "print"; const std::string kOutputs = "outputs"; @@ -138,36 +139,35 @@ namespace Mogwai bindings.addGlobalObject(kScriptVar, this, "Video Capture Helpers"); // UI - auto showUI = [](VideoCapture* pFC, bool show) { pFC->mShowUI = show; }; - vc.func_(kUI.c_str(), showUI, "show"_a = true); + auto getUI = [](VideoCapture* pVC) { return pVC->mShowUI; }; + auto setUI = [](VideoCapture* pVC, bool show) { pVC->mShowUI = show; }; + vc.property(kUI.c_str(), getUI, setUI); // Settings auto getCodec = [](VideoCapture* pVC) {return pVC->mpEncoderUI->getCodec(); }; auto setCodec = [](VideoCapture* pVC, VideoEncoder::Codec c) {pVC->mpEncoderUI->setCodec(c); return pVC; }; - vc.func_(kCodec.c_str(), getCodec); - vc.func_(kCodec.c_str(), setCodec); + vc.property(kCodec.c_str(), getCodec, setCodec); auto getFPS = [](VideoCapture* pVC) {return pVC->mpEncoderUI->getFPS(); }; auto setFPS = [](VideoCapture* pVC, uint32_t fps) {pVC->mpEncoderUI->setFPS(fps); return pVC; }; - vc.func_(kFps.c_str(), getFPS); - vc.func_(kFps.c_str(), setFPS); + vc.property(kFps.c_str(), getFPS, setFPS); auto getBitrate = [](VideoCapture* pVC) {return pVC->mpEncoderUI->getBitrate(); }; auto setBitrate = [](VideoCapture* pVC, float bitrate) {pVC->mpEncoderUI->setBitrate(bitrate); return pVC; }; - vc.func_(kBitrate.c_str(), getBitrate); - vc.func_(kBitrate.c_str(), setBitrate); + vc.property(kBitrate.c_str(), getBitrate, setBitrate); auto getGopSize = [](VideoCapture* pVC) {return pVC->mpEncoderUI->getGopSize(); }; auto setGopSize = [](VideoCapture* pVC, uint32_t gop) {pVC->mpEncoderUI->setGopSize(gop); return pVC; }; - vc.func_(kGopSize.c_str(), getGopSize); - vc.func_(kGopSize.c_str(), setGopSize); + vc.property(kGopSize.c_str(), getGopSize, setGopSize); // Ranges - vc.func_(kRanges.c_str(), ScriptBindings::overload_cast(&VideoCapture::ranges)); - vc.func_(kRanges.c_str(), ScriptBindings::overload_cast(&VideoCapture::ranges)); + vc.func_(kRanges.c_str(), ScriptBindings::overload_cast(&VideoCapture::addRanges)); // PYTHONDEPRECATED + vc.func_(kRanges.c_str(), ScriptBindings::overload_cast(&VideoCapture::addRanges)); // PYTHONDEPRECATED + vc.func_(kAddRanges.c_str(), ScriptBindings::overload_cast(&VideoCapture::addRanges), "graph"_a, "ranges"_a); + vc.func_(kAddRanges.c_str(), ScriptBindings::overload_cast(&VideoCapture::addRanges), "name"_a, "ranges"_a); auto printGraph = [](VideoCapture* pVC, RenderGraph* pGraph) { pybind11::print(pVC->graphRangesStr(pGraph)); }; - vc.func_(kPrint.c_str(), printGraph); + vc.func_(kPrint.c_str(), printGraph, "graph"_a); auto printAllGraphs = [](VideoCapture* pVC) { @@ -184,28 +184,28 @@ namespace Mogwai std::string s("# Video Capture\n"); s += CaptureTrigger::getScript(kScriptVar); - s += Scripting::makeMemberFunc(kScriptVar, kCodec, mpEncoderUI->getCodec()); - s += Scripting::makeMemberFunc(kScriptVar, kFps, mpEncoderUI->getFPS()); - s += Scripting::makeMemberFunc(kScriptVar, kBitrate, mpEncoderUI->getBitrate()); - s += Scripting::makeMemberFunc(kScriptVar, kGopSize, mpEncoderUI->getGopSize()); + s += Scripting::makeSetProperty(kScriptVar, kCodec, mpEncoderUI->getCodec()); + s += Scripting::makeSetProperty(kScriptVar, kFps, mpEncoderUI->getFPS()); + s += Scripting::makeSetProperty(kScriptVar, kBitrate, mpEncoderUI->getBitrate()); + s += Scripting::makeSetProperty(kScriptVar, kGopSize, mpEncoderUI->getGopSize()); for (const auto& g : mGraphRanges) { - s += Scripting::makeMemberFunc(kScriptVar, kRanges, g.first->getName(), g.second); + s += Scripting::makeMemberFunc(kScriptVar, kAddRanges, g.first->getName(), g.second); } return s; } - void VideoCapture::ranges(const RenderGraph* pGraph, const range_vec& ranges) + void VideoCapture::addRanges(const RenderGraph* pGraph, const range_vec& ranges) { for (auto r : ranges) addRange(pGraph, r.first, r.second); } - void VideoCapture::ranges(const std::string& graphName, const range_vec& ranges) + void VideoCapture::addRanges(const std::string& graphName, const range_vec& ranges) { auto pGraph = mpRenderer->getGraph(graphName).get(); if (!pGraph) throw std::runtime_error("Can't find a graph named `" + graphName + "`"); - this->ranges(pGraph, ranges); + this->addRanges(pGraph, ranges); } std::string VideoCapture::graphRangesStr(const RenderGraph* pGraph) diff --git a/Source/Mogwai/Extensions/Capture/VideoCapture.h b/Source/Mogwai/Extensions/Capture/VideoCapture.h index 0ecf2df63..a74e758b4 100644 --- a/Source/Mogwai/Extensions/Capture/VideoCapture.h +++ b/Source/Mogwai/Extensions/Capture/VideoCapture.h @@ -26,6 +26,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ #pragma once +#include "../../Mogwai.h" #include "CaptureTrigger.h" #include "Utils/Video/VideoEncoderUI.h" #include "Utils/Video/VideoEncoder.h" @@ -46,8 +47,8 @@ namespace Mogwai private: VideoCapture(Renderer* pRenderer); - void ranges(const RenderGraph* pGraph, const range_vec& ranges); - void ranges(const std::string& graphName, const range_vec& ranges); + void addRanges(const RenderGraph* pGraph, const range_vec& ranges); + void addRanges(const std::string& graphName, const range_vec& ranges); std::string graphRangesStr(const RenderGraph* pGraph); bool mShowUI = false; diff --git a/Source/Mogwai/Extensions/Profiler/TimingCapture.cpp b/Source/Mogwai/Extensions/Profiler/TimingCapture.cpp index 2d6ef8708..f1c8cd031 100644 --- a/Source/Mogwai/Extensions/Profiler/TimingCapture.cpp +++ b/Source/Mogwai/Extensions/Profiler/TimingCapture.cpp @@ -50,7 +50,7 @@ namespace Mogwai bindings.addGlobalObject(kScriptVar, this, "Timing Capture Helpers"); // Members - c.func_(kCaptureFrameTime.c_str(), &TimingCapture::captureFrameTime); + c.func_(kCaptureFrameTime.c_str(), &TimingCapture::captureFrameTime, "filename"_a); } void TimingCapture::beginFrame(RenderContext* pRenderContext, const Fbo::SharedPtr& pTargetFbo) diff --git a/Source/Mogwai/Mogwai.cpp b/Source/Mogwai/Mogwai.cpp index 324982399..7eaa0bf54 100644 --- a/Source/Mogwai/Mogwai.cpp +++ b/Source/Mogwai/Mogwai.cpp @@ -43,10 +43,16 @@ namespace Mogwai const char* kScriptSwitch = "script"; const char* kGraphFileSwitch = "graphFile"; const char* kGraphNameSwitch = "graphName"; + + const std::string kAppDataPath = getAppDataDirectory() + "/NVIDIA/Falcor/Mogwai.json"; } size_t Renderer::DebugWindow::index = 0; + Renderer::Renderer() + : mAppData(kAppDataPath) + {} + void Renderer::extend(Extension::CreateFunc func, const std::string& name) { if (!gExtensions) gExtensions = new std::map(); @@ -163,15 +169,15 @@ namespace Mogwai } } - bool Renderer::renderDebugWindow(Gui::Widgets& widget, const Gui::DropdownList& dropdown, DebugWindow& data, const uvec2& winSize) + bool Renderer::renderDebugWindow(Gui::Widgets& widget, const Gui::DropdownList& dropdown, DebugWindow& data, const uint2& winSize) { // Get the current output, in case `renderOutputUI()` unmarks it Texture::SharedPtr pTex = std::dynamic_pointer_cast(mGraphs[mActiveGraph].pGraph->getOutput(data.currentOutput)); std::string label = data.currentOutput + "##" + mGraphs[mActiveGraph].pGraph->getName(); if (!pTex) { logError("Invalid output resource. Is not a texture."); } - uvec2 debugSize = (uvec2)(vec2(winSize) * vec2(0.4f, 0.55f)); - uvec2 debugPos = winSize - debugSize; + uint2 debugSize = (uint2)(float2(winSize) * float2(0.4f, 0.55f)); + uint2 debugPos = winSize - debugSize; debugPos -= 10; // Display the dropdown @@ -208,7 +214,7 @@ namespace Mogwai if (graphOuts.size()) { - uvec2 dims(gpFramework->getTargetFbo()->getWidth(), gpFramework->getTargetFbo()->getHeight()); + uint2 dims(gpFramework->getTargetFbo()->getWidth(), gpFramework->getTargetFbo()->getHeight()); for (size_t i = 0; i < mGraphs[mActiveGraph].debugWindows.size();) { @@ -236,9 +242,20 @@ namespace Mogwai void Renderer::onDroppedFile(const std::string& filename) { std::string ext = getExtensionFromFile(filename); - if (std::any_of(Scene::kFileExtensionFilters.begin(), Scene::kFileExtensionFilters.end(), [&ext](FileDialogFilter f) {return f.ext == ext; })) loadScene(filename); - else if (ext == "py") loadScript(filename); - else logWarning("RenderGraphViewer::onDroppedFile() - Unknown file extension `" + ext + "`"); + if (ext == "py") + { + loadScript(filename); + mAppData.addRecentScript(filename); + } + else if (std::any_of(Scene::kFileExtensionFilters.begin(), Scene::kFileExtensionFilters.end(), [&ext](FileDialogFilter f) {return f.ext == ext; })) + { + loadScene(filename); + mAppData.addRecentScene(filename); + } + else + { + logWarning("RenderGraphViewer::onDroppedFile() - Unknown file extension `" + ext + "`"); + } } void Renderer::editorFileChangeCB() @@ -355,7 +372,17 @@ namespace Mogwai void Renderer::loadScriptDialog() { - openFileDialog(Scripting::kFileExtensionFilters, mScriptFilename); + std::string filename; + if (openFileDialog(Scripting::kFileExtensionFilters, filename)) + { + mAppData.addRecentScript(filename); + loadScriptDeferred(filename); + } + } + + void Renderer::loadScriptDeferred(const std::string& filename) + { + mScriptFilename = filename; } void Renderer::loadScript(const std::string& filename) @@ -401,6 +428,7 @@ namespace Mogwai std::string filename; if (openFileDialog(Scene::kFileExtensionFilters, filename)) { + mAppData.addRecentScene(filename); loadScene(filename); } } @@ -410,16 +438,6 @@ namespace Mogwai setScene(SceneBuilder::create(filename, buildFlags)->getScene()); } - // Temporary workaround for setting environment maps for non-fscenes, remove when all scene files support environment maps - void Renderer::setEnvMap(std::string filename) - { - if (mpScene) - { - Texture::SharedPtr pEnvMap = Texture::createFromFile(filename, false, true); - mpScene->setEnvironmentMap(pEnvMap); - } - } - void Renderer::setScene(Scene::ConstSharedPtrRef pScene) { mpScene = pScene; @@ -442,7 +460,7 @@ namespace Mogwai } for (auto& g : mGraphs) g.pGraph->setScene(mpScene); - gpFramework->getGlobalClock().now(0); + gpFramework->getGlobalClock().setTime(0); } Scene::SharedPtr Renderer::getScene() const @@ -517,7 +535,7 @@ namespace Mogwai applyEditorChanges(); // Clear frame buffer. - const glm::vec4 clearColor(0.38f, 0.52f, 0.10f, 1); + const float4 clearColor(0.38f, 0.52f, 0.10f, 1); pRenderContext->clearFbo(pTargetFbo.get(), clearColor, 1.0f, 0, FboAttachmentType::All); if (mGraphs.size()) @@ -527,7 +545,7 @@ namespace Mogwai // Update scene and camera. if (mpScene) { - mpScene->update(pRenderContext, gpFramework->getGlobalClock().now()); + mpScene->update(pRenderContext, gpFramework->getGlobalClock().getTime()); } executeActiveGraph(pRenderContext); diff --git a/Source/Mogwai/Mogwai.h b/Source/Mogwai/Mogwai.h index 77f0e3342..28d413a53 100644 --- a/Source/Mogwai/Mogwai.h +++ b/Source/Mogwai/Mogwai.h @@ -28,6 +28,7 @@ #pragma once #include "Falcor.h" #include "FalcorExperimental.h" +#include "AppData.h" using namespace Falcor; @@ -78,7 +79,7 @@ namespace Mogwai class Renderer : public IRenderer { public: - Renderer() = default; + Renderer(); void onLoad(RenderContext* pRenderContext) override; void onFrameRender(RenderContext* pRenderContext, const Fbo::SharedPtr& pTargetFbo) override; void onResizeSwapChain(uint32_t width, uint32_t height) override; @@ -89,6 +90,7 @@ namespace Mogwai void onShutdown() override; void onDroppedFile(const std::string& filename) override; void loadScriptDialog(); + void loadScriptDeferred(const std::string& filename); void loadScript(const std::string& filename); void dumpConfig(std::string filename = {}) const; static std::string getVersionString(); @@ -98,7 +100,10 @@ namespace Mogwai static constexpr uint32_t kMajorVersion = 0; static constexpr uint32_t kMinorVersion = 1; + const AppData& getAppData() const { return mAppData; } + RenderGraph* getActiveGraph() const; + // private: // MOGWAI friend class Extension; std::vector mpExtensions; @@ -131,7 +136,6 @@ namespace Mogwai void removeActiveGraph(); void loadSceneDialog(); void loadScene(std::string filename, SceneBuilder::Flags buildFlags = SceneBuilder::Flags::Default); - void setEnvMap(std::string filename); void setScene(Scene::ConstSharedPtrRef pScene); Scene::SharedPtr getScene() const; void executeActiveGraph(RenderContext* pRenderContext); @@ -140,7 +144,7 @@ namespace Mogwai std::vector getGraphOutputs(const RenderGraph::SharedPtr& pGraph); void graphOutputsGui(Gui::Widgets& widget); - bool renderDebugWindow(Gui::Widgets& widget, const Gui::DropdownList& dropdown, DebugWindow& data, const uvec2& winSize); // Returns false if the window was closed + bool renderDebugWindow(Gui::Widgets& widget, const Gui::DropdownList& dropdown, DebugWindow& data, const uint2& winSize); // Returns false if the window was closed void renderOutputUI(Gui::Widgets& widget, const Gui::DropdownList& dropdown, std::string& selectedOutput); void addDebugWindow(); void eraseDebugWindow(size_t id); @@ -148,6 +152,8 @@ namespace Mogwai void markOutput(const std::string& name); size_t findGraph(std::string_view name); + AppData mAppData; + std::vector mGraphs; uint32_t mActiveGraph = 0; Sampler::SharedPtr mpSampler = nullptr; @@ -177,13 +183,4 @@ namespace Mogwai Renderer::extend(Name::create, #Name); \ } \ } gRendererExtensions##Name; - - constexpr char kRendererVar[] = "m"; // MOGWAI do we want to expose it to all the extensions? - - inline std::string filenameString(const std::string& s, bool stripDataDirs = true) - { - std::string filename = stripDataDirs ? stripDataDirectories(s) : s; - std::replace(filename.begin(), filename.end(), '\\', '/'); - return filename; - } } diff --git a/Source/Mogwai/Mogwai.vcxproj b/Source/Mogwai/Mogwai.vcxproj index 8deb203a3..7cb8ee843 100644 --- a/Source/Mogwai/Mogwai.vcxproj +++ b/Source/Mogwai/Mogwai.vcxproj @@ -11,6 +11,7 @@ + @@ -23,6 +24,7 @@ + diff --git a/Source/Mogwai/Mogwai.vcxproj.filters b/Source/Mogwai/Mogwai.vcxproj.filters index 0f7b03bfe..adde3fdd7 100644 --- a/Source/Mogwai/Mogwai.vcxproj.filters +++ b/Source/Mogwai/Mogwai.vcxproj.filters @@ -17,6 +17,7 @@ Extensions\Profiler + @@ -34,6 +35,7 @@ Extensions\Profiler + diff --git a/Source/Mogwai/MogwaiScripting.cpp b/Source/Mogwai/MogwaiScripting.cpp index 400f0b8bd..22344535c 100644 --- a/Source/Mogwai/MogwaiScripting.cpp +++ b/Source/Mogwai/MogwaiScripting.cpp @@ -31,19 +31,19 @@ namespace Mogwai { namespace { - constexpr char kScene[] = "s"; - const std::string kRunScript = "script"; const std::string kLoadScene = "loadScene"; - const std::string kSetEnvMap = "envMap"; const std::string kSaveConfig = "saveConfig"; const std::string kAddGraph = "addGraph"; const std::string kRemoveGraph = "removeGraph"; - const std::string kToggleUI = "ui"; + const std::string kGetGraph = "getGraph"; + const std::string kUI = "ui"; const std::string kResizeSwapChain = "resizeSwapChain"; const std::string kActiveGraph = "activeGraph"; - const std::string kGetGraph = "graph"; - const std::string kGetScene = "scene"; + const std::string kScene = "scene"; + + const std::string kRendererVar = "m"; + const std::string kTimeVar = "t"; template std::string prepareHelpMessage(const T& g) @@ -70,38 +70,44 @@ namespace Mogwai SampleConfig c = gpFramework->getConfig(); s += "# Window Configuration\n"; s += Scripting::makeMemberFunc(kRendererVar, kResizeSwapChain, c.windowDesc.width, c.windowDesc.height); - s += Scripting::makeMemberFunc(kRendererVar, kToggleUI, c.showUI); + s += Scripting::makeSetProperty(kRendererVar, kUI, c.showUI); return s; } } void Renderer::dumpConfig(std::string filename) const { - if(filename.empty()) + if (filename.empty()) { if (!saveFileDialog(Scripting::kFileExtensionFilters, filename)) return; } std::string s; - if (mpScene) + if (!mGraphs.empty()) { - s += "# Scene\n"; - s += Scripting::makeMemberFunc(kRendererVar, kLoadScene, filenameString(mpScene->getFilename())); - if (mpScene->getEnvironmentMap() != nullptr) + s += "# Graphs\n"; + for (const auto& g : mGraphs) { - s += Scripting::makeMemberFunc(kRendererVar, kSetEnvMap, filenameString(mpScene->getEnvironmentMap()->getSourceFilename())); + s += RenderGraphExporter::getIR(g.pGraph); + s += kRendererVar + "." + kAddGraph + "(" + RenderGraphIR::getFuncName(g.pGraph->getName()) + "())\n"; } + s += "\n"; } - if(mGraphs.size()) s += "\n# Graphs\n"; - for (auto& g : mGraphs) + if (mpScene) { - s += RenderGraphExporter::getIR(g.pGraph); - s += std::string(kRendererVar) + "." + kAddGraph + "(" + RenderGraphIR::getFuncName(g.pGraph->getName()) + "())\n"; + s += "# Scene\n"; + s += Scripting::makeMemberFunc(kRendererVar, kLoadScene, Scripting::getFilenameString(mpScene->getFilename())); + const std::string sceneVar = kRendererVar + "." + kScene; + s += mpScene->getScript(sceneVar); + s += "\n"; } - s += "\n" + windowConfig() + "\n"; + s += windowConfig() + "\n"; + + s += "# Time Settings\n"; + s += gpFramework->getGlobalClock().getScript(kTimeVar) + "\n"; for (auto& pe : mpExtensions) { @@ -109,13 +115,6 @@ namespace Mogwai if (eStr.size()) s += eStr + "\n"; } - if (mpScene->hasSavedViewpoints()) - { - s += "# Saved Viewpoints\n"; - s += std::string(kScene) + " = " + Scripting::makeMemberFunc(kRendererVar, kGetScene); - s += mpScene->getConfig() + "\n"; - } - std::ofstream(filename) << s; } @@ -125,16 +124,25 @@ namespace Mogwai c.func_(kRunScript.c_str(), &Renderer::loadScript, "filename"_a = std::string()); c.func_(kLoadScene.c_str(), &Renderer::loadScene, "filename"_a = std::string(), "buildFlags"_a = SceneBuilder::Flags::Default); - c.func_(kSetEnvMap.c_str(), &Renderer::setEnvMap); c.func_(kSaveConfig.c_str(), &Renderer::dumpConfig, "filename"_a = std::string()); - c.func_(kAddGraph.c_str(), &Renderer::addGraph); - c.func_(kRemoveGraph.c_str(), ScriptBindings::overload_cast(&Renderer::removeGraph)); - c.func_(kRemoveGraph.c_str(), ScriptBindings::overload_cast(&Renderer::removeGraph)); - c.func_(kGetGraph.c_str(), &Renderer::getGraph); - c.func_(kGetScene.c_str(), &Renderer::getScene); + c.func_(kAddGraph.c_str(), &Renderer::addGraph, "graph"_a); + c.func_(kRemoveGraph.c_str(), ScriptBindings::overload_cast(&Renderer::removeGraph), "name"_a); + c.func_(kRemoveGraph.c_str(), ScriptBindings::overload_cast(&Renderer::removeGraph), "graph"_a); + c.func_(kGetGraph.c_str(), &Renderer::getGraph, "name"_a); + c.func_("graph", &Renderer::getGraph); // PYTHONDEPRECATED + auto envMap = [](Renderer* pRenderer, const std::string& filename) { if (pRenderer->getScene()) pRenderer->getScene()->loadEnvironmentMap(filename); }; + c.func_("envMap", envMap, "filename"_a); // PYTHONDEPRECATED + + c.roProperty(kScene.c_str(), &Renderer::getScene); + c.roProperty(kActiveGraph.c_str(), &Renderer::getActiveGraph); + + auto getUI = [](Renderer* pRenderer) { return gpFramework->isUiEnabled(); }; + auto setUI = [](Renderer* pRenderer, bool show) { gpFramework->toggleUI(show); }; + c.property(kUI.c_str(), getUI, setUI); Extension::Bindings b(m, c); b.addGlobalObject(kRendererVar, this, "The engine"); + b.addGlobalObject(kTimeVar, &gpFramework->getGlobalClock(), "Time Utilities"); for (auto& pe : mpExtensions) pe->scriptBindings(b); mGlobalHelpMessage = prepareHelpMessage(b.mGlobalObjects); @@ -148,13 +156,10 @@ namespace Mogwai auto h = b.attr("help"); h(o); }; - m.func_("help", objectHelp); + m.func_("help", objectHelp, "object"_a); + // PYTHONDEPRECATED Use the global function defined in the script bindings in Sample.cpp when resizing from a Python script. auto resize = [](Renderer* pRenderer, uint32_t width, uint32_t height) {gpFramework->resizeSwapChain(width, height); }; c.func_(kResizeSwapChain.c_str(), resize); - - auto toggleUI = [](Renderer* pRenderer, bool show) {gpFramework->toggleUI(show); }; - c.func_(kToggleUI.c_str(), toggleUI, "show"_a = true); - c.func_(kActiveGraph.c_str(), &Renderer::getActiveGraph); } } diff --git a/Source/Mogwai/MogwaiSettings.cpp b/Source/Mogwai/MogwaiSettings.cpp index 0fe84606b..4c6a92fa5 100644 --- a/Source/Mogwai/MogwaiSettings.cpp +++ b/Source/Mogwai/MogwaiSettings.cpp @@ -34,15 +34,11 @@ namespace Mogwai { namespace { - bool vsync = false; - constexpr char kTime[] = "t"; - constexpr char kExitTime[] = "exitTime"; - constexpr char kExitFrame[] = "exitFrame"; - void shortcuts() { std::string s; s += " 'F1' - Show the help message\n"; + s += " 'F9' - Show/Hide the time\n"; s += " 'F10' - Show/Hide the FPS\n"; s += " 'F11' - Toggle Main Menu Auto-Hide\n"; s += "\n" + gpFramework->getKeyboardShortcutsStr(); @@ -66,7 +62,7 @@ namespace Mogwai void winSizeUI(Gui::Window& w) { - static const uvec2 resolutions[] = + static const uint2 resolutions[] = { {1280, 720}, {1920, 1080}, @@ -77,7 +73,7 @@ namespace Mogwai constexpr uint32_t kCustomIndex = uint32_t(-1); - static const auto initDropDown = [=](const uvec2 resolutions[], uint32_t count) -> Gui::DropdownList + static const auto initDropDown = [=](const uint2 resolutions[], uint32_t count) -> Gui::DropdownList { Gui::DropdownList list; for (uint32_t i = 0; i < count; i++) @@ -88,7 +84,7 @@ namespace Mogwai return list; }; - auto initDropDownVal = [=](const uvec2 resolutions[], uint32_t count, uvec2 screenDims) + auto initDropDownVal = [=](const uint2 resolutions[], uint32_t count, uint2 screenDims) { for (uint32_t i = 0; i < count; i++) { @@ -97,14 +93,14 @@ namespace Mogwai return kCustomIndex; }; - uvec2 currentRes = gpFramework->getWindow()->getClientAreaSize(); + uint2 currentRes = gpFramework->getWindow()->getClientAreaSize(); static const Gui::DropdownList dropdownList = initDropDown(resolutions, arraysize(resolutions)); uint32_t currentVal = initDropDownVal(resolutions, arraysize(resolutions), currentRes); w.text("Window Size"); w.tooltip("The Window Size refers to the renderable area size (Swap-Chain dimensions)"); bool dropdownChanged = w.dropdown("##resdd", dropdownList, currentVal); - static uvec2 customSize; + static uint2 customSize; static bool forceCustom = false; if (dropdownChanged) @@ -153,12 +149,15 @@ namespace Mogwai clock.renderUI(w); w.separator(2); - if (mExitTime || mExitFrame) + double exitTime = clock.getExitTime(); + uint64_t exitFrame = clock.getExitFrame(); + + if (exitTime || exitTime) { std::stringstream s; s << "Exiting in "; - if(mExitTime) s << std::fixed << std::setprecision(2) << (mExitTime - clock.now()) << " seconds"; - if(mExitFrame) s << (mExitFrame - clock.frame()) << " frames"; + if (exitTime) s << std::fixed << std::setprecision(2) << (exitTime - clock.getTime()) << " seconds"; + if (exitFrame) s << (exitFrame - clock.getFrame()) << " frames"; w.text(s.str()); } } @@ -212,6 +211,23 @@ namespace Mogwai // if (file.item("Reset Scene")) mpRenderer->setScene(nullptr); file.separator(); if (file.item("Reload Render-Passes", "F5")) RenderPassLibrary::instance().reloadLibraries(gpFramework->getRenderContext()); + file.separator(); + + { + auto recentScripts = file.menu("Recent Scripts"); + for (const auto& path : mpRenderer->getAppData().getRecentScripts()) + { + if (recentScripts.item(path)) mpRenderer->loadScriptDeferred(path); + } + } + + { + auto recentScenes = file.menu("Recent Scenes"); + for (const auto& path : mpRenderer->getAppData().getRecentScenes()) + { + if (recentScenes.item(path)) mpRenderer->loadScene(path); + } + } } { @@ -243,18 +259,6 @@ namespace Mogwai if (mShowConsole) Console::render(pGui__); } - void MogwaiSettings::exitIfNeeded() - { - auto& clock = gpFramework->getGlobalClock(); - if (mExitTime && (clock.now() >= mExitTime)) postQuitMessage(0); - if (mExitFrame && (clock.frame() >= mExitFrame)) postQuitMessage(0); - } - - void MogwaiSettings::beginFrame(RenderContext* pRenderContext, const Fbo::SharedPtr& pTargetFbo) - { - exitIfNeeded(); - } - bool MogwaiSettings::mouseEvent(const MouseEvent& e) { if (e.type == MouseEvent::Type::Move) mMousePosition = e.screenPos; @@ -321,34 +325,4 @@ namespace Mogwai { return UniquePtr(new MogwaiSettings(pRenderer)); } - - void MogwaiSettings::scriptBindings(Bindings& bindings) - { - auto& m = bindings.getModule(); - - auto mm = pybind11::module::import("falcor"); - auto t = mm.attr("Clock").cast>(); - - bindings.addGlobalObject(kTime, &gpFramework->getGlobalClock(), "Time Utilities"); - - auto setExitTime = [this](Clock*, double exitTime) {mExitTime = exitTime; mExitFrame = 0; }; - t.def(kExitTime, setExitTime); - - auto setExitFrame = [this](Clock*, uint64_t exitFrame) {mExitFrame = exitFrame; mExitTime = 0; }; - t.def(kExitFrame, setExitFrame); - - auto showUI = [this](Clock*, bool show) { mShowTime = show; }; - t.def("ui", showUI ,"show"_a = true); - } - - std::string MogwaiSettings::getScript() - { - std::string s; - - s += "# Global Settings\n"; - s += gpFramework->getGlobalClock().getScript(kTime) + "\n"; - if(mExitTime) s += Scripting::makeMemberFunc(kTime, kExitTime, mExitTime); - if(mExitFrame) s += Scripting::makeMemberFunc(kTime, kExitFrame, mExitFrame); - return s; - } } diff --git a/Source/Mogwai/MogwaiSettings.h b/Source/Mogwai/MogwaiSettings.h index 9d764bd65..ff30d558e 100644 --- a/Source/Mogwai/MogwaiSettings.h +++ b/Source/Mogwai/MogwaiSettings.h @@ -41,9 +41,6 @@ namespace Mogwai void renderUI(Gui* pGui) override; bool mouseEvent(const MouseEvent& e) override; bool keyboardEvent(const KeyboardEvent& e) override; - void scriptBindings(Bindings& bindings) override; - std::string getScript() override; - void beginFrame(RenderContext* pRenderContext, const Fbo::SharedPtr& pTargetFbo) override; private: MogwaiSettings(Renderer* pRenderer); @@ -61,8 +58,6 @@ namespace Mogwai bool mShowConsole = false; bool mShowTime = false; bool mShowWinSize = false; - uvec2 mMousePosition; - double mExitTime = 0; - uint64_t mExitFrame = 0; + uint2 mMousePosition; }; } diff --git a/Source/RenderPasses/AccumulatePass/AccumulatePass.cpp b/Source/RenderPasses/AccumulatePass/AccumulatePass.cpp index bfcb44ec8..d67347759 100644 --- a/Source/RenderPasses/AccumulatePass/AccumulatePass.cpp +++ b/Source/RenderPasses/AccumulatePass/AccumulatePass.cpp @@ -149,7 +149,7 @@ void AccumulatePass::execute(RenderContext* pRenderContext, const RenderData& re assert(pSrc && pDst); assert(pSrc->getWidth() == pDst->getWidth() && pSrc->getHeight() == pDst->getHeight()); - const glm::uvec2 resolution = glm::uvec2(pSrc->getWidth(), pSrc->getHeight()); + const uint2 resolution = uint2(pSrc->getWidth(), pSrc->getHeight()); // If accumulation is disabled, just blit the source to the destination and return. if (!mEnableAccumulation) @@ -177,7 +177,7 @@ void AccumulatePass::execute(RenderContext* pRenderContext, const RenderData& re // Run the accumulation program. auto pProgram = mpProgram[mPrecisionMode]; assert(pProgram); - glm::uvec3 numGroups = div_round_up(glm::uvec3(resolution.x, resolution.y, 1u), pProgram->getReflector()->getThreadGroupSize()); + uint3 numGroups = div_round_up(uint3(resolution.x, resolution.y, 1u), pProgram->getReflector()->getThreadGroupSize()); mpState->setProgram(pProgram); pRenderContext->dispatch(mpState.get(), mpVars.get(), numGroups); } @@ -238,7 +238,7 @@ void AccumulatePass::prepareAccumulation(RenderContext* pRenderContext, uint32_t if (mFrameCount == 0) { if (getFormatType(format) == FormatType::Float) pRenderContext->clearUAV(pBuf->getUAV().get(), float4(0.f)); - else pRenderContext->clearUAV(pBuf->getUAV().get(), glm::uvec4(0)); + else pRenderContext->clearUAV(pBuf->getUAV().get(), uint4(0)); } }; diff --git a/Source/RenderPasses/AccumulatePass/AccumulatePass.h b/Source/RenderPasses/AccumulatePass/AccumulatePass.h index 4c7bb2e9b..2a6d58956 100644 --- a/Source/RenderPasses/AccumulatePass/AccumulatePass.h +++ b/Source/RenderPasses/AccumulatePass/AccumulatePass.h @@ -76,7 +76,7 @@ class AccumulatePass : public RenderPass, public inherit_shared_from_thisattachColorTarget(pDst, 0); mpPass["gSrc"] = pSrc; - vec2 rcpFrame = 1.0f / vec2(pSrc->getWidth(), pSrc->getHeight()); + float2 rcpFrame = 1.0f / float2(pSrc->getWidth(), pSrc->getHeight()); auto pCB = mpPass["PerFrameCB"]; pCB["rcpTexDim"] = rcpFrame; diff --git a/Source/RenderPasses/BSDFViewer/BSDFViewer.cpp b/Source/RenderPasses/BSDFViewer/BSDFViewer.cpp index 094c28128..fe7f576a5 100644 --- a/Source/RenderPasses/BSDFViewer/BSDFViewer.cpp +++ b/Source/RenderPasses/BSDFViewer/BSDFViewer.cpp @@ -72,6 +72,8 @@ BSDFViewer::BSDFViewer(const Dictionary& dict) // Create readback buffer. mPixelDataBuffer = Buffer::createStructured(mpViewerPass->getProgram().get(), "gPixelData", 1u, ResourceBindFlags::UnorderedAccess); + + mpPixelDebug = PixelDebug::create(); } Dictionary BSDFViewer::getScriptingDictionary() @@ -122,13 +124,11 @@ void BSDFViewer::setScene(RenderContext* pRenderContext, const Scene::SharedPtr& mpViewerPass["gScene"] = mpScene->getParameterBlock(); // Load and bind environment map. - // We're getting the file name from the scene's LightProbe because that was used in the fscene files. - // TODO: Switch to use Scene::getEnvironmentMap() when the assets have been updated. - auto pLightProbe = mpScene->getLightProbe(); - if (pLightProbe != nullptr) + Texture::SharedPtr pEnvMap = mpScene->getEnvironmentMap(); + if (pEnvMap != nullptr) { - std::string fn = pLightProbe->getOrigTexture()->getSourceFilename(); - loadEnvMap(pRenderContext, fn); + std::string filename = pEnvMap->getSourceFilename(); + loadEnvMap(pRenderContext, filename); } if (!mpEnvProbe) mParams.useEnvMap = false; @@ -172,8 +172,13 @@ void BSDFViewer::execute(RenderContext* pRenderContext, const RenderData& render mpViewerPass["gPixelData"] = mPixelDataBuffer; mpViewerPass["PerFrameCB"]["gParams"].setBlob(mParams); + mpPixelDebug->beginFrame(pRenderContext, renderData.getDefaultTextureDims()); + mpPixelDebug->prepareProgram(mpViewerPass->getProgram(), mpViewerPass->getRootVar()); + // Execute pass. - mpViewerPass->execute(pRenderContext, uvec3(mParams.frameDim, 1)); + mpViewerPass->execute(pRenderContext, uint3(mParams.frameDim, 1)); + + mpPixelDebug->endFrame(pRenderContext); mPixelDataValid = false; if (mParams.readback) @@ -260,7 +265,7 @@ void BSDFViewer::renderUI(Gui::Widgets& widget) if (mParams.sliceViewer) { - bsdfGroup.dummy("#space1", vec2(1, 8)); + bsdfGroup.dummy("#space1", float2(1, 8)); bsdfGroup.text("Slice viewer settings:"); dirty |= bsdfGroup.checkbox("Enable diffuse", mParams.enableDiffuse); @@ -315,12 +320,12 @@ void BSDFViewer::renderUI(Gui::Widgets& widget) auto filters = Bitmap::getFileDialogFilters(); filters.push_back({ "dds", "DDS textures" }); - std::string fn; - if (openFileDialog(filters, fn)) + std::string filename; + if (openFileDialog(filters, filename)) { // TODO: RenderContext* should maybe be a parameter to renderUI()? auto pRenderContext = gpFramework->getRenderContext(); - if (loadEnvMap(pRenderContext, fn)) + if (loadEnvMap(pRenderContext, filename)) { mParams.useDirectionalLight = false; mParams.useEnvMap = true; @@ -381,7 +386,15 @@ void BSDFViewer::renderUI(Gui::Widgets& widget) pixelGroup.release(); } - //widget.dummy("#space3", vec2(1, 16)); + auto loggingGroup = Gui::Group(widget, "Logging", false); + if (loggingGroup.open()) + { + mpPixelDebug->renderUI(widget); + + loggingGroup.release(); + } + + //widget.dummy("#space3", float2(1, 16)); //dirty |= widget.checkbox("Debug switch", mParams.debugSwitch0); if (dirty) @@ -394,9 +407,10 @@ bool BSDFViewer::onMouseEvent(const MouseEvent& mouseEvent) { if (mouseEvent.type == MouseEvent::Type::LeftButtonDown) { - mParams.selectedPixel = glm::clamp((glm::ivec2)(mouseEvent.pos * (glm::vec2)mParams.frameDim), { 0,0 }, (glm::ivec2)mParams.frameDim - 1); + mParams.selectedPixel = glm::clamp((int2)(mouseEvent.pos * (float2)mParams.frameDim), { 0,0 }, (int2)mParams.frameDim - 1); } - return false; + + return mpPixelDebug->onMouseEvent(mouseEvent); } bool BSDFViewer::onKeyEvent(const KeyboardEvent& keyEvent) diff --git a/Source/RenderPasses/BSDFViewer/BSDFViewer.cs.slang b/Source/RenderPasses/BSDFViewer/BSDFViewer.cs.slang index 5067d4a8e..2589558a4 100644 --- a/Source/RenderPasses/BSDFViewer/BSDFViewer.cs.slang +++ b/Source/RenderPasses/BSDFViewer/BSDFViewer.cs.slang @@ -33,6 +33,7 @@ import Scene.TextureSampler; import Experimental.Scene.Material.MaterialShading; import Experimental.Scene.Lights.EnvProbe; import Utils.Sampling.SampleGenerator; +import Utils.Debug.PixelDebug; import Utils.Math.BitTricks; import Utils.Math.MathHelpers; import BSDFViewerParams; @@ -212,7 +213,7 @@ SurfaceData prepareMaterial(VertexData v, float3 viewDir) data.sd = _prepareShadingData(v, gParams.materialID, gScene.materials[gParams.materialID], gScene.materialResources[gParams.materialID], viewDir, lod, gParams.useNormalMapping); // Setup additional fields not currently available in ShadingData. - MaterialData md = gScene.materials[gParams.materialID]; + MaterialData md = gScene.getMaterial(gParams.materialID); MaterialResources mr = gScene.materialResources[gParams.materialID]; data.baseColor = sampleTexture(mr.baseColor, mr.samplerState, v.texC, md.baseColor, EXTRACT_DIFFUSE_TYPE(md.flags), lod).rgb; } @@ -393,6 +394,8 @@ void main(uint3 dispatchThreadID : SV_DispatchThreadID) const uint2 pixel = dispatchThreadID.xy; if (any(pixel >= gParams.frameDim)) return; + printSetPixel(pixel); + SurfaceData data = {}; float3 output = 0; float2 uv = getViewportCoord(pixel); diff --git a/Source/RenderPasses/BSDFViewer/BSDFViewer.h b/Source/RenderPasses/BSDFViewer/BSDFViewer.h index 76a7a787e..9b72a9e48 100644 --- a/Source/RenderPasses/BSDFViewer/BSDFViewer.h +++ b/Source/RenderPasses/BSDFViewer/BSDFViewer.h @@ -30,6 +30,7 @@ #include "FalcorExperimental.h" #include "BSDFViewerParams.slang" #include "Utils/Sampling/SampleGenerator.h" +#include "Utils/Debug/PixelDebug.h" #include "Experimental/Scene/Lights/EnvProbe.h" using namespace Falcor; @@ -72,6 +73,8 @@ class BSDFViewer : public RenderPass, public inherit_shared_from_thisblit(pSrcTex->getSRV(), pDstTex->getRTV(), uvec4(-1), uvec4(-1), mFilter); + pContext->blit(pSrcTex->getSRV(), pDstTex->getRTV(), uint4(-1), uint4(-1), mFilter); } else { diff --git a/Source/RenderPasses/CSM/CSM.cpp b/Source/RenderPasses/CSM/CSM.cpp index 6ace9e8e5..7efd55638 100644 --- a/Source/RenderPasses/CSM/CSM.cpp +++ b/Source/RenderPasses/CSM/CSM.cpp @@ -215,35 +215,35 @@ class CsmSceneRenderer : public SceneRenderer }; #endif -static void createShadowMatrix(const DirectionalLight* pLight, const glm::vec3& center, float radius, glm::mat4& shadowVP) +static void createShadowMatrix(const DirectionalLight* pLight, const float3& center, float radius, glm::mat4& shadowVP) { - glm::mat4 view = glm::lookAt(center, center + pLight->getWorldDirection(), glm::vec3(0, 1, 0)); + glm::mat4 view = glm::lookAt(center, center + pLight->getWorldDirection(), float3(0, 1, 0)); glm::mat4 proj = glm::ortho(-radius, radius, -radius, radius, -radius, radius); shadowVP = proj * view; } -static void createShadowMatrix(const PointLight* pLight, const glm::vec3& center, float radius, float fboAspectRatio, glm::mat4& shadowVP) +static void createShadowMatrix(const PointLight* pLight, const float3& center, float radius, float fboAspectRatio, glm::mat4& shadowVP) { - const glm::vec3 lightPos = pLight->getWorldPosition(); - const glm::vec3 lookat = pLight->getWorldDirection() + lightPos; - glm::vec3 up(0, 1, 0); + const float3 lightPos = pLight->getWorldPosition(); + const float3 lookat = pLight->getWorldDirection() + lightPos; + float3 up(0, 1, 0); if (abs(glm::dot(up, pLight->getWorldDirection())) >= 0.95f) { - up = glm::vec3(1, 0, 0); + up = float3(1, 0, 0); } glm::mat4 view = glm::lookAt(lightPos, lookat, up); float distFromCenter = glm::length(lightPos - center); - float nearZ = max(0.1f, distFromCenter - radius); - float maxZ = min(radius * 2, distFromCenter + radius); + float nearZ = std::max(0.1f, distFromCenter - radius); + float maxZ = std::min(radius * 2, distFromCenter + radius); float angle = pLight->getOpeningAngle() * 2; glm::mat4 proj = glm::perspective(angle, fboAspectRatio, nearZ, maxZ); shadowVP = proj * view; } -static void createShadowMatrix(const Light* pLight, const glm::vec3& center, float radius, float fboAspectRatio, glm::mat4& shadowVP) +static void createShadowMatrix(const Light* pLight, const float3& center, float radius, float fboAspectRatio, glm::mat4& shadowVP) { switch (pLight->getType()) { @@ -340,7 +340,7 @@ CSM::CSM() mpLightCamera = Camera::create(); Sampler::Desc samplerDesc; - samplerDesc.setFilterMode(Sampler::Filter::Point, Sampler::Filter::Point, Sampler::Filter::Point).setAddressingMode(Sampler::AddressMode::Border, Sampler::AddressMode::Border, Sampler::AddressMode::Border).setBorderColor(glm::vec4(1.0f)); + samplerDesc.setFilterMode(Sampler::Filter::Point, Sampler::Filter::Point, Sampler::Filter::Point).setAddressingMode(Sampler::AddressMode::Border, Sampler::AddressMode::Border, Sampler::AddressMode::Border).setBorderColor(float4(1.0f)); samplerDesc.setLodParams(0.f, 0.f, 0.f); samplerDesc.setComparisonMode(Sampler::ComparisonMode::LessEqual); mShadowPass.pPointCmpSampler = Sampler::create(samplerDesc); @@ -358,8 +358,8 @@ CSM::SharedPtr CSM::create(RenderContext* pRenderContext, const Dictionary& dict auto pCSM = SharedPtr(new CSM()); for (const auto& v : dict) { - if (v.key() == kMapSize) pCSM->mMapSize = (uvec2)v.val(); - else if (v.key() == kVisBufferSize) pCSM->mVisibilityPassData.screenDim = (uvec2)v.val(); + if (v.key() == kMapSize) pCSM->mMapSize = (uint2)v.val(); + else if (v.key() == kVisBufferSize) pCSM->mVisibilityPassData.screenDim = (uint2)v.val(); else if (v.key() == kCascadeCount) pCSM->setCascadeCount(v.val()); else if (v.key() == kVisMapBitsPerChannel) pCSM->setVisibilityBufferBitsPerChannel(v.val()); else if (v.key() == kSdsmReadbackLatency) pCSM->setSdsmReadbackLatency(v.val()); @@ -422,27 +422,27 @@ void CSM::compile(RenderContext* pContext, const CompileData& compileData) mVisibilityPass.pFbo->attachColorTarget(nullptr, 0); } -void camClipSpaceToWorldSpace(const Camera* pCamera, glm::vec3 viewFrustum[8], glm::vec3& center, float& radius) +void camClipSpaceToWorldSpace(const Camera* pCamera, float3 viewFrustum[8], float3& center, float& radius) { - glm::vec3 clipSpace[8] = + float3 clipSpace[8] = { - glm::vec3(-1.0f, 1.0f, 0), - glm::vec3(1.0f, 1.0f, 0), - glm::vec3(1.0f, -1.0f, 0), - glm::vec3(-1.0f, -1.0f, 0), - glm::vec3(-1.0f, 1.0f, 1.0f), - glm::vec3(1.0f, 1.0f, 1.0f), - glm::vec3(1.0f, -1.0f, 1.0f), - glm::vec3(-1.0f, -1.0f, 1.0f), + float3(-1.0f, 1.0f, 0), + float3(1.0f, 1.0f, 0), + float3(1.0f, -1.0f, 0), + float3(-1.0f, -1.0f, 0), + float3(-1.0f, 1.0f, 1.0f), + float3(1.0f, 1.0f, 1.0f), + float3(1.0f, -1.0f, 1.0f), + float3(-1.0f, -1.0f, 1.0f), }; glm::mat4 invViewProj = pCamera->getInvViewProjMatrix(); - center = glm::vec3(0, 0, 0); + center = float3(0, 0, 0); for (uint32_t i = 0; i < 8; i++) { - glm::vec4 crd = invViewProj * glm::vec4(clipSpace[i], 1); - viewFrustum[i] = glm::vec3(crd) / crd.w; + float4 crd = invViewProj * float4(clipSpace[i], 1); + viewFrustum[i] = float3(crd) / crd.w; center += viewFrustum[i]; } @@ -453,11 +453,11 @@ void camClipSpaceToWorldSpace(const Camera* pCamera, glm::vec3 viewFrustum[8], g for (uint32_t i = 0; i < 8; i++) { float d = glm::length(center - viewFrustum[i]); - radius = max(d, radius); + radius = std::max(d, radius); } } -forceinline float calcPssmPartitionEnd(float nearPlane, float camDepthRange, const glm::vec2& distanceRange, float linearBlend, uint32_t cascade, uint32_t cascadeCount) +forceinline float calcPssmPartitionEnd(float nearPlane, float camDepthRange, const float2& distanceRange, float linearBlend, uint32_t cascade, uint32_t cascadeCount) { // Convert to camera space float minDepth = nearPlane + distanceRange.x * camDepthRange; @@ -477,21 +477,21 @@ forceinline float calcPssmPartitionEnd(float nearPlane, float camDepthRange, con return distance; } -void getCascadeCropParams(const glm::vec3 crd[8], const glm::mat4& lightVP, glm::vec4& scale, glm::vec4& offset) +void getCascadeCropParams(const float3 crd[8], const glm::mat4& lightVP, float4& scale, float4& offset) { // Transform the frustum into light clip-space and calculate min-max - glm::vec4 maxCS(-1, -1, 0, 1); - glm::vec4 minCS(1, 1, 1, 1); + float4 maxCS(-1, -1, 0, 1); + float4 minCS(1, 1, 1, 1); for (uint32_t i = 0; i < 8; i++) { - glm::vec4 c = lightVP * glm::vec4(crd[i], 1.0f); + float4 c = lightVP * float4(crd[i], 1.0f); c /= c.w; - maxCS = max(maxCS, c); - minCS = min(minCS, c); + maxCS = glm::max(maxCS, c); + minCS = glm::min(minCS, c); } - glm::vec4 delta = maxCS - minCS; - scale = glm::vec4(2, 2, 1, 1) / delta; + float4 delta = maxCS - minCS; + scale = float4(2, 2, 1, 1) / delta; offset.x = -0.5f * (maxCS.x + minCS.x) * scale.x; offset.y = -0.5f * (maxCS.y + minCS.y) * scale.y; @@ -501,12 +501,12 @@ void getCascadeCropParams(const glm::vec3 crd[8], const glm::mat4& lightVP, glm: offset.w = 0; } -void CSM::partitionCascades(const Camera* pCamera, const glm::vec2& distanceRange) +void CSM::partitionCascades(const Camera* pCamera, const float2& distanceRange) { struct { - glm::vec3 crd[8]; - glm::vec3 center; + float3 crd[8]; + float3 center; float radius; } camFrustum; @@ -517,8 +517,8 @@ void CSM::partitionCascades(const Camera* pCamera, const glm::vec2& distanceRang if (mCsmData.cascadeCount == 1) { - mCsmData.cascadeScale[0] = glm::vec4(1); - mCsmData.cascadeOffset[0] = glm::vec4(0); + mCsmData.cascadeScale[0] = float4(1); + mCsmData.cascadeOffset[0] = float4(0); mCsmData.cascadeRange[0].x = 0; mCsmData.cascadeRange[0].y = 1; return; @@ -555,8 +555,8 @@ void CSM::partitionCascades(const Camera* pCamera, const glm::vec2& distanceRang nextCascadeStart -= blendCorrection; // Calculate the cascade distance in camera-clip space(Where the clip-space range is [0, farPlane]) - float camClipSpaceCascadeStart = lerp(nearPlane, farPlane, cascadeStart); - float camClipSpaceCascadeEnd = lerp(nearPlane, farPlane, cascadeEnd); + float camClipSpaceCascadeStart = glm::lerp(nearPlane, farPlane, cascadeStart); + float camClipSpaceCascadeEnd = glm::lerp(nearPlane, farPlane, cascadeEnd); //Convert to ndc space [0, 1] float projTermA = farPlane / (nearPlane - farPlane); @@ -567,12 +567,12 @@ void CSM::partitionCascades(const Camera* pCamera, const glm::vec2& distanceRang mCsmData.cascadeRange[c].y = ndcSpaceCascadeEnd - ndcSpaceCascadeStart; // Calculate the cascade frustum - glm::vec3 cascadeFrust[8]; + float3 cascadeFrust[8]; for (uint32_t i = 0; i < 4; i++) { - glm::vec3 edge = camFrustum.crd[i + 4] - camFrustum.crd[i]; - glm::vec3 start = edge * cascadeStart; - glm::vec3 end = edge * cascadeEnd; + float3 edge = camFrustum.crd[i + 4] - camFrustum.crd[i]; + float3 start = edge * cascadeStart; + float3 end = edge * cascadeEnd; cascadeFrust[i] = camFrustum.crd[i] + start; cascadeFrust[i + 4] = camFrustum.crd[i] + end; } @@ -633,7 +633,7 @@ void CSM::executeDepthPass(RenderContext* pCtx, const Camera* pCamera) mDepthPass.pState->setFbo(Fbo::create2D(width, height, desc)); } - pCtx->clearFbo(pFbo.get(), glm::vec4(), 1, 0, FboAttachmentType::Depth); + pCtx->clearFbo(pFbo.get(), float4(), 1, 0, FboAttachmentType::Depth); // mpCsmSceneRenderer->renderScene(pCtx, mDepthPass.pState.get(), mDepthPass.pVars.get(), pCamera); } @@ -656,25 +656,25 @@ void CSM::reduceDepthSdsmMinMax(RenderContext* pRenderCtx, const Camera* pCamera } createSdsmData(pDepthBuffer); - vec2 distanceRange = glm::vec2(mSdsmData.minMaxReduction->reduce(pRenderCtx, pDepthBuffer)); + float2 distanceRange = float2(mSdsmData.minMaxReduction->reduce(pRenderCtx, pDepthBuffer)); // Convert to linear glm::mat4 camProj = pCamera->getProjMatrix(); distanceRange = camProj[2][2] - distanceRange * camProj[2][3]; distanceRange = camProj[3][2] / distanceRange; distanceRange = (distanceRange - pCamera->getNearPlane()) / (pCamera->getFarPlane() - pCamera->getNearPlane()); - distanceRange = glm::clamp(distanceRange, glm::vec2(0), glm::vec2(1)); + distanceRange = glm::clamp(distanceRange, float2(0), float2(1)); mSdsmData.sdsmResult = distanceRange; if (mControls.stabilizeCascades) { // Ignore minor changes that can result in swimming distanceRange = round(distanceRange * 16.0f) / 16.0f; - distanceRange.y = max(distanceRange.y, 0.005f); + distanceRange.y = std::max(distanceRange.y, 0.005f); } } -vec2 CSM::calcDistanceRange(RenderContext* pRenderCtx, const Camera* pCamera, const Texture::SharedPtr& pDepthBuffer) +float2 CSM::calcDistanceRange(RenderContext* pRenderCtx, const Camera* pCamera, const Texture::SharedPtr& pDepthBuffer) { if (mControls.useMinMaxSdsm) { @@ -742,11 +742,11 @@ void CSM::execute(RenderContext* pContext, const RenderData& renderData) const auto pCamera = mpScene->getCamera().get(); //const auto pCamera = mpCsmSceneRenderer->getScene()->getActiveCamera().get(); - const glm::vec4 clearColor(0); + const float4 clearColor(0); pContext->clearFbo(mShadowPass.pFbo.get(), clearColor, 1, 0, FboAttachmentType::All); // Calc the bounds - glm::vec2 distanceRange = calcDistanceRange(pContext, pCamera, pDepth); + float2 distanceRange = calcDistanceRange(pContext, pCamera, pDepth); GraphicsState::Viewport VP; VP.originX = 0; @@ -771,7 +771,7 @@ void CSM::execute(RenderContext* pContext, const RenderData& renderData) } // Clear visibility buffer - pContext->clearFbo(mVisibilityPass.pFbo.get(), glm::vec4(1, 0, 0, 0), 1, 0, FboAttachmentType::All); + pContext->clearFbo(mVisibilityPass.pFbo.get(), float4(1, 0, 0, 0), 1, 0, FboAttachmentType::All); // Update Vars mVisibilityPass.pPass["gDepth"] = pDepth ? pDepth : mDepthPass.pState->getFbo()->getDepthStencilTexture(); @@ -780,7 +780,7 @@ void CSM::execute(RenderContext* pContext, const RenderData& renderData) auto visibilityVars = mVisibilityPass.pPass->getVars().getRootVar(); setDataIntoVars(visibilityVars, visibilityVars["PerFrameCB"]["gCsmData"]); mVisibilityPassData.camInvViewProj = pCamera->getInvViewProjMatrix(); - mVisibilityPassData.screenDim = glm::uvec2(mVisibilityPass.pFbo->getWidth(), mVisibilityPass.pFbo->getHeight()); + mVisibilityPassData.screenDim = uint2(mVisibilityPass.pFbo->getWidth(), mVisibilityPass.pFbo->getHeight()); mVisibilityPass.pPass["PerFrameCB"][mVisibilityPass.mPassDataOffset].setBlob(mVisibilityPassData); // Render visibility buffer @@ -841,7 +841,7 @@ void CSM::renderUI(Gui::Widgets& widget) } // Shadow-map size - ivec2 smDims = ivec2(mShadowPass.pFbo->getWidth(), mShadowPass.pFbo->getHeight()); + int2 smDims = int2(mShadowPass.pFbo->getWidth(), mShadowPass.pFbo->getHeight()); if (widget.var("Shadow-Map Size", smDims, 0, 8192)) resizeShadowMap(smDims); // Visibility buffer bits-per channel @@ -910,7 +910,7 @@ void CSM::renderUI(Gui::Widgets& widget) if ((CsmFilter)mCsmData.filterMode == CsmFilter::FixedPcf || (CsmFilter)mCsmData.filterMode == CsmFilter::StochasticPcf) { - i32 kernelWidth = mCsmData.pcfKernelWidth; + int32_t kernelWidth = mCsmData.pcfKernelWidth; if (widget.var("Kernel Width", kernelWidth, 1, 15, 2)) { setPcfKernelWidth(kernelWidth); @@ -1019,7 +1019,7 @@ void CSM::setVisibilityBufferBitsPerChannel(uint32_t bitsPerChannel) mPassChangedCB(); } -void CSM::resizeShadowMap(const uvec2& smDims) +void CSM::resizeShadowMap(const uint2& smDims) { mMapSize = smDims; createShadowPassResources(); diff --git a/Source/RenderPasses/CSM/CSM.h b/Source/RenderPasses/CSM/CSM.h index 24355e241..dbc558345 100644 --- a/Source/RenderPasses/CSM/CSM.h +++ b/Source/RenderPasses/CSM/CSM.h @@ -61,7 +61,7 @@ class CSM : public RenderPass, public inherit_shared_from_this // Scripting functions void setCascadeCount(uint32_t cascadeCount); - void setMapSize(const uvec2& size) { resizeShadowMap(size); } + void setMapSize(const uint2& size) { resizeShadowMap(size); } void setVisibilityBufferBitsPerChannel(uint32_t bitsPerChannel); void setFilterMode(uint32_t filterMode); void setSdsmReadbackLatency(uint32_t latency); @@ -70,14 +70,14 @@ class CSM : public RenderPass, public inherit_shared_from_this void setMinDistanceRange(float min) { mControls.distanceRange.x = glm::clamp(min, 0.f, 1.f); } void setMaxDistanceRange(float max) { mControls.distanceRange.y = glm::clamp(max, 0.f, 1.f); } void setCascadeBlendThreshold(float threshold) { mCsmData.cascadeBlendThreshold = glm::clamp(threshold, 0.f, 1.0f); } - void setDepthBias(float bias) { mCsmData.depthBias = max(0.f, bias); } + void setDepthBias(float bias) { mCsmData.depthBias = std::max(0.f, bias); } void setPcfKernelWidth(uint32_t width) { mCsmData.pcfKernelWidth = width | 1; } void setVsmMaxAnisotropy(uint32_t maxAniso) { createVsmSampleState(maxAniso); } void setVsmLightBleedReduction(float reduction) { mCsmData.lightBleedingReduction = glm::clamp(reduction, 0.f, 1.0f); } void setEvsmPositiveExponent(float exp) { mCsmData.evsmExponents.x = glm::clamp(exp, 0.f, 5.54f); } void setEvsmNegativeExponent(float exp) { mCsmData.evsmExponents.y = glm::clamp(exp, 0.f, 5.54f); } uint32_t getCascadeCount() { return mCsmData.cascadeCount; } - const uvec2& getMapSize() { return mMapSize; } + const uint2& getMapSize() { return mMapSize; } uint32_t getVisibilityBufferBitsPerChannel() { return mVisibilityPassData.mapBitsPerChannel; } uint32_t getFilterMode() { return (uint32_t)mCsmData.filterMode; } uint32_t getSdsmReadbackLatency() { return mSdsmData.readbackLatency; } @@ -95,7 +95,7 @@ class CSM : public RenderPass, public inherit_shared_from_this private: CSM(); - uvec2 mMapSize = uvec2(2048, 2048); + uint2 mMapSize = uint2(2048, 2048); Light::SharedConstPtr mpLight; Camera::SharedPtr mpLightCamera; //std::shared_ptr mpCsmSceneRenderer; @@ -107,8 +107,8 @@ class CSM : public RenderPass, public inherit_shared_from_this // Set shadow map generation parameters into a program. void setDataIntoVars(ShaderVar const& globalVars, ShaderVar const& csmDataVar); - vec2 calcDistanceRange(RenderContext* pRenderCtx, const Camera* pCamera, const Texture::SharedPtr& pDepthBuffer); - void partitionCascades(const Camera* pCamera, const glm::vec2& distanceRange); + float2 calcDistanceRange(RenderContext* pRenderCtx, const Camera* pCamera, const Texture::SharedPtr& pDepthBuffer); + void partitionCascades(const Camera* pCamera, const float2& distanceRange); void renderScene(RenderContext* pCtx); // Shadow-pass @@ -122,14 +122,14 @@ class CSM : public RenderPass, public inherit_shared_from_this GraphicsProgram::SharedPtr pProgram; GraphicsVars::SharedPtr pVars; GraphicsState::SharedPtr pState; - glm::vec2 mapSize; + float2 mapSize; } mShadowPass; // SDSM struct SdsmData { ParallelReduction::UniquePtr minMaxReduction; - vec2 sdsmResult; // Used for displaying the range in the UI + float2 sdsmResult; // Used for displaying the range in the UI uint32_t width = 0; uint32_t height = 0; uint32_t sampleCount = 0; @@ -166,7 +166,7 @@ class CSM : public RenderPass, public inherit_shared_from_this uint32_t shouldVisualizeCascades = 0u; int3 padding; glm::mat4 camInvViewProj; - glm::uvec2 screenDim = { 0, 0 }; + uint2 screenDim = { 0, 0 }; uint32_t mapBitsPerChannel = 32; } mVisibilityPassData; @@ -174,7 +174,7 @@ class CSM : public RenderPass, public inherit_shared_from_this { bool depthClamp = true; bool useMinMaxSdsm = true; - glm::vec2 distanceRange = glm::vec2(0, 1); + float2 distanceRange = float2(0, 1); float pssmLambda = 0.5f; PartitionMode partitionMode = PartitionMode::Logarithmic; bool stabilizeCascades = false; @@ -190,7 +190,7 @@ class CSM : public RenderPass, public inherit_shared_from_this void setupVisibilityPassFbo(const Texture::SharedPtr& pVisBuffer); ProgramReflection::BindLocation mPerLightCbLoc; - void resizeShadowMap(const uvec2& smDims); + void resizeShadowMap(const uint2& smDims); void setLight(const Light::SharedConstPtr& pLight); }; diff --git a/Source/RenderPasses/CSM/DepthPass.slang b/Source/RenderPasses/CSM/DepthPass.slang index a21dc2365..6e0fdc934 100644 --- a/Source/RenderPasses/CSM/DepthPass.slang +++ b/Source/RenderPasses/CSM/DepthPass.slang @@ -55,7 +55,7 @@ ShadowPassVSOut vsMain(VSIn vIn) { ShadowPassVSOut vOut; float4x4 worldMat = gScene.getWorldMatrix(vIn.meshInstanceID); - vOut.pos = mul(vIn.pos, worldMat); + vOut.pos = mul(float4(vIn.pos, 1.f), worldMat); #ifdef _APPLY_PROJECTION vOut.pos = mul(vOut.pos, gScene.camera.getViewProj()); #endif diff --git a/Source/RenderPasses/CSM/ShadowPass.slang b/Source/RenderPasses/CSM/ShadowPass.slang index c0c0d4204..881316aae 100644 --- a/Source/RenderPasses/CSM/ShadowPass.slang +++ b/Source/RenderPasses/CSM/ShadowPass.slang @@ -63,7 +63,7 @@ ShadowPassVSOut vsMain(VSIn vIn) { ShadowPassVSOut vOut; float4x4 worldMat = gScene.getWorldMatrix(vIn.meshInstanceID); - vOut.pos = mul(vIn.pos, worldMat); + vOut.pos = mul(float4(vIn.pos, 1.f), worldMat); #ifdef _APPLY_PROJECTION vOut.pos = mul(vOut.pos, gScene.camera.getViewProj()); #endif diff --git a/Source/RenderPasses/DebugPasses/ComparisonPass.cpp b/Source/RenderPasses/DebugPasses/ComparisonPass.cpp index 0a58574f7..6dd5baa36 100644 --- a/Source/RenderPasses/DebugPasses/ComparisonPass.cpp +++ b/Source/RenderPasses/DebugPasses/ComparisonPass.cpp @@ -112,12 +112,12 @@ void ComparisonPass::execute(RenderContext* pContext, const RenderData& renderDa // Draw text labeling the right side image std::string rightSide = mSwapSides ? mLeftLabel : mRightLabel; - TextRenderer::render(pContext, rightSide.c_str(), pDstFbo, vec2(screenLoc + 16, 16)); + TextRenderer::render(pContext, rightSide.c_str(), pDstFbo, float2(screenLoc + 16, 16)); // Draw text labeling the left side image std::string leftSide = mSwapSides ? mRightLabel : mLeftLabel; uint32_t leftLength = uint32_t(leftSide.length()) * 9; - TextRenderer::render(pContext, leftSide.c_str(), pDstFbo, vec2(screenLoc - 16 - leftLength, 16)); + TextRenderer::render(pContext, leftSide.c_str(), pDstFbo, float2(screenLoc - 16 - leftLength, 16)); } } diff --git a/Source/RenderPasses/DebugPasses/SplitScreenPass/SplitScreenPass.cpp b/Source/RenderPasses/DebugPasses/SplitScreenPass/SplitScreenPass.cpp index 26739c17d..df1dcb548 100644 --- a/Source/RenderPasses/DebugPasses/SplitScreenPass/SplitScreenPass.cpp +++ b/Source/RenderPasses/DebugPasses/SplitScreenPass/SplitScreenPass.cpp @@ -30,8 +30,8 @@ namespace { // Divider colors - const vec4 kColorUnselected = vec4(0, 0, 0, 1); - const vec4 kColorSelected = vec4(1, 1, 1, 1); + const float4 kColorUnselected = float4(0, 0, 0, 1); + const float4 kColorSelected = float4(1, 1, 1, 1); // A simple character array representing a 16x16 grayscale arrow const unsigned char kArrowArray[256] = { @@ -53,7 +53,7 @@ namespace 0, 0, 0, 0, 0, 0, 0, 0, 87, 12, 0, 0, 0, 0, 0, 0 }; - // Where is our shader located? + // Where is our shader located? const std::string kSplitShader = "RenderPasses/DebugPasses/SplitScreenPass/SplitScreen.ps.slang"; } @@ -99,10 +99,10 @@ bool SplitScreenPass::onMouseEvent(const MouseEvent& mouseEvent) bool handled = mDividerGrabbed; // Find out where on the screen we are - mMousePos = ivec2(mouseEvent.screenPos.x, mouseEvent.screenPos.y); + mMousePos = int2(mouseEvent.screenPos.x, mouseEvent.screenPos.y); // If we're outside the window, stop. - mMousePos = glm::clamp(mMousePos, ivec2(0, 0), ivec2(pDstFbo->getWidth() - 1, pDstFbo->getHeight() - 1)); + mMousePos = glm::clamp(mMousePos, int2(0, 0), int2(pDstFbo->getWidth() - 1, pDstFbo->getHeight() - 1)); // Actually process our events if (mMouseOverDivider && mouseEvent.type == MouseEvent::Type::LeftButtonDown) @@ -110,8 +110,8 @@ bool SplitScreenPass::onMouseEvent(const MouseEvent& mouseEvent) mDividerGrabbed = true; handled = true; - if (mClock.now() - mTimeOfLastClick < 0.1f) mSplitLoc = 0.5f; - else mTimeOfLastClick = mClock.now(); + if (mClock.getTime() - mTimeOfLastClick < 0.1f) mSplitLoc = 0.5f; + else mTimeOfLastClick = mClock.getTime(); } else if (mDividerGrabbed) { diff --git a/Source/RenderPasses/DebugPasses/SplitScreenPass/SplitScreenPass.h b/Source/RenderPasses/DebugPasses/SplitScreenPass/SplitScreenPass.h index df8a1686c..18e9fba4b 100644 --- a/Source/RenderPasses/DebugPasses/SplitScreenPass/SplitScreenPass.h +++ b/Source/RenderPasses/DebugPasses/SplitScreenPass/SplitScreenPass.h @@ -49,7 +49,7 @@ class SplitScreenPass : public ComparisonPass // Mouse parameters bool mMouseOverDivider = false; ///< Is the mouse over the divider? - ivec2 mMousePos = ivec2(0, 0); ///< Where was mouse in last mouse event processed + int2 mMousePos = int2(0, 0); ///< Where was mouse in last mouse event processed bool mDividerGrabbed = false; ///< Are we grabbing the divider? bool mDrawArrows = false; ///< When hovering over divider, show arrows? diff --git a/Source/RenderPasses/ErrorMeasurePass/ErrorMeasurePass.cpp b/Source/RenderPasses/ErrorMeasurePass/ErrorMeasurePass.cpp index 6e19183c8..72452abff 100644 --- a/Source/RenderPasses/ErrorMeasurePass/ErrorMeasurePass.cpp +++ b/Source/RenderPasses/ErrorMeasurePass/ErrorMeasurePass.cpp @@ -188,7 +188,7 @@ void ErrorMeasurePass::runDifferencePass(RenderContext* pRenderContext, const Re mpErrorMeasurerPass["gResult"] = mpDifferenceTexture; // Set constant buffer parameters. - const glm::uvec2 resolution = glm::uvec2(pSourceTexture->getWidth(), pSourceTexture->getHeight()); + const uint2 resolution = uint2(pSourceTexture->getWidth(), pSourceTexture->getHeight()); mpErrorMeasurerPass[kConstantBufferName]["gResolution"] = resolution; // If the world position texture is unbound, then don't do the background pixel check. mpErrorMeasurerPass[kConstantBufferName]["gIgnoreBackground"] = (uint32_t)(mIgnoreBackground && pWorldPositionTexture); @@ -200,7 +200,7 @@ void ErrorMeasurePass::runDifferencePass(RenderContext* pRenderContext, const Re void ErrorMeasurePass::runReductionPasses(RenderContext* pRenderContext, const RenderData& renderData) { - glm::vec4 error; + float4 error; if (!mpParallelReduction->execute(pRenderContext, mpDifferenceTexture, ComputeParallelReduction::Type::Sum, &error)) { throw std::exception("Error running parallel reduction in ErrorMeasurePass"); diff --git a/Source/RenderPasses/ForwardLightingPass/ForwardLightingPass.cpp b/Source/RenderPasses/ForwardLightingPass/ForwardLightingPass.cpp index 4648588d4..39017c7ba 100644 --- a/Source/RenderPasses/ForwardLightingPass/ForwardLightingPass.cpp +++ b/Source/RenderPasses/ForwardLightingPass/ForwardLightingPass.cpp @@ -154,7 +154,7 @@ void ForwardLightingPass::initFbo(RenderContext* pContext, const RenderData& ren for (uint32_t i = 1; i < 3; i++) { const auto& pRtv = mpFbo->getRenderTargetView(i).get(); - if (pRtv->getResource() != nullptr) pContext->clearRtv(pRtv, vec4(0)); + if (pRtv->getResource() != nullptr) pContext->clearRtv(pRtv, float4(0)); } // TODO Matt (not really matt, just need to fix that since if depth is not bound the pass crashes @@ -168,7 +168,7 @@ void ForwardLightingPass::execute(RenderContext* pContext, const RenderData& ren if (mpScene) { - mpVars["PerFrameCB"]["gRenderTargetDim"] = vec2(mpFbo->getWidth(), mpFbo->getHeight()); + mpVars["PerFrameCB"]["gRenderTargetDim"] = float2(mpFbo->getWidth(), mpFbo->getHeight()); mpVars->setTexture(kVisBuffer, renderData[kVisBuffer]->asTexture()); mpState->setFbo(mpFbo); diff --git a/Source/RenderPasses/GBuffer/GBuffer/GBufferRT.cpp b/Source/RenderPasses/GBuffer/GBuffer/GBufferRT.cpp index 0959d3613..8acd83bc7 100644 --- a/Source/RenderPasses/GBuffer/GBuffer/GBufferRT.cpp +++ b/Source/RenderPasses/GBuffer/GBuffer/GBufferRT.cpp @@ -26,7 +26,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ #include "Falcor.h" -#include "RenderPasses/Shared/HitInfo.h" #include "RenderGraph/RenderPassStandardFlags.h" #include "GBufferRT.h" @@ -133,7 +132,6 @@ void GBufferRT::setScene(RenderContext* pRenderContext, const Scene::SharedPtr& if (pScene) { mRaytrace.pProgram->addDefines(pScene->getSceneDefines()); - mRaytrace.pProgram->addDefines(HitInfo::getDefines(pScene)); } } @@ -154,7 +152,7 @@ void GBufferRT::execute(RenderContext* pRenderContext, const RenderData& renderD auto clear = [&](const ChannelDesc& channel) { auto pTex = renderData[channel.name]->asTexture(); - if (pTex) pRenderContext->clearUAV(pTex->getUAV().get(), glm::vec4(0.f)); + if (pTex) pRenderContext->clearUAV(pTex->getUAV().get(), float4(0.f)); }; for (const auto& channel : kGBufferChannels) clear(channel); for (const auto& channel : kGBufferExtraChannels) clear(channel); @@ -204,14 +202,14 @@ void GBufferRT::execute(RenderContext* pRenderContext, const RenderData& renderD auto bind = [&](const ChannelDesc& channel) { Texture::SharedPtr pTex = renderData[channel.name]->asTexture(); - if (pTex) pRenderContext->clearUAV(pTex->getUAV().get(), glm::vec4(0, 0, 0, 0)); + if (pTex) pRenderContext->clearUAV(pTex->getUAV().get(), float4(0, 0, 0, 0)); pGlobalVars[channel.texname] = pTex; }; for (const auto& channel : kGBufferChannels) bind(channel); for (const auto& channel : kGBufferExtraChannels) bind(channel); // Launch the rays. - uvec3 targetDim = uvec3((int)mGBufferParams.frameSize.x, (int)mGBufferParams.frameSize.y, 1u); + uint3 targetDim = uint3((int)mGBufferParams.frameSize.x, (int)mGBufferParams.frameSize.y, 1u); mpScene->raytrace(pRenderContext, mRaytrace.pProgram.get(), mRaytrace.pVars, targetDim); mGBufferParams.frameCount++; diff --git a/Source/RenderPasses/GBuffer/GBuffer/GBufferRT.rt.slang b/Source/RenderPasses/GBuffer/GBuffer/GBufferRT.rt.slang index 0274f65ad..ebb14f124 100644 --- a/Source/RenderPasses/GBuffer/GBuffer/GBufferRT.rt.slang +++ b/Source/RenderPasses/GBuffer/GBuffer/GBufferRT.rt.slang @@ -26,8 +26,8 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ import Scene.Raytracing; +import Scene.HitInfo; import Utils.Sampling.SampleGenerator; -import RenderPasses.Shared.HitInfo; import GBufferHelpers; // GBuffer channels diff --git a/Source/RenderPasses/GBuffer/GBuffer/GBufferRaster.3d.slang b/Source/RenderPasses/GBuffer/GBuffer/GBufferRaster.3d.slang index d8877d032..5784b2c60 100644 --- a/Source/RenderPasses/GBuffer/GBuffer/GBufferRaster.3d.slang +++ b/Source/RenderPasses/GBuffer/GBuffer/GBufferRaster.3d.slang @@ -28,16 +28,21 @@ #include "Scene/VertexAttrib.slangh" import Scene.Raster; -import RenderPasses.Shared.HitInfo; +import Scene.HitInfo; import Utils.Helpers; import GBufferHelpers; +import Experimental.Scene.Material.TexLODHelpers; // UAV output channels -RWTexture2D gVBuffer; +RWTexture2D gVBuffer; RWTexture2D gMotionVectors; RWTexture2D gFaceNormalW; RWTexture2D gPosNormalFwidth; RWTexture2D gLinearZAndDeriv; +RWTexture2D gSurfaceSpreadAngle; +RWTexture2D gRayDifferentialX; +RWTexture2D gRayDifferentialY; +RWTexture2D gRayDifferentialZ; #define isValid(name) (is_valid_##name != 0) @@ -136,5 +141,32 @@ GBufferPSOut psMain(VSOut vsOut, uint triangleIndex : SV_PrimitiveID, float3 bar gVBuffer[ipos] = hit.encode(); } + // Store surface spread angle for texture LOD using ray cones. + if (isValid(gSurfaceSpreadAngle)) + { + gSurfaceSpreadAngle[ipos] = computeScreenSpaceSurfaceSpreadAngle(sd.posW, sd.N); + } + + if (isValid(gRayDifferentialX) && isValid(gRayDifferentialY) && isValid(gRayDifferentialZ)) + { + const float3 dOdx = ddx(sd.posW); + const float3 dOdy = ddy(sd.posW); + const float3 dNdx = ddx(sd.N); + const float3 dNdy = ddy(sd.N); + const float3 Nx = normalize(sd.N + dNdx); + const float3 Ny = normalize(sd.N + dNdy); + const float3 tmp = sd.posW - gScene.camera.getPosition(); + const float3 Dx = normalize(tmp + dOdx); + const float3 Dy = normalize(tmp + dOdy); + const float3 R = reflect(-sd.V, sd.N); + const float3 dRdx = reflect(Dx, Nx) - R; + const float3 dRdy = reflect(Dy, Ny) - R; + + gRayDifferentialX[ipos] = float4(dOdx.x, dOdy.x, dRdx.x, dRdy.x); + gRayDifferentialY[ipos] = float4(dOdx.y, dOdy.y, dRdx.y, dRdy.y); + gRayDifferentialZ[ipos] = float4(dOdx.z, dOdy.z, dRdx.z, dRdy.z); + } + + return psOut; } diff --git a/Source/RenderPasses/GBuffer/GBuffer/GBufferRaster.cpp b/Source/RenderPasses/GBuffer/GBuffer/GBufferRaster.cpp index b08ae604e..c7793f62c 100644 --- a/Source/RenderPasses/GBuffer/GBuffer/GBufferRaster.cpp +++ b/Source/RenderPasses/GBuffer/GBuffer/GBufferRaster.cpp @@ -26,7 +26,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ #include "Falcor.h" -#include "RenderPasses/Shared/HitInfo.h" #include "RenderGraph/RenderPassStandardFlags.h" #include "GBufferRaster.h" #include "../RenderPasses/DepthPass/DepthPass.h" @@ -42,11 +41,15 @@ namespace // TODO: Some are RG32 floats now. I'm sure that all of these could be fp16. const ChannelList kGBufferExtraChannels = { - { "vbuffer", "gVBuffer", "Visibility buffer", true /* optional */, ResourceFormat::RG32Uint }, - { "mvec", "gMotionVectors", "Motion vectors", true /* optional */, ResourceFormat::RG32Float }, - { "faceNormalW", "gFaceNormalW", "Face normal in world space", true /* optional */, ResourceFormat::RGBA32Float }, - { "pnFwidth", "gPosNormalFwidth", "position and normal filter width", true /* optional */, ResourceFormat::RG32Float }, - { "linearZ", "gLinearZAndDeriv", "linear z (and derivative)", true /* optional */, ResourceFormat::RG32Float }, + { "vbuffer", "gVBuffer", "Visibility buffer", true /* optional */, ResourceFormat::RG32Uint }, + { "mvec", "gMotionVectors", "Motion vectors", true /* optional */, ResourceFormat::RG32Float }, + { "faceNormalW", "gFaceNormalW", "Face normal in world space", true /* optional */, ResourceFormat::RGBA32Float }, + { "pnFwidth", "gPosNormalFwidth", "position and normal filter width", true /* optional */, ResourceFormat::RG32Float }, + { "linearZ", "gLinearZAndDeriv", "linear z (and derivative)", true /* optional */, ResourceFormat::RG32Float }, + { "surfSpreadAngle", "gSurfaceSpreadAngle", "surface spread angle (texlod)", true /* optional */, ResourceFormat::R32Float }, + { "rayDifferentialX", "gRayDifferentialX", "ray differental X", true /* optional */, ResourceFormat::RGBA32Float }, + { "rayDifferentialY", "gRayDifferentialY", "ray differental Y", true /* optional */, ResourceFormat::RGBA32Float }, + { "rayDifferentialZ", "gRayDifferentialZ", "ray differental Z", true /* optional */, ResourceFormat::RGBA32Float }, }; const std::string kDepthName = "depth"; @@ -126,7 +129,6 @@ void GBufferRaster::setScene(RenderContext* pRenderContext, const Scene::SharedP } mRaster.pProgram->addDefines(pScene->getSceneDefines()); - mRaster.pProgram->addDefines(HitInfo::getDefines(pScene)); } if (mpDepthPrePassGraph) mpDepthPrePassGraph->setScene(pScene); @@ -158,7 +160,7 @@ void GBufferRaster::execute(RenderContext* pRenderContext, const RenderData& ren Texture::SharedPtr pTex = renderData[kGBufferChannels[i].name]->asTexture(); mpFbo->attachColorTarget(pTex, uint32_t(i)); } - pRenderContext->clearFbo(mpFbo.get(), vec4(0), 1.f, 0, FboAttachmentType::Color); + pRenderContext->clearFbo(mpFbo.get(), float4(0), 1.f, 0, FboAttachmentType::Color); // If there is no scene, clear the outputs and return. if (mpScene == nullptr) @@ -166,7 +168,7 @@ void GBufferRaster::execute(RenderContext* pRenderContext, const RenderData& ren auto clear = [&](const ChannelDesc& channel) { auto pTex = renderData[channel.name]->asTexture(); - if (pTex) pRenderContext->clearUAV(pTex->getUAV().get(), glm::vec4(0.f)); + if (pTex) pRenderContext->clearUAV(pTex->getUAV().get(), float4(0.f)); }; for (const auto& channel : kGBufferExtraChannels) clear(channel); auto pDepth = renderData[kDepthName]->asTexture(); @@ -197,7 +199,7 @@ void GBufferRaster::execute(RenderContext* pRenderContext, const RenderData& ren for (const auto& channel : kGBufferExtraChannels) { Texture::SharedPtr pTex = renderData[channel.name]->asTexture(); - if (pTex) pRenderContext->clearUAV(pTex->getUAV().get(), glm::vec4(0, 0, 0, 0)); + if (pTex) pRenderContext->clearUAV(pTex->getUAV().get(), float4(0, 0, 0, 0)); mRaster.pVars[channel.texname] = pTex; } diff --git a/Source/RenderPasses/GBuffer/GBufferBase.cpp b/Source/RenderPasses/GBuffer/GBufferBase.cpp index 5e735840b..b08590142 100644 --- a/Source/RenderPasses/GBuffer/GBufferBase.cpp +++ b/Source/RenderPasses/GBuffer/GBufferBase.cpp @@ -118,7 +118,7 @@ void GBufferBase::renderUI(Gui::Widgets& widget) void GBufferBase::compile(RenderContext* pContext, const CompileData& compileData) { mFrameDim = compileData.defaultTexDims; - mInvFrameDim = 1.f / glm::vec2(mFrameDim); + mInvFrameDim = 1.f / float2(mFrameDim); if (mpScene) { diff --git a/Source/RenderPasses/GBuffer/GBufferBase.h b/Source/RenderPasses/GBuffer/GBufferBase.h index b4f671678..67e027176 100644 --- a/Source/RenderPasses/GBuffer/GBufferBase.h +++ b/Source/RenderPasses/GBuffer/GBufferBase.h @@ -58,8 +58,8 @@ class GBufferBase : public RenderPass, public inherit_shared_from_thisaddDefines(pScene->getSceneDefines()); - mRaytrace.pProgram->addDefines(HitInfo::getDefines(pScene)); } } @@ -104,7 +102,7 @@ void VBufferRT::execute(RenderContext* pRenderContext, const RenderData& renderD if (mpScene == nullptr) { auto pOutput = renderData[kOutputName]->asTexture(); - pRenderContext->clearUAV(pOutput->getUAV().get(), glm::uvec4(kInvalidIndex)); + pRenderContext->clearUAV(pOutput->getUAV().get(), uint4(kInvalidIndex)); return; } @@ -133,5 +131,5 @@ void VBufferRT::execute(RenderContext* pRenderContext, const RenderData& renderD var["gVBuffer"] = renderData[kOutputName]->asTexture(); // Dispatch the rays. - mpScene->raytrace(pRenderContext, mRaytrace.pProgram.get(), mRaytrace.pVars, uvec3(mFrameDim, 1)); + mpScene->raytrace(pRenderContext, mRaytrace.pProgram.get(), mRaytrace.pVars, uint3(mFrameDim, 1)); } diff --git a/Source/RenderPasses/GBuffer/VBuffer/VBufferRT.rt.slang b/Source/RenderPasses/GBuffer/VBuffer/VBufferRT.rt.slang index 6d7e32e6c..32c980521 100644 --- a/Source/RenderPasses/GBuffer/VBuffer/VBufferRT.rt.slang +++ b/Source/RenderPasses/GBuffer/VBuffer/VBufferRT.rt.slang @@ -26,8 +26,8 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ import Scene.Raytracing; +import Scene.HitInfo; import Utils.Sampling.SampleGenerator; -import RenderPasses.Shared.HitInfo; cbuffer PerFrameCB { diff --git a/Source/RenderPasses/GBuffer/VBuffer/VBufferRaster.3d.slang b/Source/RenderPasses/GBuffer/VBuffer/VBufferRaster.3d.slang index f234492f7..c1de70327 100644 --- a/Source/RenderPasses/GBuffer/VBuffer/VBufferRaster.3d.slang +++ b/Source/RenderPasses/GBuffer/VBuffer/VBufferRaster.3d.slang @@ -26,7 +26,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ import Scene.Raster; -import RenderPasses.Shared.HitInfo; +import Scene.HitInfo; struct VBufferPSOut { @@ -49,7 +49,7 @@ VBufferVSOut vsMain(VSIn vsIn) VBufferVSOut vsOut; float4x4 worldMat = gScene.getWorldMatrix(vsIn.meshInstanceID); - float4 posW = mul(vsIn.pos, worldMat); + float4 posW = mul(float4(vsIn.pos, 1.f), worldMat); vsOut.posH = mul(posW, gScene.camera.getViewProj()); vsOut.texC = vsIn.texC; diff --git a/Source/RenderPasses/GBuffer/VBuffer/VBufferRaster.cpp b/Source/RenderPasses/GBuffer/VBuffer/VBufferRaster.cpp index f34d32462..647a6f457 100644 --- a/Source/RenderPasses/GBuffer/VBuffer/VBufferRaster.cpp +++ b/Source/RenderPasses/GBuffer/VBuffer/VBufferRaster.cpp @@ -26,7 +26,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ #include "VBufferRaster.h" -#include "RenderPasses/Shared/HitInfo.h" #include "RenderGraph/RenderPassStandardFlags.h" const char* VBufferRaster::kDesc = "Rasterized V-buffer generation pass"; @@ -95,7 +94,6 @@ void VBufferRaster::setScene(RenderContext* pRenderContext, const Scene::SharedP } mRaster.pProgram->addDefines(pScene->getSceneDefines()); - mRaster.pProgram->addDefines(HitInfo::getDefines(pScene)); } } @@ -113,7 +111,7 @@ void VBufferRaster::execute(RenderContext* pRenderContext, const RenderData& ren // Clear depth and output buffer. auto pDepth = renderData[kDepthName]->asTexture(); auto pOutput = renderData[kOutputName]->asTexture(); - pRenderContext->clearUAV(pOutput->getUAV().get(), glm::uvec4(kInvalidIndex)); // Clear as UAV for integer clear value + pRenderContext->clearUAV(pOutput->getUAV().get(), uint4(kInvalidIndex)); // Clear as UAV for integer clear value pRenderContext->clearDsv(pDepth->getDSV().get(), 1.f, 0); // If there is no scene, we're done. diff --git a/Source/RenderPasses/ImageLoader/ImageLoader.cpp b/Source/RenderPasses/ImageLoader/ImageLoader.cpp index 122d0bd77..95cb4cd67 100644 --- a/Source/RenderPasses/ImageLoader/ImageLoader.cpp +++ b/Source/RenderPasses/ImageLoader/ImageLoader.cpp @@ -104,7 +104,7 @@ void ImageLoader::execute(RenderContext* pContext, const RenderData& renderData) const auto& pDstTex = renderData[kDst]->asTexture(); if (!mpTex) { - pContext->clearRtv(pDstTex->getRTV().get(), glm::vec4(0, 0, 0, 0)); + pContext->clearRtv(pDstTex->getRTV().get(), float4(0, 0, 0, 0)); return; } pContext->blit(mpTex->getSRV(mMipLevel, 1, mArraySlice, 1), pDstTex->getRTV()); diff --git a/Source/RenderPasses/MegakernelPathTracer/MegakernelPathTracer.cpp b/Source/RenderPasses/MegakernelPathTracer/MegakernelPathTracer.cpp index 3d7978597..f0b574f27 100644 --- a/Source/RenderPasses/MegakernelPathTracer/MegakernelPathTracer.cpp +++ b/Source/RenderPasses/MegakernelPathTracer/MegakernelPathTracer.cpp @@ -26,7 +26,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ #include "MegakernelPathTracer.h" -#include "RenderPasses/Shared/HitInfo.h" #include "RenderGraph/RenderPassHelpers.h" #include @@ -94,7 +93,6 @@ void MegakernelPathTracer::setScene(RenderContext* pRenderContext, const Scene:: if (pScene) { mTracer.pProgram->addDefines(pScene->getSceneDefines()); - mTracer.pProgram->addDefines(HitInfo::getDefines(pScene)); } } @@ -140,7 +138,7 @@ void MegakernelPathTracer::execute(RenderContext* pRenderContext, const RenderDa for (auto channel : mOutputChannels) bind(channel); // Get dimensions of ray dispatch. - const uvec2 targetDim = renderData.getDefaultTextureDims(); + const uint2 targetDim = renderData.getDefaultTextureDims(); assert(targetDim.x > 0 && targetDim.y > 0); mpPixelDebug->prepareProgram(pProgram, mTracer.pVars->getRootVar()); @@ -149,7 +147,7 @@ void MegakernelPathTracer::execute(RenderContext* pRenderContext, const RenderDa // Spawn the rays. { PROFILE("MegakernelPathTracer::execute()_RayTrace"); - mpScene->raytrace(pRenderContext, mTracer.pProgram.get(), mTracer.pVars, uvec3(targetDim, 1)); + mpScene->raytrace(pRenderContext, mTracer.pProgram.get(), mTracer.pVars, uint3(targetDim, 1)); } // Call shared post-render code. diff --git a/Source/RenderPasses/MegakernelPathTracer/PathTracer.slang b/Source/RenderPasses/MegakernelPathTracer/PathTracer.slang index 37c84e629..353248ab9 100644 --- a/Source/RenderPasses/MegakernelPathTracer/PathTracer.slang +++ b/Source/RenderPasses/MegakernelPathTracer/PathTracer.slang @@ -38,7 +38,7 @@ __exported import Scene.Scene; __exported import Scene.Raytracing; -__exported import RenderPasses.Shared.HitInfo; +__exported import Scene.HitInfo; __exported import RenderPasses.Shared.PathTracer.PixelStats; __exported import RenderPasses.Shared.PathTracer.PathTracerHelpers; __exported import RenderPasses.Shared.PathTracer.InteriorListHelpers; @@ -150,8 +150,7 @@ void handleHit(const PathTracerData pt, inout ShadingData sd, inout PathData pat { // Evaluate Falcor's material parameters at the hit point. // TODO: Implement texLOD to enable texture filtering in prepareShadingData(). - float3 barycentrics = float3(1.f - path.hit.barycentrics.x - path.hit.barycentrics.y, path.hit.barycentrics.x, path.hit.barycentrics.y); - VertexData v = gScene.getVertexData(path.hit.meshInstanceID, path.hit.primitiveIndex, barycentrics); + VertexData v = gScene.getVertexData(path.hit); const uint materialID = gScene.getMaterialID(path.hit.meshInstanceID); sd = prepareShadingData(v, materialID, gScene.materials[materialID], gScene.materialResources[materialID], -path.dir, 0.f); diff --git a/Source/RenderPasses/MinimalPathTracer/Data/MinimalPathTracer.py b/Source/RenderPasses/MinimalPathTracer/Data/MinimalPathTracer.py new file mode 100644 index 000000000..ad68d6d6f --- /dev/null +++ b/Source/RenderPasses/MinimalPathTracer/Data/MinimalPathTracer.py @@ -0,0 +1,33 @@ +from falcor import * + +def render_graph_MinimalPathTracer(): + g = RenderGraph("MinimalPathTracer") + loadRenderPassLibrary("AccumulatePass.dll") + loadRenderPassLibrary("GBuffer.dll") + loadRenderPassLibrary("MinimalPathTracer.dll") + loadRenderPassLibrary("ToneMapper.dll") + AccumulatePass = RenderPass("AccumulatePass", {'enableAccumulation': True, 'precisionMode': AccumulatePrecision.Single}) + g.addPass(AccumulatePass, "AccumulatePass") + ToneMapper = RenderPass("ToneMapper", {'autoExposure': False, 'exposureValue': 0.0}) + g.addPass(ToneMapper, "ToneMapper") + MinimalPathTracer = RenderPass("MinimalPathTracer", {'mMaxBounces': 3, 'mComputeDirect': True, 'mUseAnalyticLights': 1, 'mUseEmissiveLights': 1, 'mUseEnvLight': 1, 'mUseEnvBackground': 1}) + g.addPass(MinimalPathTracer, "MinimalPathTracer") + GBufferRT = RenderPass("GBufferRT", {'samplePattern': SamplePattern.Stratified, 'sampleCount': 16}) + g.addPass(GBufferRT, "GBufferRT") + g.addEdge("AccumulatePass.output", "ToneMapper.src") + g.addEdge("GBufferRT.posW", "MinimalPathTracer.posW") + g.addEdge("GBufferRT.normW", "MinimalPathTracer.normalW") + g.addEdge("GBufferRT.bitangentW", "MinimalPathTracer.bitangentW") + g.addEdge("GBufferRT.faceNormalW", "MinimalPathTracer.faceNormalW") + g.addEdge("GBufferRT.viewW", "MinimalPathTracer.viewW") + g.addEdge("GBufferRT.diffuseOpacity", "MinimalPathTracer.mtlDiffOpacity") + g.addEdge("GBufferRT.specRough", "MinimalPathTracer.mtlSpecRough") + g.addEdge("GBufferRT.emissive", "MinimalPathTracer.mtlEmissive") + g.addEdge("GBufferRT.matlExtra", "MinimalPathTracer.mtlParams") + g.addEdge("MinimalPathTracer.color", "AccumulatePass.input") + g.markOutput("ToneMapper.dst") + return g + +MinimalPathTracer = render_graph_MinimalPathTracer() +try: m.addGraph(MinimalPathTracer) +except NameError: None diff --git a/Source/RenderPasses/MinimalPathTracer/MinimalPathTracer.cpp b/Source/RenderPasses/MinimalPathTracer/MinimalPathTracer.cpp index 9a8b4afa3..800d8c08e 100644 --- a/Source/RenderPasses/MinimalPathTracer/MinimalPathTracer.cpp +++ b/Source/RenderPasses/MinimalPathTracer/MinimalPathTracer.cpp @@ -178,11 +178,11 @@ void MinimalPathTracer::execute(RenderContext* pRenderContext, const RenderData& for (auto channel : kOutputChannels) bind(channel); // Get dimensions of ray dispatch. - const uvec2 targetDim = renderData.getDefaultTextureDims(); + const uint2 targetDim = renderData.getDefaultTextureDims(); assert(targetDim.x > 0 && targetDim.y > 0); // Spawn the rays. - mpScene->raytrace(pRenderContext, mTracer.pProgram.get(), mTracer.pVars, uvec3(targetDim, 1)); + mpScene->raytrace(pRenderContext, mTracer.pProgram.get(), mTracer.pVars, uint3(targetDim, 1)); mFrameCount++; } @@ -238,14 +238,12 @@ void MinimalPathTracer::setScene(RenderContext* pRenderContext, const Scene::Sha mTracer.pProgram->addDefines(pScene->getSceneDefines()); // Load environment map if scene uses one. - // We're getting the file name from the scene's LightProbe because that was used in the fscene files. - // TODO: Switch to use Scene::getEnvironmentMap() when the assets have been updated. - auto pLightProbe = mpScene->getLightProbe(); - if (pLightProbe != nullptr) + Texture::SharedPtr pEnvMap = mpScene->getEnvironmentMap(); + if (pEnvMap != nullptr) { - std::string fn = pLightProbe->getOrigTexture()->getSourceFilename(); - mpEnvProbe = EnvProbe::create(pRenderContext, fn); - mEnvProbeFilename = mpEnvProbe ? getFilenameFromPath(mpEnvProbe->getEnvMap()->getSourceFilename()) : ""; + std::string filename = pEnvMap->getSourceFilename(); + mpEnvProbe = EnvProbe::create(pRenderContext, filename); + mEnvProbeFilename = mpEnvProbe ? getFilenameFromPath(filename) : ""; } } } diff --git a/Source/RenderPasses/PixelInspectorPass/PixelInspectorPass.cpp b/Source/RenderPasses/PixelInspectorPass/PixelInspectorPass.cpp index fa2ac639c..09089ba79 100644 --- a/Source/RenderPasses/PixelInspectorPass/PixelInspectorPass.cpp +++ b/Source/RenderPasses/PixelInspectorPass/PixelInspectorPass.cpp @@ -125,8 +125,8 @@ void PixelInspectorPass::execute(RenderContext* pRenderContext, const RenderData } const float2 cursorPosition = mUseContinuousPicking ? mCursorPosition : mSelectedCursorPosition; - const uvec2 resolution = renderData.getDefaultTextureDims(); - mSelectedPixel = glm::min((uvec2)(cursorPosition * ((float2)resolution)), resolution - 1u); + const uint2 resolution = renderData.getDefaultTextureDims(); + mSelectedPixel = glm::min((uint2)(cursorPosition * ((float2)resolution)), resolution - 1u); // Fill in the constant buffer. mpVars["PerFrameCB"]["gResolution"] = resolution; @@ -141,9 +141,9 @@ void PixelInspectorPass::execute(RenderContext* pRenderContext, const RenderData mpVars[it.texname] = pSrc; // If the texture has a different resolution, we need to scale the sampling coordinates accordingly. - const uvec2 srcResolution = uvec2(pSrc->getWidth(), pSrc->getHeight()); + const uint2 srcResolution = uint2(pSrc->getWidth(), pSrc->getHeight()); const bool needsScaling = mScaleInputsToWindow && srcResolution != resolution; - const uvec2 scaledCoord = (uvec2)(((float2)(srcResolution * mSelectedPixel)) / ((float2)resolution)); + const uint2 scaledCoord = (uint2)(((float2)(srcResolution * mSelectedPixel)) / ((float2)resolution)); mpVars["PerFrameCB"][std::string(it.texname) + "Coord"] = needsScaling ? scaledCoord : mSelectedPixel; mIsInputInBounds[it.name] = glm::all(glm::lessThanEqual(mSelectedPixel, srcResolution)); diff --git a/Source/RenderPasses/PixelInspectorPass/PixelInspectorPass.h b/Source/RenderPasses/PixelInspectorPass/PixelInspectorPass.h index c98236b5a..bc64a7f5a 100644 --- a/Source/RenderPasses/PixelInspectorPass/PixelInspectorPass.h +++ b/Source/RenderPasses/PixelInspectorPass/PixelInspectorPass.h @@ -65,7 +65,7 @@ class PixelInspectorPass : public RenderPass, public inherit_shared_from_this mIsInputInBounds; // UI variables - uvec2 mSelectedPixel = uvec2(0u); + uint2 mSelectedPixel = uint2(0u); bool mScaleInputsToWindow = false; bool mUseContinuousPicking = false; }; diff --git a/Source/RenderPasses/SSAO/SSAO.cpp b/Source/RenderPasses/SSAO/SSAO.cpp index d6548d721..00874c74d 100644 --- a/Source/RenderPasses/SSAO/SSAO.cpp +++ b/Source/RenderPasses/SSAO/SSAO.cpp @@ -105,9 +105,9 @@ SSAO::SharedPtr SSAO::create(RenderContext* pRenderContext, const Dictionary& di Dictionary blurDict; for (const auto& v : dict) { - if (v.key() == kAoMapSize) pSSAO->mAoMapSize = (uvec2)v.val(); + if (v.key() == kAoMapSize) pSSAO->mAoMapSize = (uint2)v.val(); else if (v.key() == kKernelSize) pSSAO->mData.kernelSize = v.val(); - else if (v.key() == kNoiseSize) pSSAO->mNoiseSize = (uvec2)v.val(); + else if (v.key() == kNoiseSize) pSSAO->mNoiseSize = (uint2)v.val(); else if (v.key() == kDistribution) pSSAO->mHemisphereDistribution = (SampleDistribution)v.val(); else if (v.key() == kRadius) pSSAO->mData.radius = v.val(); else if (v.key() == kBlurKernelWidth) pSSAO->mBlurDict["kernelWidth"] = (uint32_t)v.val(); @@ -258,11 +258,11 @@ void SSAO::setKernel() for (uint32_t i = 0; i < mData.kernelSize; i++) { // Hemisphere in the Z+ direction - glm::vec3 p; + float3 p; switch (mHemisphereDistribution) { case SampleDistribution::Random: - p = glm::normalize(glm::linearRand(glm::vec3(-1.0f, -1.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f))); + p = glm::normalize(glm::linearRand(float3(-1.0f, -1.0f, 0.0f), float3(1.0f, 1.0f, 1.0f))); break; case SampleDistribution::UniformHammersley: @@ -274,7 +274,7 @@ void SSAO::setKernel() break; } - mData.sampleKernel[i] = glm::vec4(p, 0.0f); + mData.sampleKernel[i] = float4(p, 0.0f); // Skew sample point distance on a curve so more cluster around the origin float dist = (float)i / (float)mData.kernelSize; @@ -293,13 +293,13 @@ void SSAO::setNoiseTexture(uint32_t width, uint32_t height) for (uint32_t i = 0; i < width * height; i++) { // Random directions on the XY plane - glm::vec2 dir = glm::normalize(glm::linearRand(glm::vec2(-1), glm::vec2(1))) * 0.5f + 0.5f; - data[i] = glm::packUnorm4x8(glm::vec4(dir, 0.0f, 1.0f)); + float2 dir = glm::normalize(glm::linearRand(float2(-1), float2(1))) * 0.5f + 0.5f; + data[i] = glm::packUnorm4x8(float4(dir, 0.0f, 1.0f)); } mpNoiseTexture = Texture::create2D(width, height, ResourceFormat::RGBA8Unorm, 1, Texture::kMaxPossible, data.data()); - mData.noiseScale = glm::vec2(mpAOFbo->getWidth(), mpAOFbo->getHeight()) / glm::vec2(width, height); + mData.noiseScale = float2(mpAOFbo->getWidth(), mpAOFbo->getHeight()) / float2(width, height); mDirty = true; } diff --git a/Source/RenderPasses/SSAO/SSAO.h b/Source/RenderPasses/SSAO/SSAO.h index 39ac32eec..e8df6f8d3 100644 --- a/Source/RenderPasses/SSAO/SSAO.h +++ b/Source/RenderPasses/SSAO/SSAO.h @@ -74,11 +74,11 @@ class SSAO : public RenderPass, public inherit_shared_from_thisclearFbo(mpPingPongFbo[0].get(), glm::vec4(0), 1.0f, 0, FboAttachmentType::All); - pRenderContext->clearFbo(mpPingPongFbo[1].get(), glm::vec4(0), 1.0f, 0, FboAttachmentType::All); - pRenderContext->clearFbo(mpLinearZAndNormalFbo.get(), glm::vec4(0), 1.0f, 0, FboAttachmentType::All); - pRenderContext->clearFbo(mpFilteredPastFbo.get(), glm::vec4(0), 1.0f, 0, FboAttachmentType::All); - pRenderContext->clearFbo(mpCurReprojFbo.get(), glm::vec4(0), 1.0f, 0, FboAttachmentType::All); - pRenderContext->clearFbo(mpPrevReprojFbo.get(), glm::vec4(0), 1.0f, 0, FboAttachmentType::All); - pRenderContext->clearFbo(mpFilteredIlluminationFbo.get(), glm::vec4(0), 1.0f, 0, FboAttachmentType::All); + pRenderContext->clearFbo(mpPingPongFbo[0].get(), float4(0), 1.0f, 0, FboAttachmentType::All); + pRenderContext->clearFbo(mpPingPongFbo[1].get(), float4(0), 1.0f, 0, FboAttachmentType::All); + pRenderContext->clearFbo(mpLinearZAndNormalFbo.get(), float4(0), 1.0f, 0, FboAttachmentType::All); + pRenderContext->clearFbo(mpFilteredPastFbo.get(), float4(0), 1.0f, 0, FboAttachmentType::All); + pRenderContext->clearFbo(mpCurReprojFbo.get(), float4(0), 1.0f, 0, FboAttachmentType::All); + pRenderContext->clearFbo(mpPrevReprojFbo.get(), float4(0), 1.0f, 0, FboAttachmentType::All); + pRenderContext->clearFbo(mpFilteredIlluminationFbo.get(), float4(0), 1.0f, 0, FboAttachmentType::All); pRenderContext->clearTexture(renderData[kInternalBufferPreviousLinearZAndNormal]->asTexture().get()); pRenderContext->clearTexture(renderData[kInternalBufferPreviousLighting]->asTexture().get()); diff --git a/Source/RenderPasses/SVGFPass/SVGFPass.h b/Source/RenderPasses/SVGFPass/SVGFPass.h index 27d76b472..ad1cec76f 100644 --- a/Source/RenderPasses/SVGFPass/SVGFPass.h +++ b/Source/RenderPasses/SVGFPass/SVGFPass.h @@ -49,7 +49,7 @@ class SVGFPass : public RenderPass, public inherit_shared_from_thisattachColorTarget(renderData[kTarget]->asTexture(), 0); mpFbo->attachDepthStencilTarget(renderData[kDepth]->asTexture()); - pRenderContext->clearRtv(mpFbo->getRenderTargetView(0).get(), vec4(0)); + pRenderContext->clearRtv(mpFbo->getRenderTargetView(0).get(), float4(0)); if (!mpScene) return; diff --git a/Source/RenderPasses/ToneMapper/ToneMapper.cpp b/Source/RenderPasses/ToneMapper/ToneMapper.cpp index 32ce0984b..0fc3b7810 100644 --- a/Source/RenderPasses/ToneMapper/ToneMapper.cpp +++ b/Source/RenderPasses/ToneMapper/ToneMapper.cpp @@ -300,7 +300,7 @@ void ToneMapper::renderUI(Gui::Widgets& widget) // Display color widget for the currently chosen white point. // We normalize the color so that max(RGB) = 1 for display purposes. - glm::float3 w = mSourceWhite; + float3 w = mSourceWhite; w = w / std::max(std::max(w.r, w.g), w.b); colorgradingGroup.rgbColor("", w); } @@ -394,7 +394,7 @@ void ToneMapper::setWhiteMaxLuminance(float maxLuminance) void ToneMapper::setWhiteScale(float whiteScale) { - mWhiteScale = max(0.001f, whiteScale); + mWhiteScale = std::max(0.001f, whiteScale); mUpdateToneMapPass = true; } @@ -418,7 +418,7 @@ void ToneMapper::updateWhiteBalanceTransform() // Calculate color transform for the current white point. mWhiteBalanceTransform = mWhiteBalance ? calculateWhiteBalanceTransformRGB_Rec709(mWhitePoint) : glm::identity(); // Calculate source illuminant, i.e. the color that transforms to a pure white (1, 1, 1) output at the current color settings. - mSourceWhite = inverse(mWhiteBalanceTransform) * glm::float3(1, 1, 1); + mSourceWhite = inverse(mWhiteBalanceTransform) * float3(1, 1, 1); } void ToneMapper::updateColorTransform() diff --git a/Source/RenderPasses/ToneMapper/ToneMapper.h b/Source/RenderPasses/ToneMapper/ToneMapper.h index dd275793d..ab05f61ec 100644 --- a/Source/RenderPasses/ToneMapper/ToneMapper.h +++ b/Source/RenderPasses/ToneMapper/ToneMapper.h @@ -93,7 +93,7 @@ class ToneMapper : public RenderPass, public inherit_shared_from_this("TextureLODMode"); + op.regEnumVal(TexLODMode::Mip0); + op.regEnumVal(TexLODMode::RayCones);; + op.regEnumVal(TexLODMode::RayDiffsIsotropic); + op.regEnumVal(TexLODMode::RayDiffsAnisotropic); +} + +extern "C" __declspec(dllexport) void getPasses(Falcor::RenderPassLibrary & lib) +{ + lib.registerClass("WhittedRayTracer", "Simple Whitted ray tracer", WhittedRayTracer::create); + ScriptBindings::registerBinding(regTextureLOD); +} + + +WhittedRayTracer::SharedPtr WhittedRayTracer::create(RenderContext* pRenderContext, const Dictionary& dict) +{ + return SharedPtr(new WhittedRayTracer(dict)); +} + +WhittedRayTracer::WhittedRayTracer(const Dictionary& dict) +{ + // Deserialize pass from dictionary. + serializePass(dict); + + // Create ray tracing program. + RtProgram::Desc progDesc; + progDesc.addShaderLibrary(kShaderFile).setRayGen("rayGen"); + + progDesc.addHitGroup(0, "scatterClosestHit", "scatterAnyHit").addMiss(0, "scatterMiss"); + progDesc.addHitGroup(1, "", "shadowAnyHit").addMiss(1, "shadowMiss"); + progDesc.setMaxTraceRecursionDepth(kMaxRecursionDepth); + mTracer.pProgram = RtProgram::create(progDesc, kMaxPayloadSizeBytes, kMaxAttributesSizeBytes); + assert(mTracer.pProgram); + + // Create a sample generator. + mpSampleGenerator = SampleGenerator::create(SAMPLE_GENERATOR_UNIFORM); + assert(mpSampleGenerator); + + // Adjust input channels and dropdown to whether we use a rasterized G-buffer or a ray traced G-buffer + if (mUsingRasterizedGBuffer) + { + mInputChannels = + { + { "posW", "gWorldPosition", "World-space position (xyz) and foreground flag (w)" }, + { "normalW", "gWorldShadingNormal", "World-space shading normal (xyz)" }, + { "bitangentW", "gWorldShadingBitangent", "World-space shading bitangent (xyz)", true /* optional */ }, + { "faceNormalW", "gWorldFaceNormal", "Face normal in world space (xyz)", }, + { "mtlDiffOpacity", "gMaterialDiffuseOpacity", "Material diffuse color (xyz) and opacity (w)" }, + { "mtlSpecRough", "gMaterialSpecularRoughness", "Material specular color (xyz) and roughness (w)" }, + { "mtlEmissive", "gMaterialEmissive", "Material emissive color (xyz)" }, + { "mtlParams", "gMaterialExtraParams", "Material parameters (IoR, flags etc)" }, + { "surfSpreadAngle", "gSurfaceSpreadAngle", "surface spread angle (texlod)", true, ResourceFormat::R32Float}, + { "rayDifferentialX", "gRayDifferentialX", "ray differental X", true, ResourceFormat::RGBA32Float }, + { "rayDifferentialY", "gRayDifferentialY", "ray differental Y", true, ResourceFormat::RGBA32Float }, + { "rayDifferentialZ", "gRayDifferentialZ", "ray differental Z", true, ResourceFormat::RGBA32Float }, + }; + + mTexLODModes = + { + { uint(TexLODMode::Mip0), "Mip0" }, + { uint(TexLODMode::RayCones), "Ray cones" }, + { uint(TexLODMode::RayDiffsIsotropic), "Ray diffs (isotropic)" }, + { uint(TexLODMode::RayDiffsAnisotropic), "Ray diffs (anisotropic)" }, + }; + } + else + { + mInputChannels = + { + { "posW", "gWorldPosition", "World-space position (xyz) and foreground flag (w)" }, + { "normalW", "gWorldShadingNormal", "World-space shading normal (xyz)" }, + { "bitangentW", "gWorldShadingBitangent", "World-space shading bitangent (xyz)", true /* optional */ }, + { "faceNormalW", "gWorldFaceNormal", "Face normal in world space (xyz)", }, + { "mtlDiffOpacity", "gMaterialDiffuseOpacity", "Material diffuse color (xyz) and opacity (w)" }, + { "mtlSpecRough", "gMaterialSpecularRoughness", "Material specular color (xyz) and roughness (w)" }, + { "mtlEmissive", "gMaterialEmissive", "Material emissive color (xyz)" }, + { "mtlParams", "gMaterialExtraParams", "Material parameters (IoR, flags etc)" }, + { "vbuffer", "gVBuffer", "Visibility buffer in packed 64-bit format", true, ResourceFormat::RG32Uint }, + }; + + mTexLODModes = + { + { uint(TexLODMode::Mip0), "Mip0" }, + { uint(TexLODMode::RayDiffsIsotropic), "Ray diffs (isotropic)" }, + { uint(TexLODMode::RayDiffsAnisotropic), "Ray diffs (anisotropic)" }, + }; + } +} + +Dictionary WhittedRayTracer::getScriptingDictionary() +{ + Dictionary dict; + serializePass(dict); + return dict; +} + +RenderPassReflection WhittedRayTracer::reflect(const CompileData& compileData) +{ + RenderPassReflection reflector; + + addRenderPassInputs(reflector, mInputChannels); + addRenderPassOutputs(reflector, kOutputChannels); + + return reflector; +} + +void WhittedRayTracer::execute(RenderContext* pRenderContext, const RenderData& renderData) +{ + // Update refresh flag if options that affect the output have changed. + Dictionary& dict = renderData.getDictionary(); + if (mOptionsChanged) + { + auto prevFlags = (Falcor::RenderPassRefreshFlags)(dict.keyExists(kRenderPassRefreshFlags) ? dict[Falcor::kRenderPassRefreshFlags] : 0u); + dict[Falcor::kRenderPassRefreshFlags] = (uint32_t)(prevFlags | Falcor::RenderPassRefreshFlags::RenderOptionsChanged); + mOptionsChanged = false; + } + + // If we have no scene, just clear the outputs and return. + if (!mpScene) + { + for (auto it : kOutputChannels) + { + Texture* pDst = renderData[it.name]->asTexture().get(); + if (pDst) pRenderContext->clearTexture(pDst); + } + return; + } + + setStaticParams(mTracer.pProgram.get()); + + // For optional I/O resources, set 'is_valid_' defines to inform the program of which ones it can access. + // TODO: This should be moved to a more general mechanism using Slang. + mTracer.pProgram->addDefines(getValidResourceDefines(mInputChannels, renderData)); + mTracer.pProgram->addDefines(getValidResourceDefines(kOutputChannels, renderData)); + + // Prepare program vars. This may trigger shader compilation. + // The program should have all necessary defines set at this point. + if (!mTracer.pVars) prepareVars(); + assert(mTracer.pVars); + + // Get dimensions of ray dispatch. + const uint2 targetDim = renderData.getDefaultTextureDims(); + assert(targetDim.x > 0 && targetDim.y > 0); + + // Set constants. + auto pVars = mTracer.pVars; + pVars["CB"]["gFrameCount"] = mFrameCount; + pVars["CB"]["gPRNGDimension"] = dict.keyExists(kRenderPassPRNGDimension) ? dict[kRenderPassPRNGDimension] : 0u; + // Set up screen space pixel angle for texture LOD using ray cones + pVars["CB"]["gScreenSpacePixelSpreadAngle"] = mpScene->getCamera()->computeScreenSpacePixelSpreadAngle(targetDim.y); + + // Bind I/O buffers. These needs to be done per-frame as the buffers may change anytime. + auto bind = [&](const ChannelDesc& desc) + { + if (!desc.texname.empty()) + { + auto pGlobalVars = mTracer.pVars; + pGlobalVars[desc.texname] = renderData[desc.name]->asTexture(); + } + }; + for (auto channel : mInputChannels) bind(channel); + for (auto channel : kOutputChannels) bind(channel); + + // Spawn the rays. + mpScene->raytrace(pRenderContext, mTracer.pProgram.get(), mTracer.pVars, uint3(targetDim, 1)); + + mFrameCount++; +} + +void WhittedRayTracer::renderUI(Gui::Widgets& widget) +{ + bool dirty = false; + + dirty |= widget.var("Max bounces", mMaxBounces, 0u, 5u); + widget.tooltip("Maximum path length for indirect illumination.\n0 = direct only\n1 = one indirect bounce etc.", true); + + std::string text = std::string("Whitted Ray Tracer with ") + (mUsingRasterizedGBuffer ? std::string("rasterized G-buffer") : std::string("ray traced G-buffer")); + widget.text(text); + uint32_t modeIndex = static_cast(mTexLODMode); + if (widget.dropdown("Texture LOD mode", mTexLODModes, modeIndex)) + { + setTexLODMode(TexLODMode(modeIndex)); + dirty = true; + } + widget.tooltip("The texture level-of-detail mode to use."); + + // Lighting controls. + auto lightsGroup = Gui::Group(widget, "Lights", true); + if (lightsGroup.open()) + { + dirty |= lightsGroup.checkbox("Use analytic lights", mUseAnalyticLights); + lightsGroup.tooltip("This enables Falcor's built-in analytic lights.\nThese are specified in the scene description (.fscene).", true); + dirty |= lightsGroup.checkbox("Use emissive lights", mUseEmissiveLights); + lightsGroup.tooltip("This enables using emissive triangles as light sources.", true); + dirty |= lightsGroup.checkbox("Use env map as light", mUseEnvLight); + lightsGroup.tooltip("This enables using the environment map as a distant light source", true); + dirty |= lightsGroup.checkbox("Use env map as background", mUseEnvBackground); + lightsGroup.text(("Env map: " + (mpEnvProbe ? mEnvProbeFilename : "N/A")).c_str()); + + lightsGroup.release(); + } + + // If rendering options that modify the output have changed, set flag to indicate that. + // In execute() we will pass the flag to other passes for reset of temporal data etc. + if (dirty) + { + mOptionsChanged = true; + } +} + +void WhittedRayTracer::setScene(RenderContext* pRenderContext, const Scene::SharedPtr& pScene) +{ + // Clear data for previous scene. + // After changing scene, the program vars should to be recreated. + mTracer.pVars = nullptr; + mpEnvProbe = nullptr; + mEnvProbeFilename = ""; + mFrameCount = 0; + + // Set new scene. + mpScene = pScene; + + if (pScene) + { + mTracer.pProgram->addDefines(pScene->getSceneDefines()); + + // Load environment map if scene uses one. + Texture::SharedPtr pEnvMap = mpScene->getEnvironmentMap(); + if (pEnvMap != nullptr) + { + std::string filename = pEnvMap->getSourceFilename(); + mpEnvProbe = EnvProbe::create(pRenderContext, filename); + mEnvProbeFilename = mpEnvProbe ? getFilenameFromPath(filename) : ""; + } + } + +} + +void WhittedRayTracer::prepareVars() +{ + assert(mpScene); + assert(mTracer.pProgram); + + // Configure program. + mpSampleGenerator->prepareProgram(mTracer.pProgram.get()); + + // Create program variables for the current program/scene. + // This may trigger shader compilation. If it fails, throw an exception to abort rendering. + mTracer.pVars = RtProgramVars::create(mTracer.pProgram, mpScene); + assert(mTracer.pVars); + + // Bind utility classes into shared data. + auto pGlobalVars = mTracer.pVars->getRootVar(); + bool success = mpSampleGenerator->setShaderData(pGlobalVars); + if (!success) throw std::exception("Failed to bind sample generator"); + + // Bind the light probe if one is loaded. + if (mpEnvProbe) + { + bool success = mpEnvProbe->setShaderData(pGlobalVars["CB"]["gEnvProbe"]); + if (!success) throw std::exception("Failed to bind environment map"); + } +} + +void WhittedRayTracer::setStaticParams(RtProgram* pProgram) const +{ + Program::DefineList defines; + defines.add("MAX_BOUNCES", std::to_string(mMaxBounces)); + defines.add("TEXLOD_MODE", std::to_string(static_cast(mTexLODMode))); + defines.add("USE_RASTERIZED_GBUFFER", mUsingRasterizedGBuffer ? "1" : "0"); + defines.add("USE_ANALYTIC_LIGHTS", mUseAnalyticLights ? "1" : "0"); + defines.add("USE_EMISSIVE_LIGHTS", mUseEmissiveLights ? "1" : "0"); + defines.add("USE_ENV_LIGHT", (mpEnvProbe && mUseEnvLight) ? "1" : "0"); + defines.add("USE_ENV_BACKGROUND", (mpEnvProbe && mUseEnvBackground) ? "1" : "0"); + pProgram->addDefines(defines); +} diff --git a/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.h b/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.h new file mode 100644 index 000000000..dd87a5106 --- /dev/null +++ b/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.h @@ -0,0 +1,127 @@ +/*************************************************************************** + # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ +#pragma once +#include "Falcor.h" +#include "FalcorExperimental.h" +#include "RenderGraph/RenderPassHelpers.h" +#include "Utils/Sampling/SampleGenerator.h" +#include "Experimental/Scene/Lights/EnvProbe.h" +#include "Experimental/Scene/Material/TexLODTypes.slang" // Using the enum with Mip0, RayCones, etc + +using namespace Falcor; + +/** Whitted ray tracer. + + This pass implements the simplest possible Whitted ray tracer. +*/ +class WhittedRayTracer : public RenderPass, public inherit_shared_from_this +{ +public: + using SharedPtr = std::shared_ptr; + using inherit_shared_from_this::shared_from_this; + + + static SharedPtr create(RenderContext* pRenderContext = nullptr, const Dictionary& dict = {}); + + virtual std::string getDesc() override { return "Whitted ray tracer"; } + virtual Dictionary getScriptingDictionary() override; + virtual RenderPassReflection reflect(const CompileData& compileData) override; + virtual void execute(RenderContext* pRenderContext, const RenderData& renderData) override; + virtual void renderUI(Gui::Widgets& widget) override; + virtual void setScene(RenderContext* pRenderContext, const Scene::SharedPtr& pScene) override; + virtual bool onMouseEvent(const MouseEvent& mouseEvent) override { return false; } + virtual bool onKeyEvent(const KeyboardEvent& keyEvent) override { return false; } + + void setTexLODMode(const TexLODMode mode) { mTexLODMode = mode; } + TexLODMode getTexLODMode() const { return mTexLODMode; } + +private: + WhittedRayTracer(const Dictionary& dict); + + void prepareVars(); + void setStaticParams(RtProgram* pProgram) const; + + // Internal state + Scene::SharedPtr mpScene; ///< Current scene. + SampleGenerator::SharedPtr mpSampleGenerator; ///< GPU sample generator. + EnvProbe::SharedPtr mpEnvProbe; ///< Environment map sampling (if used). + std::string mEnvProbeFilename; ///< Name of loaded environment map (stripped of full path). + + ChannelList mInputChannels; + Gui::DropdownList mTexLODModes; + + uint mMaxBounces = 3; ///< Max number of indirect bounces (0 = none). + int mUseAnalyticLights = true; ///< Use built-in analytic lights. + int mUseEmissiveLights = true; ///< Use emissive geometry as light sources. + int mUseEnvLight = false; ///< Use environment map as light source (if loaded). + int mUseEnvBackground = true; ///< Use environment map as background (if loaded). + TexLODMode mTexLODMode = TexLODMode::Mip0; ///< Which texture LOD mode to use + bool mUsingRasterizedGBuffer = true; ///< Set by the Python file (whether rasterized GBUffer or ray traced GBuffer is used) + // Runtime data + uint mFrameCount = 0; ///< Frame count since scene was loaded. + bool mOptionsChanged = false; + + // Ray tracing program. + struct + { + RtProgram::SharedPtr pProgram; + RtProgramVars::SharedPtr pVars; + } mTracer; + + // Scripting +#define serialize(var) \ + if constexpr (!loadFromDict) dict[#var] = var; \ + else if (dict.keyExists(#var)) { if constexpr (std::is_same::value) var = (const std::string &)dict[#var]; else var = dict[#var]; vars.emplace(#var); } + + template + void serializePass(DictType& dict) + { + std::unordered_set vars; + + // Add variables here that should be serialized to/from the dictionary. + serialize(mMaxBounces); + serialize(mUseAnalyticLights); + serialize(mUseEmissiveLights); + serialize(mUseEnvLight); + serialize(mUseEnvBackground); + serialize(mTexLODMode); + serialize(mUsingRasterizedGBuffer); + + if constexpr (loadFromDict) + { + for (const auto& v : dict) + { + auto k = v.key(); + if (vars.find(v.key()) == vars.end()) + logWarning("Unknown field `" + v.key() + "` in a WhittedRayTracer dictionary"); + } + } + } +#undef serialize + +}; diff --git a/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.rt.slang b/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.rt.slang new file mode 100644 index 000000000..11653b4a2 --- /dev/null +++ b/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.rt.slang @@ -0,0 +1,543 @@ +/*************************************************************************** + # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: + # * Redistributions of source code must retain the above copyright + # notice, this list of conditions and the following disclaimer. + # * Redistributions in binary form must reproduce the above copyright + # notice, this list of conditions and the following disclaimer in the + # documentation and/or other materials provided with the distribution. + # * Neither the name of NVIDIA CORPORATION nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **************************************************************************/ + +/** Whitted ray tracer. + + The purpose is to use it as a baseline for showing how to implement different + texture level-of-detail filtering methods. + + The host sets the following defines: + + MAX_BOUNCES Maximum number of indirect bounces (0 means no indirect). + USE_ANALYTIC_LIGHTS Nonzero if Falcor's analytic lights should be used. + USE_EMISSIVE_LIGHTS Nonzero if emissive geometry should be used as lights. + USE_ENV_LIGHT Nonzero if env map is available and should be used as light source. + USE_ENV_BACKGROUND Nonzero if env map is available and should be used as background. + TEXLOD_MODE Could be either of Mip0, RayCones, RayDiffsIsotropic, RayDiffsAnisotropic + USE_RASTERIZED_GBUFFER True if we use rasterized G-buffer. + is_valid_ 1 if optional I/O buffer with this name should be used. +*/ + +#include "Utils/Math/MathConstants.slangh" + +import Scene.Raytracing; +import Scene.HitInfo; +import Utils.Math.MathHelpers; +import Utils.Sampling.SampleGenerator; +import Experimental.Scene.Material.MaterialShading; +import Experimental.Scene.Lights.EnvProbe; +import Experimental.Scene.Lights.LightHelpers; +import Experimental.Scene.Material.TexLODHelpers; +import Experimental.Scene.Material.TexLODTypes; + +cbuffer CB +{ + uint gFrameCount; // Frame count since scene was loaded. + uint gPRNGDimension; // First available PRNG dimension. + EnvProbe gEnvProbe; // Environment map sampling functions. + float gScreenSpacePixelSpreadAngle; // The angle an "average" pixel spans from camera (texLOD) +} + +// Inputs +Texture2D gWorldPosition; +Texture2D gWorldShadingNormal; +Texture2D gWorldShadingBitangent; // Optional +Texture2D gWorldFaceNormal; +Texture2D gWorldView; // Optional +Texture2D gMaterialDiffuseOpacity; +Texture2D gMaterialSpecularRoughness; +Texture2D gMaterialEmissive; +Texture2D gMaterialExtraParams; +Texture2D gSurfaceSpreadAngle; +Texture2D gRayDifferentialX; +Texture2D gRayDifferentialY; +Texture2D gRayDifferentialZ; +Texture2D gVBuffer; + + +// Outputs +RWTexture2D gOutputColor; + +// Static configuration based on defines set from the host. +#define isValid(name) (is_valid_##name != 0) +static const uint kMaxBounces = MAX_BOUNCES; +static const uint kTexLODMode = TEXLOD_MODE; +static const bool kUsingRasterizedGBuffer = USE_RASTERIZED_GBUFFER; +static const bool kUseAnalyticLights = USE_ANALYTIC_LIGHTS; +static const bool kUseEmissiveLights = USE_EMISSIVE_LIGHTS; +static const bool kUseEnvLight = USE_ENV_LIGHT; +static const bool kUseEnvBackground = USE_ENV_BACKGROUND; +static const float3 kDefaultBackgroundColor = float3(0, 0, 0); +static const float kRayTMax = FLT_MAX; + +/** Payload for shadow ray. +*/ +struct ShadowRayData +{ + bool visible; +}; + +/** Payload for scatter ray (128B when ray cones are used, 164B when ray diffs are used). +*/ +struct ScatterRayData +{ + float3 radiance; ///< Accumulated outgoing radiance from path. + bool terminated; ///< Set to true when path is terminated. + float3 thp; ///< Current path throughput. This is updated at each path vertex. + uint pathLength; ///< Path length in number of path segments (0 at origin, 1 at first secondary hit, etc.). Max 2^31. + float3 origin; ///< Next path segment origin. + float3 direction; ///< Next path segment direction. + // only one (at most) of RayCone and RayDiff will be used (none, if we use Mip0) + RayCone rayCone; ///< Ray cone (2 floats) for texture LOD + RayDiff rayDiff; ///< Ray differential (12 floats) for texture LOD + + SampleGenerator sg; ///< Per-ray state for the sample generator (up to 16B). + + /** Create ray payload with default parameters. + */ + static ScatterRayData create(SampleGenerator sg) + { + ScatterRayData d; + d.terminated = false; + d.pathLength = 0; + d.radiance = float3(0, 0, 0); + d.thp = float3(1, 1, 1); + d.origin = float3(0, 0, 0); + d.direction = float3(0, 0, 0); + d.sg = sg; + d.rayCone = {}; + d.rayDiff = {}; + return d; + } +}; + +/** Helper to load the material attributes. +*/ +MaterialParams loadMaterialParams(uint2 pixelPos) +{ + MaterialParams matParams; + matParams.diffuseOpacity = gMaterialDiffuseOpacity[pixelPos]; + matParams.specularRoughness = gMaterialSpecularRoughness[pixelPos]; + matParams.emissive = gMaterialEmissive[pixelPos]; + matParams.extraParams = gMaterialExtraParams[pixelPos]; + + return matParams; +} + +/** Traces a shadow ray towards a light source. + \param[in] origin Ray origin for the shadow ray. + \param[in] dir Direction from shading point towards the light source (normalized). + \param[in] distance Distance to the light source. + \return True if light is visible, false otherwise. +*/ +bool traceShadowRay(float3 origin, float3 dir, float distance) +{ + RayDesc ray; + ray.Origin = origin; + ray.Direction = dir; + ray.TMin = 0.f; + ray.TMax = distance; + + ShadowRayData rayData; + rayData.visible = false; // Set to true by miss shader if ray is not terminated before + TraceRay(gRtScene, RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH, 0xff /* instanceInclusionMask */, 1 /* hitIdx */, hitProgramCount, 1 /* missIdx */, ray, rayData); + + return rayData.visible; +} + +/** Traces a scatter ray based on ray parameters stored in the ray payload. + \param[in] rayData Describes the ray parameters. The struct is modified based on the result. +*/ +void traceScatterRay(inout ScatterRayData rayData) +{ + RayDesc ray; + ray.Origin = rayData.origin; + ray.Direction = rayData.direction; + ray.TMin = 0.f; + ray.TMax = kRayTMax; + + uint rayFlags = 0; // TODO: Set cull mode from the app + TraceRay(gRtScene, rayFlags, 0xff /* instanceInclusionMask */, 0 /* hitIdx */, hitProgramCount, 0 /* missIdx */, ray, rayData); +} + +/** Evaluates the direct illumination from analytic lights. + This function samples Falcor's light list uniformly with one shadow ray. + \param[in] sd Shading data. + \param[in] rayOrigin Ray origin for the shadow ray. + \param[in] sg SampleGenerator object. + \return Outgoing radiance in view direction. +*/ +float3 evalDirectAnalytic(const ShadingData sd, float3 rayOrigin, inout SampleGenerator sg) +{ + // Use all analytic light sources + const uint lightCount = gScene.getLightCount(); + float invPdf = lightCount; // Light selection pdf = 1.0 / lightCount. + + float3 contribution = float3(0); + for (uint lightIndex = 0; lightIndex < lightCount; lightIndex++) + { + // Sample local light source. + AnalyticLightSample ls; + sampleLight(rayOrigin, gScene.getLight(lightIndex), sg, ls); + + // Reject sample if lower hemisphere. + if (dot(ls.dir, sd.N) > kMinCosTheta) + { + // Test visibility by tracing a shadow ray. + bool V = traceShadowRay(rayOrigin, ls.dir, ls.distance); + contribution += V ? evalBSDFCosine(sd, ls.dir) * ls.Li * invPdf : float3(0); + } + } + return contribution; +} + +/** Processes a hit point to generate a scatter ray or terminate. + This function generates a cosine-weighted direction over the hemisphere. + \param[in] sd Shading data. + \param[in] rayOrigin Ray origin for the new ray. + \param[in] rayData Ray payload. +*/ +void generateReflectionRay(const ShadingData sd, const float3 rayOrigin, const float3 rayDir, const float3 normal, inout ScatterRayData rayData) +{ + float3 wi = reflect(rayDir, normal); + rayData.origin = rayOrigin; + rayData.direction = wi; +} + +/** ********************* Ray index 0: Scatter ray ************************ */ + +[shader("miss")] +void scatterMiss(inout ScatterRayData rayData : SV_RayPayload) +{ + // Ray missed the scene. Mark the ray as terminated. + rayData.terminated = true; + + // Add contribution from distant light (env map) in this direction. + if (kUseEnvLight) + { + float3 Le = evalEnvProbe(gEnvProbe, WorldRayDirection()); + rayData.radiance += rayData.thp * Le; + } +} + +[shader("anyhit")] +void scatterAnyHit( + uniform HitShaderParams hitParams, + inout ScatterRayData rayData : SV_RayPayload, BuiltInTriangleIntersectionAttributes attribs : SV_IntersectionAttributes) +{ + // Alpha test for non-opaque geometry. + VertexData v = getVertexData(hitParams, PrimitiveIndex(), attribs); + const uint materialID = gScene.getMaterialID(hitParams.getGlobalHitID()); + if (alphaTest(v, gScene.materials[materialID], gScene.materialResources[materialID], 0.f)) IgnoreHit(); +} + +[shader("closesthit")] +void scatterClosestHit( + uniform HitShaderParams hitParams, + inout ScatterRayData rayData : SV_RayPayload, BuiltInTriangleIntersectionAttributes attribs : SV_IntersectionAttributes) +{ + // Evaluate Falcor's material parameters at the hit point. + // Note we pass hitPos-rayDir as "camera position" to avoid zero-length rays causing NaNs + // in the view direction. It'd been cleaner if prepareShadingData() took ray dir directly. + const float3 rayDir = WorldRayDirection(); + const float3 rayOrg = WorldRayOrigin(); + + float hitT = RayTCurrent(); + const uint materialID = gScene.getMaterialID(hitParams.getGlobalHitID()); + ShadingData sd; + VertexData v; + + if (TexLODMode(kTexLODMode) == TexLODMode::Mip0) + { + v = getVertexData(hitParams, PrimitiveIndex(), attribs); + sd = prepareShadingData(v, materialID, gScene.materials[materialID], gScene.materialResources[materialID], v.posW - rayDir, 0.0); + } + else if(TexLODMode(kTexLODMode) == TexLODMode::RayCones) + { + v = getVertexDataRayCones(hitParams, PrimitiveIndex(), attribs); + + // Compute texture LOD for prepareShadingData() + rayData.rayCone = rayData.rayCone.propagate(0.0, hitT); // Using 0.0 here since we do not have any curvature measure, except when starting with gBuffer (and only for the first hit) + float lambda = rayData.rayCone.computeLOD(v.coneTexLODValue, hitT, rayDir, v.normalW); + sd = prepareShadingDataUsingRayConesLOD(v, materialID, gScene.materials[materialID], gScene.materialResources[materialID], v.posW - rayDir, lambda); + } + else // RayDiffs + { + float2 dUVdx, dUVdy; // ray differential variables for the texture lookup + float3 geometricNormal = gScene.getFaceNormalW(hitParams.getGlobalHitID(), PrimitiveIndex()); + RayDiff newRayDiff = rayData.rayDiff.propagate(rayOrg, rayDir, hitT, geometricNormal); // Propagate the ray differential to the current hit point + + v = getVertexDataRayDiff(hitParams, PrimitiveIndex(), attribs, rayDir, hitT, newRayDiff, dUVdx, dUVdy); + + rayData.rayDiff = newRayDiff; + if (TexLODMode(kTexLODMode) == TexLODMode::RayDiffsIsotropic) + { + // When using prepareShadingDataUsingRayDiffsLOD(), the texture samepler will compute a single lambda for texture LOD + // using the dUVdx and dUVdy + sd = prepareShadingDataUsingRayDiffsLOD(v, materialID, gScene.materials[materialID], gScene.materialResources[materialID], v.posW - rayDir, dUVdx, dUVdy); + } + else // TexLODMode::RayDiffsAnisotropic + { + // Use the dUVdx and dUVdy directly --> gives you anisotropic filtering + sd = prepareShadingData(v, materialID, gScene.materials[materialID], gScene.materialResources[materialID], v.posW - rayDir, dUVdx, dUVdy); + } + } + + // Compute tangent space if it is invalid. + // TODO: Remove this check when we're sure the tangent space is always valid. + if (!(dot(sd.B, sd.B) > 0.f)) // Note: Comparison written so that NaNs trigger + { + sd.B = perp_stark(sd.N); + sd.T = cross(sd.B, sd.N); + } + + // Add emitted light. + if (kUseEmissiveLights) + { + rayData.radiance += rayData.thp * sd.emissive; + } + + // Check whether to terminate based on max depth. + if (rayData.pathLength >= kMaxBounces) + { + rayData.terminated = true; + return; + } + + // Compute ray origin for new rays spawned from the hit. + float3 rayOrigin = sd.computeNewRayOrigin(); + + // Add contribution of direct light from analytic lights. + if (kUseAnalyticLights) + { + float3 Lr = evalDirectAnalytic(sd, rayOrigin, rayData.sg); + rayData.radiance += rayData.thp * Lr; + } + + // Generate scatter ray for the next path segment. + // The raygen shader will continue the path based on the returned payload. + + generateReflectionRay(sd, rayOrigin, rayDir, v.normalW, rayData); + + rayData.pathLength++; +} + +/************************** Ray index 1: Shadow ray ************************ */ + +[shader("miss")] +void shadowMiss(inout ShadowRayData rayData : SV_RayPayload) +{ + // The miss shader is executed if the ray misses all geometry. Mark as visible. + rayData.visible = true; +} + +[shader("anyhit")] +void shadowAnyHit( + uniform HitShaderParams hitParams, + inout ShadowRayData rayData : SV_RayPayload, BuiltInTriangleIntersectionAttributes attribs : SV_IntersectionAttributes) +{ + // Alpha test for non-opaque geometry. + VertexData v = getVertexData(hitParams, PrimitiveIndex(), attribs); + const uint materialID = gScene.getMaterialID(hitParams.getGlobalHitID()); + if (alphaTest(v, gScene.materials[materialID], gScene.materialResources[materialID], 0.f)) IgnoreHit(); +} + +/** ******************************** RayGen ******************************** */ + +/** This is the entry point for the minimal path tracer. + + One path per pixel is generated, which is traced into the scene. + The path tracer is written as a for-loop over path segments. + + Built-in light sources (point, directional) are sampled explicitly at each + path vertex. The contributions from area lights (env map and mesh lights) + are explicitly added by the scatter ray hit/miss shaders. +*/ +[shader("raygeneration")] +void rayGen() +{ + uint2 launchIndex = DispatchRaysIndex().xy; + uint2 launchDim = DispatchRaysDimensions().xy; + + float3 outColor = float3(0, 0, 0); + + const float3 nonNormalizedRayDir = gScene.camera.computeNonNormalizedRayDirPinhole(launchIndex, launchDim); // used by ray diffs + const float3 rayDir = normalize(nonNormalizedRayDir); + const float4 worldPos = gWorldPosition[launchIndex]; + + + if (worldPos.w != 0.f) // Using w to indicate valid geometry for now + { + // Pixel represents a valid primary hit. Compute its contribution. + + // Load geometry parameters from G-buffer. + float3 normal = gWorldShadingNormal[launchIndex].xyz; + float3 bitangent = isValid(gWorldShadingBitangent) ? gWorldShadingBitangent[launchIndex].xyz : perp_stark(normal); + float3 faceNormal = gWorldFaceNormal[launchIndex].xyz; + GeometryParams geoParams = prepareGeometryParams(worldPos.xyz, -rayDir, normal, bitangent, faceNormal); + + // Load material parameters from G-buffer. + MaterialParams matParams = loadMaterialParams(launchIndex); + + // Prepare ShadingData struct. + ShadingData sd = prepareShadingData(geoParams, matParams); + + // Create sample generator. + SampleGenerator sg = SampleGenerator.create(launchIndex, gFrameCount); + + // Advance the generator to the first available dimension. + // TODO: This is potentially expensive. We may want to store/restore the state from memory if it becomes a problem. + for (uint i = 0; i < gPRNGDimension; i++) sampleNext1D(sg); + + // Compute ray origin for new rays spawned from the G-buffer. + const float3 rayOrigin = sd.computeNewRayOrigin(); + + // Always output directly emitted light, independent of whether emissive materials are treated as light sources or not. + outColor += sd.emissive; + + // Add contribution of direct light from analytic lights. + // Light probe and mesh lights are handled by the scatter ray hit/miss shaders. + outColor += kUseAnalyticLights ? evalDirectAnalytic(sd, rayOrigin, sg) : float3(0, 0, 0); + + // Prepare ray payload. + ScatterRayData rayData = ScatterRayData.create(sg); + + if (!kUsingRasterizedGBuffer) + { + rayData.pathLength++; + } + + // Generate scatter ray. + generateReflectionRay(sd, rayOrigin, rayDir, normal, rayData); + + if (TexLODMode(kTexLODMode) == TexLODMode::RayCones) + { + // Set up ray cone (texLOD) at the hit point: first create ray cone at camera, the propagate to hit point + float surfaceSpreadAngle = gSurfaceSpreadAngle[launchIndex]; // load the surface spread angle from G-buffer (for ray cones, texture LOD) + rayData.rayCone = RayCone.create(0.0, gScreenSpacePixelSpreadAngle); + const float hitT = length(gScene.camera.getPosition() - worldPos.xyz); + rayData.rayCone = rayData.rayCone.propagate(surfaceSpreadAngle, hitT); + } + else if (TexLODMode(kTexLODMode) == TexLODMode::RayDiffsIsotropic || TexLODMode(kTexLODMode) == TexLODMode::RayDiffsAnisotropic) + { + RayDiff rd; + if (kUsingRasterizedGBuffer) + { + // Create ray diff from G-buffer + // The most expensive method in terms of G-buffer storage -- generate the ray diff in pixel shader and store out in G-buffer + float4 X = gRayDifferentialX[launchIndex]; + float4 Y = gRayDifferentialY[launchIndex]; + float4 Z = gRayDifferentialZ[launchIndex]; + float3 dOdx = float3(X.x, Y.x, Z.x); + float3 dOdy = float3(X.y, Y.y, Z.y); + float3 dDdx = float3(X.z, Y.z, Z.z); + float3 dDdy = float3(X.w, Y.w, Z.w); + rayData.rayDiff = RayDiff.create(dOdx, dOdy, dDdx, dDdy); + rd = RayDiff.create(dOdx, dOdy, dDdx, dDdy); + } + else // Not using a rasterized Gbuffer + { + float3 dDdx, dDdy; + const float3 rayOrg = gScene.camera.getPosition(); + const float hitT = length(rayOrg - worldPos.xyz) * 1; + + getRayDirectionDifferentials(nonNormalizedRayDir, gScene.camera.data.cameraU, gScene.camera.data.cameraV, launchDim, dDdx, dDdy); + + rayData.rayDiff = RayDiff.create(float3(0.0), float3(0.0), dDdx, dDdy); // init ray diff. dOdx = 0 , dOdy = 0, and the directions are from above. + + rayData.rayDiff = rayData.rayDiff.propagate(worldPos.xyz, rayDir, hitT, faceNormal); // propagate the ray differential to the current hit point + HitInfo hit; + + if (hit.decode(gVBuffer[launchIndex])) + { + const float4x4 worldMat = gScene.getWorldMatrix(hit.meshInstanceID); + const float3x3 worldInvTransposeMat = gScene.getInverseTransposeWorldMatrix(hit.meshInstanceID); + const uint3 vtxIndices = gScene.getIndices(hit.meshInstanceID, hit.primitiveIndex); + const float3 barycentrics = hit.getBarycentricWeights(); + float3 unnormalizedN; + float3 vtxs[3]; + float3 normals[3]; + float2 txcoords[3]; + + // Get relevant vertex data and transform to world space + StaticVertexData vtx[3] = { gScene.getVertex(vtxIndices[0]), gScene.getVertex(vtxIndices[1]), gScene.getVertex(vtxIndices[2]) }; + + vtxs[0] = mul(float4(vtx[0].position, 1.0), worldMat).xyz; + vtxs[1] = mul(float4(vtx[1].position, 1.0), worldMat).xyz; + vtxs[2] = mul(float4(vtx[2].position, 1.0), worldMat).xyz; + normals[0] = mul(vtx[0].normal, worldInvTransposeMat); + normals[1] = mul(vtx[1].normal, worldInvTransposeMat); + normals[2] = mul(vtx[2].normal, worldInvTransposeMat); + normals[0] = normalize(normals[0]); + normals[1] = normalize(normals[1]); + normals[2] = normalize(normals[2]); + unnormalizedN = normals[0] * barycentrics[0]; + unnormalizedN += normals[1] * barycentrics[1]; + unnormalizedN += normals[2] * barycentrics[2]; + txcoords[0] = vtx[0].texCrd; + txcoords[1] = vtx[1].texCrd; + txcoords[2] = vtx[2].texCrd; + + float2 dBarydx, dBarydy; + float2 dUVdx, dUVdy; + float3 e1 = vtxs[1] - vtxs[0]; + float3 e2 = vtxs[2] - vtxs[0]; + float3 normalizedGeometricNormal = normalize(cross(vtxs[1] - vtxs[0], vtxs[2] - vtxs[0])); + + computeDifferentialsBarysAndUVs(rayData.rayDiff, rayDir, vtxs, txcoords, e1, e2, normalizedGeometricNormal, hitT, dBarydx, dBarydy, dUVdx, dUVdy); + reflectRayDifferential(rayData.rayDiff, rayDir, unnormalizedN, normalize(unnormalizedN), dBarydx, dBarydy, e1, e2, normals); + } + else + { + // TODO TAM: make it work for environment maps. Chapter 21 in Ray Tracing Gems. + rayData.rayDiff = RayDiff.create(float3(0), float3(0), float3(0), float3(0)); + } + } + } + + if(sd.linearRoughness <= 0.19) // Only trace reflection rays when material is highly reflective + { + // Follow path into the scene and compute its total contribution. + for (uint depth = 0; depth <= kMaxBounces && !rayData.terminated; depth++) + { + // Trace scatter ray. If it hits geometry, the closest hit shader samples + // direct illumination and generates the next scatter ray. + traceScatterRay(rayData); + } + } + // Store contribution from scatter ray. + outColor += rayData.radiance; + } + else + { + // Background pixel. + outColor = kUseEnvBackground ? evalEnvProbe(gEnvProbe, rayDir) : kDefaultBackgroundColor; + } + + gOutputColor[launchIndex] = float4(outColor, 1); +} diff --git a/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.vcxproj b/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.vcxproj new file mode 100644 index 000000000..7a0f7c8f8 --- /dev/null +++ b/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.vcxproj @@ -0,0 +1,105 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {431C3127-E613-424C-B964-FB53DAA87789} + Win32Proj + WhittedRayTracer + 10.0.18362.0 + WhittedRayTracer + + + + + + + + + + + + + + + + + {2c535635-e4c5-4098-a928-574f0e7cd5f9} + + + + + + + DynamicLibrary + true + v142 + Unicode + Shaders\RenderPasses\$(ProjectName) + + + DynamicLibrary + false + v142 + true + Unicode + Shaders\RenderPasses\$(ProjectName) + + + + + + + true + + + false + + + + + + Level3 + Disabled + PROJECT_DIR=R"($(ProjectDir))";_DEBUG;%(PreprocessorDefinitions) + true + true + stdcpp17 + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + PROJECT_DIR=R"($(ProjectDir))";NDEBUG;%(PreprocessorDefinitions) + true + true + stdcpp17 + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.vcxproj.filters b/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.vcxproj.filters new file mode 100644 index 000000000..216f5d82d --- /dev/null +++ b/Source/RenderPasses/WhittedRayTracer/WhittedRayTracer.vcxproj.filters @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Samples/CudaInterop/CudaInterop.cpp b/Source/Samples/CudaInterop/CudaInterop.cpp index ca03a40a4..1d08b77ba 100644 --- a/Source/Samples/CudaInterop/CudaInterop.cpp +++ b/Source/Samples/CudaInterop/CudaInterop.cpp @@ -57,7 +57,7 @@ void CudaInterop::onLoad(RenderContext* pRenderContext) void CudaInterop::onFrameRender(RenderContext* pRenderContext, const Fbo::SharedPtr& pTargetFbo) { - const glm::vec4 clearColor(0.38f, 0.52f, 0.10f, 1); + const float4 clearColor(0.38f, 0.52f, 0.10f, 1); pRenderContext->clearFbo(pTargetFbo.get(), clearColor, 1.0f, 0, FboAttachmentType::All); // Call the CUDA kernel diff --git a/Source/Samples/HelloDXR/HelloDXR.cpp b/Source/Samples/HelloDXR/HelloDXR.cpp index 2dcbb80d2..335dd5ee7 100644 --- a/Source/Samples/HelloDXR/HelloDXR.cpp +++ b/Source/Samples/HelloDXR/HelloDXR.cpp @@ -27,10 +27,10 @@ **************************************************************************/ #include "HelloDXR.h" -static const glm::vec4 kClearColor(0.38f, 0.52f, 0.10f, 1); +static const float4 kClearColor(0.38f, 0.52f, 0.10f, 1); static const std::string kDefaultScene = "Arcade/Arcade.fscene"; -std::string to_string(const vec3& v) +std::string to_string(const float3& v) { std::string s; s += "(" + std::to_string(v.x) + ", " + std::to_string(v.y) + ", " + std::to_string(v.z) + ")"; @@ -99,7 +99,7 @@ void HelloDXR::setPerFrameVars(const Fbo* pTargetFbo) PROFILE("setPerFrameVars"); auto cb = mpRtVars["PerFrameCB"]; cb["invView"] = glm::inverse(mpCamera->getViewMatrix()); - cb["viewportDims"] = vec2(pTargetFbo->getWidth(), pTargetFbo->getHeight()); + cb["viewportDims"] = float2(pTargetFbo->getWidth(), pTargetFbo->getHeight()); float fovY = focalLengthToFovY(mpCamera->getFocalLength(), Camera::kDefaultFrameHeight); cb["tanHalfFovY"] = tanf(fovY * 0.5f); cb["sampleIndex"] = mSampleIndex++; @@ -113,7 +113,7 @@ void HelloDXR::renderRT(RenderContext* pContext, const Fbo* pTargetFbo) setPerFrameVars(pTargetFbo); pContext->clearUAV(mpRtOut->getUAV().get(), kClearColor); - mpScene->raytrace(pContext, mpRaytraceProgram.get(), mpRtVars, uvec3(pTargetFbo->getWidth(), pTargetFbo->getHeight(), 1)); + mpScene->raytrace(pContext, mpRaytraceProgram.get(), mpRtVars, uint3(pTargetFbo->getWidth(), pTargetFbo->getHeight(), 1)); pContext->blit(mpRtOut->getSRV(), pTargetFbo->getRenderTargetView(0)); } @@ -123,7 +123,7 @@ void HelloDXR::onFrameRender(RenderContext* pRenderContext, const Fbo::SharedPtr if(mpScene) { - mpScene->update(pRenderContext, gpFramework->getGlobalClock().now()); + mpScene->update(pRenderContext, gpFramework->getGlobalClock().getTime()); if (mRayTrace) renderRT(pRenderContext, pTargetFbo.get()); else mpRasterPass->renderScene(pRenderContext, pTargetFbo); } diff --git a/Source/Samples/ModelViewer/ModelViewer.cpp b/Source/Samples/ModelViewer/ModelViewer.cpp index 81e3eb059..94d02f148 100644 --- a/Source/Samples/ModelViewer/ModelViewer.cpp +++ b/Source/Samples/ModelViewer/ModelViewer.cpp @@ -161,13 +161,13 @@ void ModelViewer::onLoad(RenderContext* pRenderContext) void ModelViewer::onFrameRender(RenderContext* pRenderContext, const Fbo::SharedPtr& pTargetFbo) { - const glm::vec4 clearColor(0.38f, 0.52f, 0.10f, 1); + const float4 clearColor(0.38f, 0.52f, 0.10f, 1); pRenderContext->clearFbo(pTargetFbo.get(), clearColor, 1.0f, 0, FboAttachmentType::All); mpGraphicsState->setFbo(pTargetFbo); if(mpScene) { - mpScene->update(pRenderContext, gpFramework->getGlobalClock().now()); + mpScene->update(pRenderContext, gpFramework->getGlobalClock().getTime()); // Set render state Scene::RenderFlags renderFlags = Scene::RenderFlags::None; @@ -193,7 +193,7 @@ void ModelViewer::onFrameRender(RenderContext* pRenderContext, const Fbo::Shared mpScene->render(pRenderContext, mpGraphicsState.get(), mpProgramVars.get(), renderFlags); } - TextRenderer::render(pRenderContext, mModelString, pTargetFbo, glm::vec2(10, 30)); + TextRenderer::render(pRenderContext, mModelString, pTargetFbo, float2(10, 30)); } bool ModelViewer::onKeyEvent(const KeyboardEvent& keyEvent) diff --git a/Source/Samples/ProjectTemplate/ProjectTemplate.cpp b/Source/Samples/ProjectTemplate/ProjectTemplate.cpp index 257c8fc64..e9691c0d4 100644 --- a/Source/Samples/ProjectTemplate/ProjectTemplate.cpp +++ b/Source/Samples/ProjectTemplate/ProjectTemplate.cpp @@ -48,7 +48,7 @@ void ProjectTemplate::onLoad(RenderContext* pRenderContext) void ProjectTemplate::onFrameRender(RenderContext* pRenderContext, const Fbo::SharedPtr& pTargetFbo) { - const glm::vec4 clearColor(0.38f, 0.52f, 0.10f, 1); + const float4 clearColor(0.38f, 0.52f, 0.10f, 1); pRenderContext->clearFbo(pTargetFbo.get(), clearColor, 1.0f, 0, FboAttachmentType::All); } diff --git a/Source/Samples/ShaderToy/ShaderToy.cpp b/Source/Samples/ShaderToy/ShaderToy.cpp index 2a70423f4..3fc679750 100644 --- a/Source/Samples/ShaderToy/ShaderToy.cpp +++ b/Source/Samples/ShaderToy/ShaderToy.cpp @@ -60,8 +60,8 @@ void ShaderToy::onFrameRender(RenderContext* pRenderContext, const Fbo::SharedPt // iResolution float width = (float)pTargetFbo->getWidth(); float height = (float)pTargetFbo->getHeight(); - mpMainPass["ToyCB"]["iResolution"] = glm::vec2(width, height); - mpMainPass["ToyCB"]["iGlobalTime"] = (float)gpFramework->getGlobalClock().now(); + mpMainPass["ToyCB"]["iResolution"] = float2(width, height); + mpMainPass["ToyCB"]["iGlobalTime"] = (float)gpFramework->getGlobalClock().getTime(); // run final pass mpMainPass->execute(pRenderContext, pTargetFbo); diff --git a/Source/Tools/FalcorTest/Tests/Core/ParamBlockDefinition.slang b/Source/Tools/FalcorTest/Tests/Core/ParamBlockDefinition.slang index 2c9c26bbc..3c6c65f31 100644 --- a/Source/Tools/FalcorTest/Tests/Core/ParamBlockDefinition.slang +++ b/Source/Tools/FalcorTest/Tests/Core/ParamBlockDefinition.slang @@ -25,6 +25,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ +import Utils.Attributes; /** Parameter block for testing root descriptors. @@ -38,9 +39,9 @@ struct TestBlock RWBuffer bufB[3]; #if USE_UAV - RWByteAddressBuffer __root__testBuffer; // Buffer bound to root descriptor (UAV) + [root] RWByteAddressBuffer testBuffer; // Buffer bound to root descriptor (UAV) #else - ByteAddressBuffer __root__testBuffer; // Buffer bound to root descriptor (SRV) + [root] ByteAddressBuffer testBuffer; // Buffer bound to root descriptor (SRV) #endif Buffer bufC[4]; diff --git a/Source/Tools/FalcorTest/Tests/Core/RootBufferParamBlockTests.cpp b/Source/Tools/FalcorTest/Tests/Core/RootBufferParamBlockTests.cpp index 8c2ffcc21..300a2af5b 100644 --- a/Source/Tools/FalcorTest/Tests/Core/RootBufferParamBlockTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Core/RootBufferParamBlockTests.cpp @@ -36,8 +36,8 @@ namespace Falcor const std::string kTestProgram = "Tests/Core/RootBufferParamBlockTests.cs.slang"; const uint32_t kNumElems = 256; - const std::string kRootBufferName = "__root__testBuffer"; - const std::string kGlobalRootBufferName = "__root__globalTestBuffer"; + const std::string kRootBufferName = "testBuffer"; + const std::string kGlobalRootBufferName = "globalTestBuffer"; std::mt19937 rng; auto dist = std::uniform_int_distribution(0, 100); diff --git a/Source/Tools/FalcorTest/Tests/Core/RootBufferParamBlockTests.cs.slang b/Source/Tools/FalcorTest/Tests/Core/RootBufferParamBlockTests.cs.slang index 96eee6a75..151ec6814 100644 --- a/Source/Tools/FalcorTest/Tests/Core/RootBufferParamBlockTests.cs.slang +++ b/Source/Tools/FalcorTest/Tests/Core/RootBufferParamBlockTests.cs.slang @@ -25,6 +25,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ +import Utils.Attributes; import ParamBlockDefinition; // Global scope root and non-root resources @@ -32,9 +33,9 @@ RWStructuredBuffer result; Buffer globalBufA; #if USE_UAV -RWByteAddressBuffer __root__globalTestBuffer; // Buffer bound to root descriptor (UAV) +[root] RWByteAddressBuffer globalTestBuffer; // Buffer bound to root descriptor (UAV) #else -ByteAddressBuffer __root__globalTestBuffer; // Buffer bound to root descriptor (SRV) +[root] ByteAddressBuffer globalTestBuffer; // Buffer bound to root descriptor (SRV) #endif // Parameter block containing both root and non-root resources @@ -58,11 +59,11 @@ void main(uint3 threadId : SV_DispatchThreadID) r += gParamBlock.bufC[1][i] * 7; r += gParamBlock.bufC[2][i] * 8; r += gParamBlock.bufC[3][i] * 9; - r += gParamBlock.__root__testBuffer.Load(i * 4) * 10; + r += gParamBlock.testBuffer.Load(i * 4) * 10; // Add data read from buffers bound at the global scope. r += globalBufA[i] * 11; - r += __root__globalTestBuffer.Load(i * 4) * 12; + r += globalTestBuffer.Load(i * 4) * 12; result[i] = r; } diff --git a/Source/Tools/FalcorTest/Tests/Core/RootBufferStructTests.cpp b/Source/Tools/FalcorTest/Tests/Core/RootBufferStructTests.cpp index 783ec879b..e34aa2eb4 100644 --- a/Source/Tools/FalcorTest/Tests/Core/RootBufferStructTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Core/RootBufferStructTests.cpp @@ -33,7 +33,7 @@ namespace Falcor namespace { const uint32_t kNumElems = 256; - const std::string kRootBufferName = "__root__buf"; + const std::string kRootBufferName = "rootBuf"; std::mt19937 rng; auto dist = std::uniform_int_distribution(0, 100); diff --git a/Source/Tools/FalcorTest/Tests/Core/RootBufferStructTests.cs.slang b/Source/Tools/FalcorTest/Tests/Core/RootBufferStructTests.cs.slang index 8d63f19dc..96fe4beba 100644 --- a/Source/Tools/FalcorTest/Tests/Core/RootBufferStructTests.cs.slang +++ b/Source/Tools/FalcorTest/Tests/Core/RootBufferStructTests.cs.slang @@ -25,6 +25,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ +import Utils.Attributes; /** Unit tests for testing a buffer bound as root descriptor inside a struct, where the struct is placed in a constant buffer. @@ -42,9 +43,9 @@ struct S Buffer buf; RWBuffer rwBuf; #if USE_UAV - RWStructuredBuffer __root__buf; // Buffer bound to root descriptor (UAV) + [root] RWStructuredBuffer rootBuf; // Buffer bound to root descriptor (UAV) #else - StructuredBuffer __root__buf; // Buffer bound to root descriptor (SRV) + [root] StructuredBuffer rootBuf; // Buffer bound to root descriptor (SRV) #endif }; @@ -63,7 +64,7 @@ void main(uint3 threadId : SV_DispatchThreadID) uint r = 0; r += data.buf[i]; r += data.rwBuf[i] * 2; - r += data.__root__buf[i].value * 3; + r += data.rootBuf[i].value * 3; result[i] = r; } diff --git a/Source/Tools/FalcorTest/Tests/Core/RootBufferTests.cpp b/Source/Tools/FalcorTest/Tests/Core/RootBufferTests.cpp index c4714fa90..ce5d267dd 100644 --- a/Source/Tools/FalcorTest/Tests/Core/RootBufferTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Core/RootBufferTests.cpp @@ -33,7 +33,7 @@ namespace Falcor namespace { const uint32_t kNumElems = 256; - const std::string kRootBufferName = "__root__testBuffer"; + const std::string kRootBufferName = "testBuffer"; std::mt19937 rng; auto dist = std::uniform_int_distribution(0, 100); @@ -79,10 +79,10 @@ namespace Falcor var["typedBufferUint"] = Buffer::createTyped(kNumElems, ResourceBindFlags::UnorderedAccess, Buffer::CpuAccess::None, typedBufferUint.data()); } - std::vector typedBufferFloat4(kNumElems); + std::vector typedBufferFloat4(kNumElems); { for (uint32_t i = 0; i < kNumElems; i++) typedBufferFloat4[i] = { r() * 0.25f, r() * 0.5f, r() * 0.75f, r() }; - var["typedBufferFloat4"] = Buffer::createTyped(kNumElems, ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, typedBufferFloat4.data()); + var["typedBufferFloat4"] = Buffer::createTyped(kNumElems, ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, typedBufferFloat4.data()); } // Test binding buffer to root descriptor. @@ -122,7 +122,7 @@ namespace Falcor for (uint32_t i = 0; i < kNumElems; i++) rawBuffer[i] = r(); var["rawBuffer"] = Buffer::create(kNumElems * sizeof(uint32_t), ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, rawBuffer.data()); for (uint32_t i = 0; i < kNumElems; i++) typedBufferFloat4[i] = { r() * 0.25f, r() * 0.5f, r() * 0.75f, r() }; - var["typedBufferFloat4"] = Buffer::createTyped(kNumElems, ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, typedBufferFloat4.data()); + var["typedBufferFloat4"] = Buffer::createTyped(kNumElems, ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, typedBufferFloat4.data()); var["CB"]["c0"] = ++c0; ctx.runProgram(kNumElems, 1, 1); diff --git a/Source/Tools/FalcorTest/Tests/Core/RootBufferTests.cs.slang b/Source/Tools/FalcorTest/Tests/Core/RootBufferTests.cs.slang index ac37d5daa..81a43c9f3 100644 --- a/Source/Tools/FalcorTest/Tests/Core/RootBufferTests.cs.slang +++ b/Source/Tools/FalcorTest/Tests/Core/RootBufferTests.cs.slang @@ -25,6 +25,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **************************************************************************/ +import Utils.Attributes; /** Unit tests for binding buffers using root descriptors. */ @@ -48,9 +49,9 @@ ByteAddressBuffer rawBuffer; StructuredBuffer structBuffer; #if USE_UAV -RWByteAddressBuffer __root__testBuffer; // Buffer bound to root descriptor (UAV) +[root] RWByteAddressBuffer testBuffer; // Buffer bound to root descriptor (UAV) #else -ByteAddressBuffer __root__testBuffer; // Buffer bound to root descriptor (SRV) +[root] ByteAddressBuffer testBuffer; // Buffer bound to root descriptor (SRV) #endif RWBuffer typedBufferUint; @@ -71,7 +72,7 @@ void main(uint3 threadId : SV_DispatchThreadID) r += typedBufferFloat4[i].z * 3; r += structBuffer[i].a * 4; r += structBuffer[i].b * 5; - r += __root__testBuffer.Load(i * 4) * 6; + r += testBuffer.Load(i * 4) * 6; result[i] = r; } diff --git a/Source/Tools/FalcorTest/Tests/DebugPasses/InvalidPixelDetectionTests.cpp b/Source/Tools/FalcorTest/Tests/DebugPasses/InvalidPixelDetectionTests.cpp index eda3c99d2..2db0c8c38 100644 --- a/Source/Tools/FalcorTest/Tests/DebugPasses/InvalidPixelDetectionTests.cpp +++ b/Source/Tools/FalcorTest/Tests/DebugPasses/InvalidPixelDetectionTests.cpp @@ -45,7 +45,7 @@ namespace Falcor pGraph->execute(pRenderContext); Resource::SharedPtr pOutput = pGraph->getOutput("InvalidPixelDetectionPass.dst"); std::vector color = pRenderContext->readTextureSubresource(pOutput->asTexture().get(), 0); - uint32* output = (uint32_t*)color.data(); + uint32_t* output = (uint32_t*)color.data(); for (uint32_t i = 0; i < 8; ++i) { diff --git a/Source/Tools/FalcorTest/Tests/Sampling/SampleGeneratorTests.cpp b/Source/Tools/FalcorTest/Tests/Sampling/SampleGeneratorTests.cpp index fdabb052d..648a5320c 100644 --- a/Source/Tools/FalcorTest/Tests/Sampling/SampleGeneratorTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Sampling/SampleGeneratorTests.cpp @@ -39,7 +39,7 @@ namespace Falcor // The shader uses the first two dispatch dimensions as spatial seed and the last as instance index. // For each sample generator instance, it generates kDimensions samples. - const glm::uvec3 kDispatchDim = { 64, 64, 16 }; + const uint3 kDispatchDim = { 64, 64, 16 }; const uint32_t kDimensions = 32; /** Estimates the population Pearson correlation between pairs of diff --git a/Source/Tools/FalcorTest/Tests/ShadingUtils/RaytracingTests.cpp b/Source/Tools/FalcorTest/Tests/ShadingUtils/RaytracingTests.cpp index e9e01e453..0143a478d 100644 --- a/Source/Tools/FalcorTest/Tests/ShadingUtils/RaytracingTests.cpp +++ b/Source/Tools/FalcorTest/Tests/ShadingUtils/RaytracingTests.cpp @@ -35,8 +35,6 @@ namespace Falcor { int float_as_int(float f) { return *reinterpret_cast(&f); } float int_as_float(int i) { return *reinterpret_cast(&i); } - using float3 = glm::vec3; - using int3 = glm::int3; /** Unmodified reference code from Ray Tracing Gems, Chapter 6. */ @@ -69,36 +67,36 @@ namespace Falcor auto r = [&]() -> float { return dist(rng); }; // Create random test data. - std::vector testPositions(n); - std::vector testNormals(n); + std::vector testPositions(n); + std::vector testNormals(n); for (uint32_t i = 0; i < n; i++) { float scale = std::pow(10.f, (float)i / n * 60.f - 30.f); // 1e-30..1e30 - testPositions[i] = glm::vec3(r(), r(), r()) * scale; - testNormals[i] = glm::normalize(glm::vec3(r(), r(), r())); + testPositions[i] = float3(r(), r(), r()) * scale; + testNormals[i] = glm::normalize(float3(r(), r(), r())); } // Setup and run GPU test. ctx.createProgram("Tests/ShadingUtils/RaytracingTests.cs.slang", "testComputeRayOrigin", {{"MATERIAL_COUNT", "1"}}); ctx.allocateStructuredBuffer("result", n); // TODO: Cleanup when !122 is merged - //ctx.allocateStructuredBuffer("pos", n, testPositions, testPositions.size() * sizeof(glm::vec3)); - //ctx.allocateStructuredBuffer("normal", n, testNormals.size() * sizeof(glm::vec3)); + //ctx.allocateStructuredBuffer("pos", n, testPositions, testPositions.size() * sizeof(float3)); + //ctx.allocateStructuredBuffer("normal", n, testNormals.size() * sizeof(float3)); auto pPos = Buffer::createStructured(ctx.getProgram(), "pos", n); - pPos->setBlob(testPositions.data(), 0, testPositions.size() * sizeof(glm::vec3)); + pPos->setBlob(testPositions.data(), 0, testPositions.size() * sizeof(float3)); ctx["pos"] = pPos; auto pNormal = Buffer::createStructured(ctx.getProgram(), "normal", n); - pNormal->setBlob(testNormals.data(), 0, testNormals.size() * sizeof(glm::vec3)); + pNormal->setBlob(testNormals.data(), 0, testNormals.size() * sizeof(float3)); ctx["normal"] = pNormal; ctx["CB"]["n"] = n; ctx.runProgram(n); // Verify results. - const glm::vec3* result = ctx.mapBuffer("result"); + const float3* result = ctx.mapBuffer("result"); for (uint32_t i = 0; i < n; i++) { - glm::vec3 ref = offset_ray(testPositions[i], testNormals[i]); + float3 ref = offset_ray(testPositions[i], testNormals[i]); EXPECT_EQ(result[i], ref) << "i = " << i; } ctx.unmapBuffer("result"); diff --git a/Source/Tools/FalcorTest/Tests/ShadingUtils/ShadingUtilsTests.cpp b/Source/Tools/FalcorTest/Tests/ShadingUtils/ShadingUtilsTests.cpp index a86a1029b..033cff97a 100644 --- a/Source/Tools/FalcorTest/Tests/ShadingUtils/ShadingUtilsTests.cpp +++ b/Source/Tools/FalcorTest/Tests/ShadingUtils/ShadingUtilsTests.cpp @@ -32,7 +32,7 @@ namespace Falcor { namespace { - using float3 = glm::vec3; + using float3 = float3; enum class RayOriginLocation { @@ -48,7 +48,7 @@ namespace Falcor auto r = [&]() -> float { return dist(rng); }; float x1, x2; - do + do { x1 = r(); x2 = r(); @@ -203,15 +203,15 @@ namespace Falcor auto dist = std::uniform_real_distribution(-10.f, 10.f); auto r = [&]() -> float { return dist(rng); }; - std::vector testSphereCenters(12); + std::vector testSphereCenters(12); std::vector testSphereRadii(12); - std::vector refIsects(12); - std::vector testRayOrigins(12); - std::vector testRayDirs(12); + std::vector refIsects(12); + std::vector testRayOrigins(12); + std::vector testRayDirs(12); for (int32_t i = 0; i < 12; i++) { - testSphereCenters[i] = glm::vec3(r(), r(), r()); + testSphereCenters[i] = float3(r(), r(), r()); testSphereRadii[i] = abs(r()); refIsects[i] = getHitPoint(testSphereRadii[i], testSphereCenters[i]); switch (i) @@ -250,18 +250,18 @@ namespace Falcor } ctx.createProgram("Tests/ShadingUtils/ShadingUtilsTests.cs.slang", "testRaySphereIntersection"); - ctx.allocateStructuredBuffer("sphereCenter", 12, testSphereCenters.data(), testSphereCenters.size() * sizeof(glm::vec3)); + ctx.allocateStructuredBuffer("sphereCenter", 12, testSphereCenters.data(), testSphereCenters.size() * sizeof(float3)); ctx.allocateStructuredBuffer("sphereRadius", 12, testSphereRadii.data()); - ctx.allocateStructuredBuffer("rayOrigin", 12, testRayOrigins.data(), testRayOrigins.size() * sizeof(glm::vec3)); - ctx.allocateStructuredBuffer("rayDir", 12, testRayDirs.data(), testRayDirs.size() * sizeof(glm::vec3)); + ctx.allocateStructuredBuffer("rayOrigin", 12, testRayOrigins.data(), testRayOrigins.size() * sizeof(float3)); + ctx.allocateStructuredBuffer("rayDir", 12, testRayDirs.data(), testRayDirs.size() * sizeof(float3)); ctx.allocateStructuredBuffer("isectResult", 12); ctx.allocateStructuredBuffer("isectLoc", 12); ctx["TestCB"]["resultSize"] = 12; - + ctx.runProgram(); const uint32_t* result = ctx.mapBuffer("isectResult"); - const glm::vec3* isectLoc = ctx.mapBuffer("isectLoc"); + const float3* isectLoc = ctx.mapBuffer("isectLoc"); for (int32_t i = 0; i < 12; i++) { switch (i) diff --git a/Source/Tools/FalcorTest/Tests/Slang/SlangMutatingTests.cpp b/Source/Tools/FalcorTest/Tests/Slang/SlangMutatingTests.cpp index 8736f68ad..f279ea926 100644 --- a/Source/Tools/FalcorTest/Tests/Slang/SlangMutatingTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Slang/SlangMutatingTests.cpp @@ -35,8 +35,8 @@ namespace Falcor ctx.allocateStructuredBuffer("result", 1); ShaderVar var = ctx.vars().getRootVar(); - glm::uvec4 v = { 11, 22, 33, 44 }; - var["buffer"] = Buffer::createTyped(1, ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, &v); + uint4 v = { 11, 22, 33, 44 }; + var["buffer"] = Buffer::createTyped(1, ResourceBindFlags::ShaderResource, Buffer::CpuAccess::None, &v); ctx.runProgram(); diff --git a/Source/Tools/FalcorTest/Tests/Slang/SlangTests.cpp b/Source/Tools/FalcorTest/Tests/Slang/SlangTests.cpp index f85e9c8fe..c414c70fc 100644 --- a/Source/Tools/FalcorTest/Tests/Slang/SlangTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Slang/SlangTests.cpp @@ -72,8 +72,8 @@ namespace Falcor half f32tof16(float fval) { return DirectX::PackedVector::XMConvertFloatToHalf(fval); } float f16tof32(half hval) { return DirectX::PackedVector::XMConvertHalfToFloat(hval); } - uint32_t asuint(float32_t a) { return *reinterpret_cast(&a); } - uint64_t asuint64(float64_t a) { return *reinterpret_cast(&a); } + uint32_t asuint(float a) { return *reinterpret_cast(&a); } + uint64_t asuint64(double a) { return *reinterpret_cast(&a); } } /** Test that compares the enums generated by enum declarations in C++ vs Slang. diff --git a/Source/Tools/FalcorTest/Tests/Slang/WaveOps.cpp b/Source/Tools/FalcorTest/Tests/Slang/WaveOps.cpp index debfbd5be..55af808ef 100644 --- a/Source/Tools/FalcorTest/Tests/Slang/WaveOps.cpp +++ b/Source/Tools/FalcorTest/Tests/Slang/WaveOps.cpp @@ -46,16 +46,16 @@ namespace Falcor return data; } - std::vector computeMatchResult(const std::vector& data, uint32_t laneCount) + std::vector computeMatchResult(const std::vector& data, uint32_t laneCount) { assert(laneCount >= 4 && laneCount <= 128); - std::vector masks(data.size(), glm::uvec4(0)); + std::vector masks(data.size(), uint4(0)); for (size_t i = 0; i < data.size(); i++) { size_t firstLane = (i / laneCount) * laneCount; uint32_t currentLaneValue = data[i]; - glm::uvec4& mask = masks[i]; + uint4& mask = masks[i]; for (uint32_t j = 0; j < laneCount; j++) { @@ -109,10 +109,10 @@ namespace Falcor if (laneCount < 4 || laneCount > 128) throw std::exception("Unsupported wave lane count"); // Verify results of wave match. - std::vector expectedResult = computeMatchResult(matchData, laneCount); + std::vector expectedResult = computeMatchResult(matchData, laneCount); assert(expectedResult.size() == matchData.size()); - const glm::uvec4* result = ctx.mapBuffer("result"); + const uint4* result = ctx.mapBuffer("result"); for (size_t i = 0; i < matchData.size(); i++) { EXPECT_EQ(result[i].x, expectedResult[i].x) << "i = " << i; diff --git a/Source/Tools/FalcorTest/Tests/Utils/AABBTests.cpp b/Source/Tools/FalcorTest/Tests/Utils/AABBTests.cpp index f24e228c7..b2771efa0 100644 --- a/Source/Tools/FalcorTest/Tests/Utils/AABBTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Utils/AABBTests.cpp @@ -33,7 +33,7 @@ namespace Falcor namespace { // Some test points. Use exactly representable fp32 values to not worry about numerical issues. - const glm::vec3 kTestData[] = + const float3 kTestData[] = { { 1.00f, 2.50f, -0.50f }, { -3.50f, -0.00f, -1.25f }, @@ -54,7 +54,7 @@ namespace Falcor ctx.runProgram(); // Verify results. - const glm::vec3* result = ctx.mapBuffer("result"); + const float3* result = ctx.mapBuffer("result"); size_t i = 0; // Test 0 @@ -64,52 +64,52 @@ namespace Falcor EXPECT_EQ(result[i], kTestData[2]) << "i = " << i++; // Test 1 - EXPECT_EQ(result[i], glm::vec3(1)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(1)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(0)) << "i = " << i++; + EXPECT_EQ(result[i], float3(1)) << "i = " << i++; + EXPECT_EQ(result[i], float3(1)) << "i = " << i++; + EXPECT_EQ(result[i], float3(0)) << "i = " << i++; EXPECT_EQ(result[i], kTestData[0]) << "i = " << i++; - EXPECT_EQ(result[i], kTestData[0] + glm::vec3(1.f, 1.f, -0.5f)) << "i = " << i++; + EXPECT_EQ(result[i], kTestData[0] + float3(1.f, 1.f, -0.5f)) << "i = " << i++; // Test 2 - EXPECT_EQ(result[i], glm::vec3(0)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(FLT_MAX)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(-FLT_MAX)) << "i = " << i++; + EXPECT_EQ(result[i], float3(0)) << "i = " << i++; + EXPECT_EQ(result[i], float3(FLT_MAX)) << "i = " << i++; + EXPECT_EQ(result[i], float3(-FLT_MAX)) << "i = " << i++; // Test 3 - EXPECT_EQ(result[i], glm::vec3(-3.50f, 0.00f, -1.25f)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3( 1.00f, 2.50f, -0.50f)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3( 0.50f, 1.25f, -2.50f)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3( 4.00f, 2.75f, 4.50f)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(-3.50f, 0.00f, -2.50f)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3( 4.00f, 2.75f, 4.50f)) << "i = " << i++; + EXPECT_EQ(result[i], float3(-3.50f, 0.00f, -1.25f)) << "i = " << i++; + EXPECT_EQ(result[i], float3( 1.00f, 2.50f, -0.50f)) << "i = " << i++; + EXPECT_EQ(result[i], float3( 0.50f, 1.25f, -2.50f)) << "i = " << i++; + EXPECT_EQ(result[i], float3( 4.00f, 2.75f, 4.50f)) << "i = " << i++; + EXPECT_EQ(result[i], float3(-3.50f, 0.00f, -2.50f)) << "i = " << i++; + EXPECT_EQ(result[i], float3( 4.00f, 2.75f, 4.50f)) << "i = " << i++; // Test 4 - EXPECT_EQ(result[i], glm::vec3(0)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(0)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(1)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(0)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(1)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(1)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(1)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(0)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(0)) << "i = " << i++; + EXPECT_EQ(result[i], float3(0)) << "i = " << i++; + EXPECT_EQ(result[i], float3(0)) << "i = " << i++; + EXPECT_EQ(result[i], float3(1)) << "i = " << i++; + EXPECT_EQ(result[i], float3(0)) << "i = " << i++; + EXPECT_EQ(result[i], float3(1)) << "i = " << i++; + EXPECT_EQ(result[i], float3(1)) << "i = " << i++; + EXPECT_EQ(result[i], float3(1)) << "i = " << i++; + EXPECT_EQ(result[i], float3(0)) << "i = " << i++; + EXPECT_EQ(result[i], float3(0)) << "i = " << i++; // Test 5 EXPECT_EQ(result[i], kTestData[0]) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(0)) << "i = " << i++; + EXPECT_EQ(result[i], float3(0)) << "i = " << i++; EXPECT_EQ(result[i].x, 0.f) << "i = " << i++; EXPECT_EQ(result[i].x, 0.f) << "i = " << i++; EXPECT_EQ(result[i].x, 0.f) << "i = " << i++; - EXPECT_EQ(result[i], kTestData[0] - glm::vec3(0.f, 0.5f, 0.f)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(0.f, 1.f, 0.f)) << "i = " << i++; + EXPECT_EQ(result[i], kTestData[0] - float3(0.f, 0.5f, 0.f)) << "i = " << i++; + EXPECT_EQ(result[i], float3(0.f, 1.f, 0.f)) << "i = " << i++; EXPECT_EQ(result[i].x, 0.f) << "i = " << i++; EXPECT_EQ(result[i].x, 0.f) << "i = " << i++; EXPECT_EQ(result[i].x, 0.5f) << "i = " << i++; - - EXPECT_EQ(result[i], glm::vec3(0.25f, 1.375f, 1.00f)) << "i = " << i++; - EXPECT_EQ(result[i], glm::vec3(7.50f, 2.75f, 7.00f)) << "i = " << i++; + + EXPECT_EQ(result[i], float3(0.25f, 1.375f, 1.00f)) << "i = " << i++; + EXPECT_EQ(result[i], float3(7.50f, 2.75f, 7.00f)) << "i = " << i++; EXPECT_EQ(result[i].x, 184.75f) << "i = " << i++; EXPECT_EQ(result[i].x, 144.375f) << "i = " << i++; EXPECT_EQ(result[i].x, 0.5f*std::sqrt(7.50f*7.50f + 2.75f*2.75f + 7.00f*7.00f)) << "i = " << i++; diff --git a/Source/Tools/FalcorTest/Tests/Utils/ColorUtilsTests.cpp b/Source/Tools/FalcorTest/Tests/Utils/ColorUtilsTests.cpp index 8d48ec852..3ebdb66db 100644 --- a/Source/Tools/FalcorTest/Tests/Utils/ColorUtilsTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Utils/ColorUtilsTests.cpp @@ -36,9 +36,9 @@ namespace Falcor { const float kMaxError = 1e-5f; - auto maxAbsDiff = [](glm::vec3 a, glm::vec3 b) -> float + auto maxAbsDiff = [](float3 a, float3 b) -> float { - glm::vec3 d = abs(a - b); + float3 d = abs(a - b); return std::max(std::max(d.x, d.y), d.z); }; } @@ -58,28 +58,28 @@ namespace Falcor // Run test code that transforms random colors between different spaces. for (uint32_t i = 0; i < n; i++) { - const glm::vec3 c = { u(), u(), u() }; + const float3 c = { u(), u(), u() }; // Test RGB<->XYZ by transforming random colors back and forth. - glm::vec3 res1 = XYZtoRGB_Rec709(RGBtoXYZ_Rec709(c)); + float3 res1 = XYZtoRGB_Rec709(RGBtoXYZ_Rec709(c)); EXPECT_LE(maxAbsDiff(res1, c), kMaxError); // Test XYZ<->LMS using the CAT02 transform. - glm::vec3 res2 = LMS_CAT02 * c; + float3 res2 = LMS_CAT02 * c; EXPECT_LE(maxAbsDiff(res2, c), kMaxError); - // Test XYZ<->LMS using the Bradford transform - glm::vec3 res3 = LMS_Bradford * c; + // Test XYZ<->LMS using the Bradford transform + float3 res3 = LMS_Bradford * c; EXPECT_LE(maxAbsDiff(res3, c), kMaxError); } } CPU_TEST(WhiteBalance) { - const glm::vec3 white = { 1, 1, 1 }; + const float3 white = { 1, 1, 1 }; // The white point should be 6500K. Verify that we get pure white back. - glm::vec3 wbWhite = calculateWhiteBalanceTransformRGB_Rec709(6500.f) * white; + float3 wbWhite = calculateWhiteBalanceTransformRGB_Rec709(6500.f) * white; EXPECT_LE(maxAbsDiff(wbWhite, white), kMaxError); // Test white balance transform at a few different color temperatures. @@ -89,9 +89,9 @@ namespace Falcor // - Cloudy (7000K) => yellowish tint (r > g > b) // - Sunny (5500K) => blueish tint (r < g < b) // - Indoor (3000K) => stronger bluish tint (r < g < b) - glm::vec3 wbCloudy = calculateWhiteBalanceTransformRGB_Rec709(7000.f) * white; - glm::vec3 wbSunny = calculateWhiteBalanceTransformRGB_Rec709(5500.f) * white; - glm::vec3 wbIndoor = calculateWhiteBalanceTransformRGB_Rec709(3000.f) * white; + float3 wbCloudy = calculateWhiteBalanceTransformRGB_Rec709(7000.f) * white; + float3 wbSunny = calculateWhiteBalanceTransformRGB_Rec709(5500.f) * white; + float3 wbIndoor = calculateWhiteBalanceTransformRGB_Rec709(3000.f) * white; EXPECT_GE(wbCloudy.r, wbCloudy.g); EXPECT_GE(wbCloudy.g, wbCloudy.b); diff --git a/Source/Tools/FalcorTest/Tests/Utils/HashUtilsTests.cpp b/Source/Tools/FalcorTest/Tests/Utils/HashUtilsTests.cpp index c31e8b858..756b6159d 100644 --- a/Source/Tools/FalcorTest/Tests/Utils/HashUtilsTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Utils/HashUtilsTests.cpp @@ -55,7 +55,7 @@ namespace Falcor { // Allocate results buffer (64k dwords). Buffer::SharedPtr pResultBuffer = Buffer::createTyped(1 << 16, ResourceBindFlags::UnorderedAccess); - ctx.getRenderContext()->clearUAV(pResultBuffer->getUAV().get(), glm::uvec4(0)); + ctx.getRenderContext()->clearUAV(pResultBuffer->getUAV().get(), uint4(0)); // Setup and run GPU test. ctx.createProgram("Tests/Utils/HashUtilsTests.cs.slang", "testJenkinsHash"); @@ -98,7 +98,7 @@ namespace Falcor { // Allocate results buffer (2^27 dwords). Buffer::SharedPtr pResultBuffer = Buffer::createTyped(1 << 27, ResourceBindFlags::UnorderedAccess); - ctx.getRenderContext()->clearUAV(pResultBuffer->getUAV().get(), glm::uvec4(0)); + ctx.getRenderContext()->clearUAV(pResultBuffer->getUAV().get(), uint4(0)); // Setup and run GPU test. ctx.createProgram("Tests/Utils/HashUtilsTests.cs.slang", "testJenkinsHash_PerfectHash"); diff --git a/Source/Tools/FalcorTest/Tests/Utils/ParallelReductionTests.cpp b/Source/Tools/FalcorTest/Tests/Utils/ParallelReductionTests.cpp index 97a5743e2..83a4a7447 100644 --- a/Source/Tools/FalcorTest/Tests/Utils/ParallelReductionTests.cpp +++ b/Source/Tools/FalcorTest/Tests/Utils/ParallelReductionTests.cpp @@ -35,7 +35,7 @@ namespace Falcor namespace { // Utility classes for compact data types on the GPU. - // TODO: Make types like these part of new math library. + // TODO: Make types like these part of new math library. // Unsigned normalized integer. template @@ -210,9 +210,9 @@ namespace Falcor void testReduction(GPUUnitTestContext& ctx, const ComputeParallelReduction::SharedPtr& pReduction, ResourceFormat format, uint32_t width, uint32_t height) { const FormatType type = getFormatType(format); - if (type == FormatType::Uint) testReduction(ctx, pReduction, format, width, height); - else if (type == FormatType::Sint) testReduction(ctx, pReduction, format, width, height); - else testReduction(ctx, pReduction, format, width, height); + if (type == FormatType::Uint) testReduction(ctx, pReduction, format, width, height); + else if (type == FormatType::Sint) testReduction(ctx, pReduction, format, width, height); + else testReduction(ctx, pReduction, format, width, height); } } diff --git a/Source/Tools/ImageCompare/args.h b/Source/Tools/ImageCompare/args.h index e93ee6bcc..f784538ab 100644 --- a/Source/Tools/ImageCompare/args.h +++ b/Source/Tools/ImageCompare/args.h @@ -1,30 +1,28 @@ -/*************************************************************************** - # Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. - # - # Redistribution and use in source and binary forms, with or without - # modification, are permitted provided that the following conditions - # are met: - # * Redistributions of source code must retain the above copyright - # notice, this list of conditions and the following disclaimer. - # * Redistributions in binary form must reproduce the above copyright - # notice, this list of conditions and the following disclaimer in the - # documentation and/or other materials provided with the distribution. - # * Neither the name of NVIDIA CORPORATION nor the names of its - # contributors may be used to endorse or promote products derived - # from this software without specific prior written permission. - # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **************************************************************************/ +/* A simple header-only C++ argument parser library. + * + * https://github.com/Taywee/args + * + * Copyright (c) 2016-2019 Taylor C. Richberger and Pavel + * Belikov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ /** \file args.hxx * \brief this single-header lets you use all of the args functionality diff --git a/Source/Tools/RenderGraphEditor/RenderGraphEditor.cpp b/Source/Tools/RenderGraphEditor/RenderGraphEditor.cpp index 867143134..204f722c6 100644 --- a/Source/Tools/RenderGraphEditor/RenderGraphEditor.cpp +++ b/Source/Tools/RenderGraphEditor/RenderGraphEditor.cpp @@ -511,7 +511,7 @@ void RenderGraphEditor::createNewGraph(const std::string& renderGraphName) void RenderGraphEditor::onFrameRender(RenderContext* pRenderContext, const Fbo::SharedPtr& pTargetFbo) { - const glm::vec4 clearColor(0.25, 0.25, 0.25 , 1); + const float4 clearColor(0.25, 0.25, 0.25 , 1); pRenderContext->clearFbo(pTargetFbo.get(), clearColor, 1.0f, 0, FboAttachmentType::All); mRenderGraphUIs[mCurrentGraphIndex].updateGraph(pRenderContext); } diff --git a/Source/Tools/RenderGraphEditor/RenderGraphEditor.h b/Source/Tools/RenderGraphEditor/RenderGraphEditor.h index c0957a917..c5aca5239 100644 --- a/Source/Tools/RenderGraphEditor/RenderGraphEditor.h +++ b/Source/Tools/RenderGraphEditor/RenderGraphEditor.h @@ -54,7 +54,7 @@ class RenderGraphEditor : public IRenderer std::vector mRenderGraphUIs; std::unordered_map mGraphNamesToIndex; size_t mCurrentGraphIndex; - glm::uvec2 mWindowSize; + uint2 mWindowSize; std::string mCurrentLog; std::string mNextGraphString; std::string mCurrentGraphOutput; diff --git a/Tests/image_tests/renderpasses/graphs/WhittedRayTracer.py b/Tests/image_tests/renderpasses/graphs/WhittedRayTracer.py new file mode 100644 index 000000000..476b55e27 --- /dev/null +++ b/Tests/image_tests/renderpasses/graphs/WhittedRayTracer.py @@ -0,0 +1,32 @@ +from falcor import * + +def render_graph_WhittedRayTracer(): + g = RenderGraph("DefaultRenderGraph") + loadRenderPassLibrary("GBuffer.dll") + loadRenderPassLibrary("WhittedRatTracer.dll") + loadRenderPassLibrary("ToneMapper.dll") + WhittedRayTracer = RenderPass("WhittedRayTracer", {'mUsingRasterizedGBuffer': True, 'mMaxBounces': 1, 'mComputeDirect': True, 'mUseAnalyticLights': 1, 'mUseEmissiveLights': 1, 'mUseEnvLight': 0, 'mUseEnvBackground': 1}) + g.addPass(WhittedRayTracer, "WhittedRayTracer") + GBufferRaster = RenderPass("GBufferRaster", {'samplePattern': SamplePattern.Center, 'sampleCount': 16, 'forceCullMode': False, 'cull': CullMode.CullBack, 'useBentShadingNormals': True, 'texLOD': LODMode.UseMip0}) + g.addPass(GBufferRaster, "GBufferRaster") + ToneMapper = RenderPass("ToneMapper", {'exposureCompensation': 0.0, 'autoExposure': True, 'exposureValue': 0.0, 'filmSpeed': 100.0, 'whiteBalance': False, 'whitePoint': 6500.0, 'operator': ToneMapOp.Aces, 'clamp': True, 'whiteMaxLuminance': 1.0, 'whiteScale': 11.199999809265137}) + g.addPass(ToneMapper, "ToneMapper") + g.addEdge("WhittedRayTracer.color", "ToneMapper.src") + g.addEdge("GBufferRaster.posW", "WhittedRayTracer.posW") + g.addEdge("GBufferRaster.normW", "WhittedRayTracer.normalW") + g.addEdge("GBufferRaster.bitangentW", "WhittedRayTracer.bitangentW") + g.addEdge("GBufferRaster.diffuseOpacity", "WhittedRayTracer.mtlDiffOpacity") + g.addEdge("GBufferRaster.specRough", "WhittedRayTracer.mtlSpecRough") + g.addEdge("GBufferRaster.matlExtra", "WhittedRayTracer.mtlParams") + g.addEdge("GBufferRaster.emissive", "WhittedRayTracer.mtlEmissive") + g.addEdge("GBufferRaster.faceNormalW", "WhittedRayTracer.faceNormalW") + g.addEdge("GBufferRaster.surfSpreadAngle", "WhittedRayTracer.surfSpreadAngle") + g.addEdge("GBufferRaster.rayDifferentialX", "WhittedRayTracer.rayDifferentialX") + g.addEdge("GBufferRaster.rayDifferentialY", "WhittedRayTracer.rayDifferentialY") + g.addEdge("GBufferRaster.rayDifferentialZ", "WhittedRayTracer.rayDifferentialZ") + g.markOutput("ToneMapper.dst") + return g + +WhittedRayTracer = render_graph_WhittedRayTracer() +try: m.addGraph(WhittedRayTracer) +except NameError: None diff --git a/Tests/image_tests/renderpasses/helpers.py b/Tests/image_tests/renderpasses/helpers.py index dd3734aa3..9c839135e 100644 --- a/Tests/image_tests/renderpasses/helpers.py +++ b/Tests/image_tests/renderpasses/helpers.py @@ -5,14 +5,14 @@ def render_frames(ctx, name, frames=[1], framerate=60, resolution=[1280,720]): m, t, fc, renderFrame = itemgetter('m', 't', 'fc', 'renderFrame')(ctx) m.resizeSwapChain(*resolution) - m.ui(False) - t.framerate(framerate) - t.now(0) + m.ui = False + t.framerate = framerate + t.time = 0 t.pause() - fc.baseFilename(name) + fc.baseFilename = name current_frame = 0 for frame in frames: - t.frame(frame) + t.frame = frame while current_frame < frame: renderFrame() current_frame += 1 diff --git a/Tests/image_tests/renderpasses/test_CSM.py b/Tests/image_tests/renderpasses/test_CSM.py index 4fe4c4739..36d62f32b 100644 --- a/Tests/image_tests/renderpasses/test_CSM.py +++ b/Tests/image_tests/renderpasses/test_CSM.py @@ -1,4 +1,7 @@ -# SKIPPED Skipped due to random generation of NaNs. +IMAGE_TEST = { + 'skipped': 'Skipped due to random generation of NaNs.' +} + from helpers import render_frames from graphs.CSM import CSM as g from falcor import * diff --git a/Tests/image_tests/renderpasses/test_TextureLOD.py b/Tests/image_tests/renderpasses/test_TextureLOD.py new file mode 100644 index 000000000..f479c5cb9 --- /dev/null +++ b/Tests/image_tests/renderpasses/test_TextureLOD.py @@ -0,0 +1,17 @@ +# use the WhittedRayTracer pass to test various texture LOD modes +from helpers import render_frames +from graphs.WhittedRayTracer import WhittedRayTracer as g +from falcor import * + +m.addGraph(g) +m.loadScene('Arcade/Arcade.fscene') +ctx = locals() + +# default +render_frames(ctx, 'default') + +# texture LOD mode +for mode in [TextureLODMode.Mip0, TextureLODMode.RayCones, TextureLODMode.RayDiffsIsotropic, TextureLODMode.RayDiffsAnisotropic]: + g.updatePass('WhittedRayTracer', {'mTexLODMode': mode, 'mUsingRasterizedGBuffer': True, 'mMaxBounces': 1}) + render_frames(ctx, 'mode.' + str(mode)) +exit() diff --git a/Tests/testing/run_image_tests.py b/Tests/testing/run_image_tests.py index 19f0e4d0c..03847f783 100644 --- a/Tests/testing/run_image_tests.py +++ b/Tests/testing/run_image_tests.py @@ -20,16 +20,36 @@ from core.termcolor import colored -def has_skip_message(script_file): +def read_header(script_file): ''' - Check if script file has a skip message. + Check if script has a IMAGE_TEST dictionary defined at the top and return it's content. ''' with open(script_file) as f: - line = f.readline() - match = re.match(r'^#\s+SKIPPED\s+(.*)$', line) - if match: - return True, match.group(1) - return False, '' + script = f.read() + # Find IMAGE_TEST={} at the top of the script + m = re.match(r'IMAGE_TEST\s*=\s*({.*})', script, re.DOTALL) + if m: + header = None + # Match curly braces + depth = 0 + for i, c in enumerate(m.group(1)): + if c == '{': + depth += 1 + if c == '}': + depth -= 1 + if depth == 0: + header = m.group(1)[0:i+1] + break + if depth != 0: + raise Exception(f'Failed to parse script header in {script_file} (curly braces do not match)') + # Evaluate dictionary + if header: + try: + return eval(header) + except Exception as e: + raise Exception(f'Failed to parse script header in {script_file} ({e})') + + return {} class Test: ''' @@ -62,8 +82,19 @@ def __init__(self, script_file, root_dir): # Test name derived from test directory. self.name = str(self.test_dir.as_posix()) - # Check if script is skipped. - self.skipped, self.skip_message = has_skip_message(script_file) + # Read script header. + try: + self.header = read_header(script_file) + except Exception as e: + print(e) + sys.exit(1) + + # Get skipped tests. + self.skip_message = self.header.get('skipped', None) + self.skipped = self.skip_message != None + + # Get tolerance. + self.tolerance = self.header.get('tolerance', config.TOLERANCE) def __repr__(self): return f'Test(name={self.name},script_file={self.script_file})' @@ -103,7 +134,7 @@ def generate_images(self, output_dir, mogwai_exe): # Write helper script to run test. generate_file = output_dir / 'generate.py' with open(generate_file, 'w') as f: - f.write(f'fc.outputDir(r"{output_dir}")\n') + f.write(f'fc.outputDir = r"{output_dir}"\n') f.write(f'm.script(r"{relative_to_cwd(self.script_file)}")\n') # Run Mogwai to generate images. @@ -181,8 +212,7 @@ def compare_images(self, ref_dir, result_dir, image_compare_exe): ref_file = ref_dir / image result_file = result_dir / image error_file = result_dir / (str(image) + config.ERROR_IMAGE_SUFFIX) - tolerance = config.TOLERANCE - compare_success, compare_error = self.compare_image(ref_file, result_file, error_file, tolerance, image_compare_exe) + compare_success, compare_error = self.compare_image(ref_file, result_file, error_file, self.tolerance, image_compare_exe) if not compare_success: result = Test.Result.FAILED messages.append(f'Test image "{image}" failed with error {compare_error}.') @@ -191,7 +221,7 @@ def compare_images(self, ref_dir, result_dir, image_compare_exe): 'name': str(image), 'success': compare_success, 'error': compare_error, - 'tolerance': tolerance + 'tolerance': self.tolerance }) # Report missing result images for existing reference images.